Clover Coverage Report - Atlassian Core
Coverage timestamp: Sun Nov 30 2008 18:33:35 CST
254   867   106   7.47
122   607   0.42   17
34     3.12  
2    
 
 
  DateUtils       Line # 19 252 105 79.1% 0.7911548
  DateUtils.DateRange       Line # 50 2 1 0% 0.0
 
  (14)
 
1    /*
2    * Created by IntelliJ IDEA.
3    * User: Administrator
4    * Date: 5/03/2002
5    * Time: 14:31:36
6    * To change template for new class use
7    * Code Style | Class Templates options (Tools | IDE Options).
8    */
9    package com.atlassian.core.util;
10   
11    import com.opensymphony.util.TextUtils;
12    import org.apache.log4j.Category;
13   
14    import java.sql.Timestamp;
15    import java.text.DateFormat;
16    import java.text.SimpleDateFormat;
17    import java.util.*;
18   
 
19    public class DateUtils
20    {
21    private static Category log = Category.getInstance(DateUtils.class);
22   
23    /** Constants for time computation */
24    private static final int SECOND = 1;
25    private static final int MINUTE = 60 * SECOND;
26    private static final int HOUR = 60 * MINUTE;
27    private static final int DAY = 24 * HOUR;
28    private static final int WEEK = 7 * DAY;
29    private static final int MONTH = 31 * DAY;
30    private static final int YEAR = 365 * DAY;
31   
32    public static final long SECOND_MILLIS = 1000L * SECOND;
33    public static final long MINUTE_MILLIS = 1000L * MINUTE;
34    public static final long HOUR_MILLIS = 1000L * HOUR;
35    public static final long DAY_MILLIS = 1000L * DAY;
36    public static final long MONTH_MILLIS = 1000L * MONTH;
37    public static final long YEAR_MILLIS = 1000L * YEAR;
38   
39    /*
40    It's important these stay ordered from biggest to smallest.
41    Everything in this must be able to be zeroed without changing anything
42    that comes before it in the list. So don't add WEEK!
43    */
44    private static final int[] CALENDAR_PERIODS = { Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH,
45    Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND };
46   
47    // This is used by the Velocity templates as a bean
48    private final ResourceBundle resourceBundle;
49   
 
50    public static class DateRange
51    {
52    public final java.util.Date startDate;
53    public final java.util.Date endDate;
54   
 
55  0 toggle public DateRange(java.util.Date startDate, java.util.Date endDate)
56    {
57  0 this.startDate = startDate;
58  0 this.endDate = endDate;
59    }
60    }
61   
62   
 
63  0 toggle public DateUtils(ResourceBundle resourceBundle)
64    {
65  0 this.resourceBundle = resourceBundle;
66    }
67   
68    /** compares if these two timestamps are within 10 milliseconds of each other (precision error) */
 
69  4 toggle public static boolean equalTimestamps(Timestamp t1, Timestamp t2)
70    {
71  4 return (Math.abs(t1.getTime() - t2.getTime()) < 10L);
72    }
73   
74    /** Date Format to be used for internal logging operations */
75    public static final DateFormat ISO8601DateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
76   
 
77  0 toggle public String dateDifferenceBean(long dateA, long dateB, long resolution, ResourceBundle resourceBundle)
78    {
79  0 return dateDifference(dateA, dateB, resolution, resourceBundle);
80    }
81   
82    /**
83    * Resolution is the degree of difference.
84    * <p/>
85    * 0 = months
86    * 1 = days
87    * 2 = hours
88    * 3 = minutes
89    * 4 = seconds
90    */
 
91  14 toggle public static String dateDifference(long dateA, long dateB, long resolution, ResourceBundle resourceBundle)
92    {
93  14 long months, days, hours, minutes, seconds;
94  14 StringBuffer sb = new StringBuffer();
95  14 long difference = Math.abs(dateB - dateA);
96   
97  14 resolution--;
98  14 months = difference / MONTH_MILLIS;
99  14 if (months > 0)
100    {
101  4 difference = difference % MONTH_MILLIS;
102  4 if (months > 1)
103    {
104  1 sb.append(months).append(" ").append(getText(resourceBundle, "core.dateutils.months")).append(", ");
105    }
106    else
107    {
108  3 sb.append(months).append(" ").append(getText(resourceBundle, "core.dateutils.month")).append(", ");
109    }
110    }
111   
112  14 if (resolution < 0)
113    {
114  2 if (sb.length() == 0)
115    {
116  2 return "0 " + getText(resourceBundle, "core.dateutils.months");
117    }
118    else
119    {
120  0 return sb.substring(0, sb.length() - 2);
121    }
122    }
123    else
124    {
125  12 resolution--;
126  12 days = difference / DAY_MILLIS;
127  12 if (days > 0)
128    {
129  9 difference = difference % DAY_MILLIS;
130  9 if (days > 1)
131    {
132  8 sb.append(days).append(" ").append(getText(resourceBundle, "core.dateutils.days")).append(", ");
133    }
134    else
135    {
136  1 sb.append(days).append(" ").append(getText(resourceBundle, "core.dateutils.day")).append(", ");
137    }
138    }
139    }
140   
141  12 if (resolution < 0)
142    {
143  4 if (sb.length() == 0)
144    {
145  1 return "0 " + getText(resourceBundle, "core.dateutils.days");
146    }
147    else
148    {
149  3 return sb.substring(0, sb.length() - 2);
150    }
151    }
152    else
153    {
154  8 resolution--;
155  8 hours = difference / HOUR_MILLIS;
156  8 if (hours > 0)
157    {
158  3 difference = difference % HOUR_MILLIS;
159  3 if (hours > 1)
160    {
161  3 sb.append(hours).append(" ").append(getText(resourceBundle, "core.dateutils.hours")).append(", ");
162    }
163    else
164    {
165  0 sb.append(hours).append(" ").append(getText(resourceBundle, "core.dateutils.hour")).append(", ");
166    }
167    }
168    }
169   
170  8 if (resolution < 0)
171    {
172  6 if (sb.length() == 0)
173    {
174  1 return "0 " + getText(resourceBundle, "core.dateutils.hours");
175    }
176    else
177    {
178  5 return sb.substring(0, sb.length() - 2);
179    }
180    }
181    else
182    {
183  2 resolution--;
184  2 minutes = difference / MINUTE_MILLIS;
185  2 if (minutes > 0)
186    {
187  2 difference = difference % MINUTE_MILLIS;
188  2 if (minutes > 1)
189    {
190  2 sb.append(minutes).append(" ").append(getText(resourceBundle, "core.dateutils.minutes")).append(", ");
191    }
192    else
193    {
194  0 sb.append(minutes).append(" ").append(getText(resourceBundle, "core.dateutils.minute")).append(", ");
195    }
196    }
197    }
198   
199  2 if (resolution < 0)
200    {
201  1 if (sb.length() == 0)
202    {
203  0 return "0 " + getText(resourceBundle, "core.dateutils.minutes");
204    }
205    else
206    {
207  1 return sb.substring(0, sb.length() - 2);
208    }
209    }
210    else
211    {
212  1 resolution--;
213  1 seconds = difference / SECOND_MILLIS;
214  1 if (seconds > 0)
215    {
216  1 if (seconds > 1)
217    {
218  1 sb.append(seconds).append(" ").append(getText(resourceBundle, "core.dateutils.seconds")).append(", ");
219    }
220    else
221    {
222  0 sb.append(seconds).append(" ").append(getText(resourceBundle, "core.dateutils.second")).append(", ");
223    }
224    }
225    }
226   
227  1 if (resolution <= 0 && sb.length() == 0)
228    {
229  0 return "0 " + getText(resourceBundle, "core.dateutils.seconds");
230    }
231   
232  1 if (sb.length() > 2)
233    {
234  1 return sb.substring(0, sb.length() - 2);
235    }
236    else
237    {
238  0 return "";
239    }
240    }
241   
242   
 
243  0 toggle public static String formatDateISO8601(Date ts)
244    {
245  0 return ISO8601DateFormat.format(ts);
246    }
247   
248    /**
249    * Check whether a given duration string is valid
250    *
251    * @param s the duration string
252    * @return true if it a valid duration
253    */
 
254  0 toggle public static boolean validDuration(String s)
255    {
256  0 try
257    {
258  0 getDuration(s);
259  0 return true;
260    }
261    catch (InvalidDurationException e)
262    {
263  0 return false;
264    }
265    }
266   
267    /**
268    * Given a duration string, get the number of minutes it represents (all case insensitive):
269    * <ul>
270    * <li>w = weeks
271    * <li>d = days
272    * <li>h = hours
273    * <li>m = minutes
274    * </ul>
275    * If no category is specified, assume minutes.<br>
276    * Each field must be separated by a space, and they can come in any order.
277    * Case is ignored.
278    * <p/>
279    * ie 2h = 120, 60m = 60, 3d = 24 * 60, 30m
280    *
281    * @param durationStr the duration string
282    * @return the duration in seconds
283    * @throws InvalidDurationException if the duration is invalid
284    */
 
285  21 toggle public static long getDuration(String durationStr) throws InvalidDurationException
286    {
287  21 return getDurationSeconds(durationStr, DAY, WEEK);
288    }
289   
290    /**
291    * Get a duration string with the possibility of a negative.
292    * <p/>
293    * A duration will be considered negative if the first non-space character is a - sign.
294    *
295    * @param durationStr the duration string
296    * @return the duration in seconds, which can be negative
297    * @throws InvalidDurationException if its a badly formatted duration
298    */
 
299  4 toggle public static long getDurationWithNegative(String durationStr) throws InvalidDurationException
300    {
301  4 String cleanedDurationStr = TextUtils.noNull(durationStr).trim();
302  4 if (!TextUtils.stringSet(cleanedDurationStr))
303    {
304  0 return 0;
305    }
306   
307  4 boolean negative = false;
308   
309  4 if (cleanedDurationStr.charAt(0) == '-')
310    {
311  3 negative = true;
312    }
313   
314  4 if (negative)
315    {
316  3 return 0 - getDuration(cleanedDurationStr.substring(1));
317    }
318    else
319    {
320  1 return getDuration(cleanedDurationStr);
321    }
322    }
323   
324    /**
325    * This function retrieves a duration in seconds that depends on number of hours in a day and
326    * days in a week
327    *
328    * @param durationStr to convert to a duration
329    * @param hoursPerDay Number of hourse i day
330    * @param daysPerWeek Days Per Week
331    * @return the duration in seconds
332    * @throws InvalidDurationException if its badly formatted duration
333    */
 
334  3 toggle public static long getDuration(String durationStr, int hoursPerDay, int daysPerWeek) throws InvalidDurationException
335    {
336  3 int secondsInDay = hoursPerDay * HOUR;
337  3 int secondsPerWeek = daysPerWeek * secondsInDay;
338  3 return getDurationSeconds(durationStr, secondsInDay, secondsPerWeek);
339    }
340   
 
341  54 toggle private static long getDurationSeconds(String durationStr, int secondsPerDay, int secondsPerWeek)
342    throws InvalidDurationException
343    {
344  54 long time = 0;
345  54 String remainingDurationStr = null;
346   
347  54 if (!TextUtils.stringSet(durationStr))
348    {
349  2 return 0;
350    }
351   
352  52 durationStr = durationStr.trim().toLowerCase();
353   
354    // if we have more than one 'token', parse each separately
355  52 if (durationStr.indexOf(" ") > 0)
356    {
357  11 StringTokenizer st = new StringTokenizer(durationStr, ", ");
358  40 while (st.hasMoreTokens())
359    {
360  30 time += getDurationSeconds(st.nextToken(), secondsPerDay, secondsPerWeek);
361    }
362    }
363    else
364    {
365  41 try // detect if we just have a number
366    {
367  41 time = Long.parseLong(durationStr.trim()) * MINUTE;
368    }
369    catch (Exception ex) // otherwise get the value
370    {
371    //Extract number and adjust this number with the time factor
372  77 for (int i = 0; i < durationStr.length(); i++)
373    {
374  76 if (!Character.isDigit(durationStr.charAt(i)))
375    {
376  35 if (i == 0)
377    {
378  2 throw new InvalidDurationException("Must have integer preceding duration type");
379    }
380   
381  33 time = Long.parseLong(durationStr.substring(0, i));
382  33 remainingDurationStr = durationStr.substring(i + 1);
383   
384  33 switch ((int) durationStr.charAt(i))
385    {
386  7 case(int) 'm':
387  7 time *= MINUTE;
388  7 break;
389  14 case(int) 'h':
390  14 time *= HOUR;
391  14 break;
392  7 case(int) 'd':
393  7 time *= secondsPerDay;
394  7 break;
395  4 case(int) 'w':
396  4 time *= secondsPerWeek;
397  4 break;
398  1 default:
399  1 throw new InvalidDurationException("Not a valid duration string");
400    }
401   
402  32 break;
403    } // if
404    } // for
405    } // catch
406    }
407   
408  48 if (remainingDurationStr != null && remainingDurationStr.length() != 0 && Character.isDigit(remainingDurationStr.charAt(0)))
409    {
410  0 time += getDurationSeconds(remainingDurationStr, secondsPerDay, secondsPerWeek);
411    }
412  48 return time;
413    }
414   
415    /**
416    * Get String representation of a duration
417    * <p/>
418    *
419    * @param seconds Number of seconds
420    * @return String representing duration, eg: "1h 30m"
421    * @see #getDurationStringWithNegative(long)
422    */
 
423  12 toggle public static String getDurationString(long seconds)
424    {
425  12 return getDurationStringSeconds(seconds, DAY, WEEK);
426    }
427   
428    /**
429    * Get String representation of a (possibly negative) duration.
430    * <p/>
431    *
432    * @param seconds Number of seconds
433    * @return String representing duration, eg: "-1h 30m"
434    * @see #getDurationString(long)
435    */
 
436  3 toggle public static String getDurationStringWithNegative(long seconds)
437    {
438  3 if (seconds < 0)
439    {
440  2 return "-" + getDurationString(-seconds);
441    }
442    else
443    {
444  1 return getDurationString(seconds);
445    }
446    }
447   
 
448  0 toggle public static String getDurationString(long l, int hoursPerDay, int daysPerWeek)
449    {
450  0 int secondsInDay = hoursPerDay * HOUR;
451  0 int secondsPerWeek = daysPerWeek * secondsInDay;
452  0 return getDurationStringSeconds(l, secondsInDay, secondsPerWeek);
453    }
454   
 
455  12 toggle private static String getDurationStringSeconds(long l, int secondsPerDay, int secondsPerWeek)
456    {
457  12 if (l == 0)
458    {
459  1 return "0m";
460    }
461   
462  11 StringBuffer result = new StringBuffer();
463   
464  11 if (l >= secondsPerWeek)
465    {
466  2 result.append((l / secondsPerWeek));
467  2 result.append("w ");
468  2 l = l % secondsPerWeek;
469    }
470   
471  11 if (l >= secondsPerDay)
472    {
473  3 result.append((l / secondsPerDay));
474  3 result.append("d ");
475  3 l = l % secondsPerDay;
476    }
477   
478  11 if (l >= HOUR)
479    {
480  6 result.append((l / HOUR));
481  6 result.append("h ");
482  6 l = l % HOUR;
483    }
484   
485  11 if (l >= MINUTE)
486    {
487  7 result.append((l / MINUTE));
488  7 result.append("m ");
489    }
490   
491  11 return result.toString().trim();
492    }
493   
494    /**
495    * Converts a number of seconds into a pretty formatted data string. The resolution is in minutes. So if the number of seconds is greater than a minute, it will
496    * only be shown down top minute resolution. If the number of seconds is less than a minute it will be shown in seconds.
497    * <p/>
498    * So for example <code>76</code> becomes <code>'1 minute'</code>, while <code>42</code> becomes <code>'42 seconds'</code>
499    *
500    * @param numSecs the number of seconds in the duration
501    * @param resourceBundle a resouce bundle for i18n
502    * @return a string in readable pretty duration format, using minute resolution
503    */
 
504  14 toggle public static String getDurationPretty(long numSecs, ResourceBundle resourceBundle)
505    {
506  14 return getDurationPrettySeconds(numSecs, DAY, WEEK, resourceBundle, false);
507    }
508   
509    /**
510    * Converts a number of seconds into a pretty formatted data string. The resolution is in minutes. So if the number of seconds is greater than a minute, it will
511    * only be shown down top minute resolution. If the number of seconds is less than a minute it will be shown in seconds.
512    * <p/>
513    * So for example <code>76</code> becomes <code>'1 minute'</code>, while <code>42</code> becomes <code>'42 seconds'</code>
514    *
515    * @param numSecs the number of seconds in the duration
516    * @param hoursPerDay the hours in a day
517    * @param daysPerWeek the number of days in a week
518    * @param resourceBundle a resouce bundle for i18n
519    * @return a string in readable pretty duration format, using minute resolution
520    */
 
521  0 toggle public static String getDurationPretty(long numSecs, int hoursPerDay, int daysPerWeek, ResourceBundle resourceBundle)
522    {
523  0 int secondsInDay = hoursPerDay * HOUR;
524  0 int secondsPerWeek = daysPerWeek * secondsInDay;
525  0 return getDurationPrettySeconds(numSecs, secondsInDay, secondsPerWeek, resourceBundle, false);
526    }
527   
528    /**
529    * Converts a number of seconds into a pretty formatted data string. The resolution is in seconds.
530    * <p/>
531    * So for example <code>76</code> becomes <code>'1 minute, 16 seconds'</code>, while <code>42</code> becomes <code>'42 seconds'</code>
532    *
533    * @param numSecs the number of seconds in the duration
534    * @param resourceBundle a resouce bundle for i18n
535    * @return a string in readable pretty duration format, using second resolution
536    */
 
537  23 toggle public static String getDurationPrettySecondsResolution(long numSecs, ResourceBundle resourceBundle)
538    {
539  23 return getDurationPrettySeconds(numSecs, DAY, WEEK, resourceBundle, true);
540    }
541   
542    /**
543    * Converts a number of seconds into a pretty formatted data string. The resolution is in seconds.
544    * <p/>
545    * So for example <code>76</code> becomes <code>'1 minute, 16 seconds'</code>, while <code>42</code> becomes <code>'42 seconds'</code>
546    *
547    * @param numSecs the number of seconds in the duration
548    * @param hoursPerDay the hours in a day
549    * @param daysPerWeek the number of days in a week
550    * @param resourceBundle a resouce bundle for i18n
551    * @return a string in readable pretty duration format, using second resolution
552    */
 
553  0 toggle public static String getDurationPrettySecondsResolution(long numSecs, int hoursPerDay, int daysPerWeek, ResourceBundle resourceBundle)
554    {
555  0 int secondsInDay = hoursPerDay * HOUR;
556  0 int secondsPerWeek = daysPerWeek * secondsInDay;
557  0 return getDurationPrettySeconds(numSecs, secondsInDay, secondsPerWeek, resourceBundle, true);
558    }
559   
 
560  37 toggle private static String getDurationPrettySeconds(long numSecs, int secondsPerDay, int secondsPerWeek, ResourceBundle resourceBundle, boolean secondsDuration)
561    {
562  37 return getDurationPrettySeconds(numSecs, YEAR, secondsPerDay, secondsPerWeek, resourceBundle, secondsDuration);
563    }
564   
565    /*
566    * This implementation method returns things in "minute resolution" unless the secondResolution flag is true
567    */
 
568  37 toggle private static String getDurationPrettySeconds(long numSecs, int secondsPerYear, int secondsPerDay, int secondsPerWeek, ResourceBundle resourceBundle, boolean secondResolution)
569    {
570  37 if (numSecs == 0)
571    {
572  2 if (secondResolution)
573    {
574  1 return "0 " + getText(resourceBundle, "core.dateutils.seconds");
575    }
576    else
577    {
578  1 return "0 " + getText(resourceBundle, "core.dateutils.minutes");
579    }
580    }
581   
582  35 StringBuffer result = new StringBuffer();
583   
584  35 if (numSecs >= secondsPerYear)
585    {
586  4 long years = numSecs / secondsPerYear;
587  4 result.append(years).append(' ');
588   
589  4 if (years > 1)
590    {
591  2 result.append(getText(resourceBundle, "core.dateutils.years"));
592    }
593    else
594    {
595  2 result.append(getText(resourceBundle, "core.dateutils.year"));
596    }
597   
598  4 result.append(", ");
599  4 numSecs = numSecs % secondsPerYear;
600    }
601   
602  35 if (numSecs >= secondsPerWeek)
603    {
604  10 long weeks = numSecs / secondsPerWeek;
605  10 result.append(weeks).append(' ');
606   
607  10 if (weeks > 1)
608    {
609  10 result.append(getText(resourceBundle, "core.dateutils.weeks"));
610    }
611    else
612    {
613  0 result.append(getText(resourceBundle, "core.dateutils.week"));
614    }
615   
616  10 result.append(", ");
617  10 numSecs = numSecs % secondsPerWeek;
618    }
619   
620  35 if (numSecs >= secondsPerDay)
621    {
622  13 long days = numSecs / secondsPerDay;
623  13 result.append(days).append(' ');
624   
625  13 if (days > 1)
626    {
627  6 result.append(getText(resourceBundle, "core.dateutils.days"));
628    }
629    else
630    {
631  7 result.append(getText(resourceBundle, "core.dateutils.day"));
632    }
633   
634  13 result.append(", ");
635  13 numSecs = numSecs % secondsPerDay;
636    }
637   
638  35 if (numSecs >= HOUR)
639    {
640  15 long hours = numSecs / HOUR;
641  15 result.append(hours).append(' ');
642   
643  15 if (hours > 1)
644    {
645  9 result.append(getText(resourceBundle, "core.dateutils.hours"));
646    }
647    else
648    {
649  6 result.append(getText(resourceBundle, "core.dateutils.hour"));
650    }
651   
652  15 result.append(", ");
653  15 numSecs = numSecs % HOUR;
654    }
655   
656  35 if (numSecs >= MINUTE)
657    {
658  15 long minute = numSecs / MINUTE;
659  15 result.append(minute).append(' ');
660   
661   
662  15 if (minute > 1)
663    {
664  12 result.append(getText(resourceBundle, "core.dateutils.minutes"));
665    }
666    else
667    {
668  3 result.append(getText(resourceBundle, "core.dateutils.minute"));
669    }
670   
671  15 result.append(", ");
672   
673    // if we want seconds resolution we need to reduce it down to seconds here
674  15 if (secondResolution)
675    {
676  10 numSecs = numSecs % MINUTE;
677    }
678    }
679   
680  35 if (numSecs >= SECOND && numSecs < MINUTE)
681    {
682  13 long sec = numSecs;
683  13 result.append(sec).append(' ');
684   
685   
686  13 if (sec > 1)
687    {
688  9 result.append(getText(resourceBundle, "core.dateutils.seconds"));
689    }
690    else
691    {
692  4 result.append(getText(resourceBundle, "core.dateutils.second"));
693    }
694   
695  13 result.append(", ");
696    }
697   
698  35 if (result.length() > 2) // remove the ", " on th end
699    {
700  35 return result.substring(0, result.length() - 2);
701    }
702    else
703    {
704  0 return result.toString();
705    }
706    }
707   
708    /** This is used by the Velocity templates as a bean */
 
709  0 toggle public String formatDurationPretty(long l)
710    {
711  0 return DateUtils.getDurationPretty(l, resourceBundle);
712    }
713   
714    /** This is used by the Velocity templates as a bean */
 
715  0 toggle public String formatDurationPretty(String seconds)
716    {
717  0 return DateUtils.getDurationPretty(Long.parseLong(seconds), resourceBundle);
718    }
719   
720   
721    /** This is used by the WebWork tags as a bean */
 
722  0 toggle public String formatDurationString(long l)
723    {
724  0 return DateUtils.getDurationPretty(l, resourceBundle);
725    }
726   
 
727  95 toggle private static String getText(ResourceBundle resourceBundle, String key)
728    {
729  95 try
730    {
731  95 return resourceBundle.getString(key);
732    }
733    catch (MissingResourceException e)
734    {
735  0 log.error(e);
736  0 return "";
737    }
738    }
739   
740    /**
741    * Change the date of a Calendar object so that it has the maximum resolution
742    * of "period" where period is one of the constants in CALENDAR_PERIODS above.
743    * <p/>
744    * e.g. to obtain the maximum value for a month, call toEndOfPeriod(calendarObject, Calendar.MONTH)
745    *
746    * @param calendar The Calendar to change
747    * @param period The period to "maximise"
748    * @return A modified Calendar object
749    */
 
750  5 toggle public static Calendar toEndOfPeriod(Calendar calendar, int period)
751    {
752  5 boolean zero = false;
753   
754  40 for (int i = 0; i < CALENDAR_PERIODS.length; i++)
755    {
756  35 if (zero)
757    {
758  20 calendar.set(CALENDAR_PERIODS[i], calendar.getMaximum(CALENDAR_PERIODS[i]));
759    }
760   
761  35 if (CALENDAR_PERIODS[i] == period)
762    {
763  5 zero = true;
764    }
765    }
766   
767  5 if (!zero)
768    {
769  0 throw new IllegalArgumentException("unknown Calendar period: " + period);
770    }
771   
772  5 return calendar;
773    }
774   
775    /**
776    * Change the date of a Calendar object so that it has the minimum resolution
777    * of "period" where period is one of the constants in CALENDAR_PERIODS above.
778    */
 
779  5 toggle public static Calendar toStartOfPeriod(Calendar calendar, int period)
780    {
781  5 boolean zero = false;
782  40 for (int i = 0; i < CALENDAR_PERIODS.length; i++)
783    {
784  35 if (zero)
785    {
786  20 if (CALENDAR_PERIODS[i] == Calendar.DAY_OF_MONTH)
787    {
788  2 calendar.set(Calendar.DAY_OF_MONTH, 1);
789    }
790    else
791    {
792  18 calendar.set(CALENDAR_PERIODS[i], 0);
793    }
794    }
795   
796  35 if (CALENDAR_PERIODS[i] == period)
797    {
798  5 zero = true;
799    }
800   
801    }
802   
803  5 if (!zero)
804    {
805  0 throw new IllegalArgumentException("unknown Calendar period: " + period);
806    }
807   
808  5 return calendar;
809    }
810   
811    /**
812    * Given a period, and a date that falls within that period, create a range of dates such
813    * that the period is contained exactly within [startDate <= {range} < endDate]
814    *
815    * @param date a calendar object of a date falling in that range
816    * @param period something in CALENDAR_PERIODS
817    */
 
818  0 toggle public static DateRange toDateRange(Calendar date, int period)
819    {
820    // defensively copy the calendar so we don't break anything outside.
821  0 Calendar cal = (Calendar) date.clone();
822  0 toStartOfPeriod(cal, period);
823  0 Date startDate = new Date(cal.getTimeInMillis());
824  0 cal.add(period, 1);
825  0 Date endDate = new Date(cal.getTimeInMillis());
826   
827  0 return new DateRange(startDate, endDate);
828    }
829   
 
830  0 toggle public static Calendar getCalendarDay(int year, int month, int day)
831    {
832  0 return initCalendar(year, month, day, 0, 0, 0, 0);
833    }
834   
 
835  0 toggle public static Date getDateDay(int year, int month, int day)
836    {
837  0 return getCalendarDay(year, month, day).getTime();
838    }
839   
 
840  0 toggle public static Date getSqlDateDay(int year, int month, int day)
841    {
842  0 return new java.sql.Date(getCalendarDay(year, month, day).getTimeInMillis());
843    }
844   
845   
 
846  0 toggle public static Date tomorrow()
847    {
848  0 Calendar cal = Calendar.getInstance();
849  0 cal.add(Calendar.DAY_OF_MONTH, 1);
850  0 return cal.getTime();
851    }
852   
 
853  0 toggle public static Date yesterday()
854    {
855  0 Calendar cal = Calendar.getInstance();
856  0 cal.add(Calendar.DAY_OF_MONTH, -1);
857  0 return cal.getTime();
858    }
859   
 
860  0 toggle private static Calendar initCalendar(int year, int month, int day, int hour, int minute, int second, int millis)
861    {
862  0 Calendar calendar = Calendar.getInstance();
863  0 calendar.set(year, month, day, hour, minute, second);
864  0 calendar.set(Calendar.MILLISECOND, millis);
865  0 return calendar;
866    }
867    }