]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
67c1abc0d9ea045b2f1c3ae3ccaba60645359a61
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.structureddate;
2
3 import org.joda.time.Chronology;
4 import org.joda.time.DateTime;
5 import org.joda.time.DateTimeConstants;
6 import org.joda.time.Days;
7 import org.joda.time.IllegalFieldValueException;
8 import org.joda.time.MutableDateTime;
9 import org.joda.time.Years;
10 import org.joda.time.chrono.GJChronology;
11 import org.joda.time.format.DateTimeFormat;
12 import org.joda.time.format.DateTimeFormatter;
13 import org.joda.time.LocalDate;
14
15 public class DateUtils {
16         private static final DateTimeFormatter monthFormatter = DateTimeFormat.forPattern("MMMM");
17         private static final DateTimeFormatter scalarDateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
18
19         // The chronology to use for date calculations, which are done using the joda-time library.
20         // See http://www.joda.org/joda-time/apidocs/org/joda/time/Chronology.html for descriptions of
21         // the chronologies supported by joda-time.
22         
23         // GJChronology (http://www.joda.org/joda-time/apidocs/org/joda/time/chrono/GJChronology.html)
24         // seems best for representing a mix of modern and historical dates, as might be seen by an
25         // anthropology museum.
26         
27         private static final Chronology chronology = GJChronology.getInstance();
28         
29         // Define the DateTime that serves as the basis for circa calculations, using the algorithm
30         // ported from the XDB date parser. Its comment states:
31         //
32         //    We define circa year/century specifications offsets
33         //    as +/- 5% of the difference between that year/century
34         //    and the present (2100), so that the farther we go back
35         //    in time, the wider the range of meaning of "circa."
36         
37         private static final DateTime circaBaseDateTime = new DateTime(2100, 12, 31, 0, 0, 0, 0, chronology);
38         
39         /**
40          * Gets the number (1-12) of a month for a given name.
41          * 
42          * @param monthName The name of the month
43          * @return          The number of the month, between 1 and 12
44          */
45         public static int getMonthByName(String monthName) {
46                 // Normalize "sept" to "sep", since DateTimeFormat doesn't
47                 // understand the former.
48                 
49                 if (monthName.equals("sept")) {
50                         monthName = "sep";
51                 }
52                 
53                 return monthFormatter.parseDateTime(monthName).getMonthOfYear();
54         }
55         
56         /**
57          * Gets the number of days in a given month.
58          * 
59          * @param month The month number, between 1 and 12
60          * @param year  The year (in order to account for leap years)
61          * @return      The number of days in the month
62          */
63         public static int getDaysInMonth(int month, int year, Era era) {
64                 if (era == null) {
65                         era = Date.DEFAULT_ERA;
66                 }
67                 
68                 DateTime dateTime = new DateTime(chronology)
69                                 .withEra((era == Era.BCE) ? DateTimeConstants.BC : DateTimeConstants.AD)
70                                 .withYearOfEra(year)
71                                 .withMonthOfYear(month);
72
73                 return dateTime.dayOfMonth().getMaximumValue();
74         }
75         
76         /**
77          * Gets the Date representing the first day of a given quarter year.
78          * 
79          * @param year    The year
80          * @param quarter The quarter, between 1 and 4
81          * @return        The first day of the quarter year
82          */
83         public static Date getQuarterYearStartDate(int quarter, int year) {
84                 int startMonth = getQuarterYearStartMonth(quarter);
85                 
86                 return new Date(year, startMonth, 1);
87         }
88         
89         /**
90          * Gets the Date representing the last day of a given quarter year.
91          * 
92          * @param year    The year
93          * @param quarter The quarter, between 1 and 4
94          * @return        The last day of the quarter year
95          */
96         public static Date getQuarterYearEndDate(int quarter, int year, Era era) {
97                 int endMonth = getQuarterYearEndMonth(quarter);
98                 
99                 return new Date(year, endMonth, DateUtils.getDaysInMonth(endMonth, year, era));
100         }
101         
102         /**
103          * Gets the first month of a given quarter in a year.
104          * 
105          * @param quarter The quarter, between 1 and 4
106          * @return        The number of the first month in the quarter
107          */
108         public static int getQuarterYearStartMonth(int quarter) {
109                 return ((3 * (quarter-1)) + 1);
110         }
111         
112         /**
113          * Gets the last month of a given quarter in a year.
114          * 
115          * @param quarter The quarter, between 1 and 4
116          * @return        The number of the last month in the quarter
117          */
118         public static int getQuarterYearEndMonth(int quarter) {
119                 return (getQuarterYearStartMonth(quarter) + 2);
120         }
121
122         /**
123          * Gets the Date representing the first day of a given half year.
124          * 
125          * @param year The year
126          * @param half The half, between 1 and 2
127          * @return     The first day of the half year
128          */
129         public static Date getHalfYearStartDate(int half, int year) {
130                 int startMonth = getHalfYearStartMonth(half);
131                 
132                 return new Date(year, startMonth, 1);
133         }
134
135
136         /**
137          * Gets the Date representing the last day of a given half year.
138          * 
139          * @param year The year
140          * @param half The half, between 1 and 2
141          * @return     The last day of the half year
142          */
143         public static Date getHalfYearEndDate(int half, int year, Era era) {
144                 int endMonth = getHalfYearEndMonth(half);
145                 
146                 return new Date(year, endMonth, DateUtils.getDaysInMonth(endMonth, year, era));
147         }
148
149         /**
150          * Gets the first month of a given half in a year.
151          * 
152          * @param half The half, between 1 and 2
153          * @return     The number of the first month in the half
154          */
155         public static int getHalfYearStartMonth(int half) {
156                 return ((6 * (half-1)) + 1);
157         }
158
159         /**
160          * Gets the last month of a given half in a year.
161          * 
162          * @param half The half, between 1 and 2
163          * @return     The number of the last month in the half
164          */
165         public static int getHalfYearEndMonth(int half) {
166                 return (getHalfYearStartMonth(half) + 5);
167         }
168         
169         /**
170          * Gets the Date representing the first day of a given partial year.
171          * 
172          * @param year The year
173          * @param part The part
174          * @return     The first day of the partial year
175          */
176         public static Date getPartialYearStartDate(Part part, int year) {
177                 int startMonth = getPartialYearStartMonth(part);
178                 
179                 return new Date(year, startMonth, 1);
180         }
181
182         /**
183          * Gets the Date representing the last day of a given partial year.
184          * 
185          * @param year The year
186          * @param part The part
187          * @return     The last day of the partial year
188          */
189         public static Date getPartialYearEndDate(Part part, int year, Era era) {
190                 int endMonth = getPartialYearEndMonth(part);
191                 
192                 return new Date(year, endMonth, DateUtils.getDaysInMonth(endMonth, year, era));
193         }
194         
195         /**
196          * Gets the first month of a given part of a year.
197          * 
198          * @param part The part
199          * @return     The number of the first month in the part
200          */
201         public static int getPartialYearStartMonth(Part part) {
202                 int month;
203                 
204                 if (part == Part.EARLY) {
205                         month = 1;
206                 }
207                 else if (part == Part.MIDDLE) {
208                         month = 5;
209                 }
210                 else if (part == Part.LATE) {
211                         month = 9;
212                 }
213                 else {
214                         throw new IllegalArgumentException("unexpected part");
215                 }
216                 
217                 return month;
218         }
219         
220         /**
221          * Gets the last month of a given part of a year.
222          * 
223          * @param part The part
224          * @return     The number of the last month in the part
225          */
226         public static int getPartialYearEndMonth(Part part) {
227                 int month;
228                 
229                 if (part == Part.EARLY) {
230                         month = 4;
231                 }
232                 else if (part == Part.MIDDLE) {
233                         month = 8;
234                 }
235                 else if (part == Part.LATE) {
236                         month = 12;
237                 }
238                 else {
239                         throw new IllegalArgumentException("unexpected part");
240                 }
241                 
242                 return month;
243         }
244         
245         /**
246          * Gets the Date representing the first day of a given partial decade.
247          * 
248          * @param decade The decade, specified as a number ending in 0.
249          *               For decades A.D., this is the first year of the decade. For 
250          *               decades B.C., this is the last year of the decade.
251          * @param part   The part
252          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
253          * @return       The first day of the partial decade
254          */
255         public static Date getPartialDecadeStartDate(int decade, Part part, Era era) {
256                 if (era == null) {
257                         era = Date.DEFAULT_ERA;
258                 }
259
260                 int startYear = getPartialDecadeStartYear(decade, part, era);
261                 
262                 return new Date(startYear, 1, 1, era);
263         }
264
265         /**
266          * Gets the Date representing the last day of a given partial decade.
267          * 
268          * @param decade The decade, specified as a number ending in 0.
269          *               For decades A.D., this is the first year of the decade. For 
270          *               decades B.C., this is the last year of the decade.
271          * @param part   The part
272          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
273          * @return       The last day of the partial decade
274          */
275         public static Date getPartialDecadeEndDate(int decade, Part part, Era era) {
276                 if (era == null) {
277                         era = Date.DEFAULT_ERA;
278                 }
279
280                 int endYear = getPartialDecadeEndYear(decade, part, era);
281                 
282                 return new Date(endYear, 12, 31, era);
283         }
284         
285         /**
286          * Gets the first year of a given part of a decade.
287          * 
288          * @param decade The decade, specified as a number ending in 0.
289          *               For decades A.D., this is the first year of the decade. For 
290          *               decades B.C., this is the last year of the decade.
291          * @param part   The part
292          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
293          * @return       The first year in the part
294          */
295         public static int getPartialDecadeStartYear(int decade, Part part, Era era) {
296                 if (era == null) {
297                         era = Date.DEFAULT_ERA;
298                 }
299                 
300                 int startYear;
301                 
302                 if (era == Era.BCE) {
303                         if (part == Part.EARLY) {
304                                 startYear = decade + 9;
305                         }
306                         else if (part == Part.MIDDLE) {
307                                 startYear = decade + 6;
308                         }
309                         else if (part == Part.LATE) {
310                                 startYear = decade + 3;
311                         }
312                         else {
313                                 throw new IllegalArgumentException("unexpected part");
314                         }
315                 }
316                 else {
317                         if (part == Part.EARLY) {
318                                 startYear = decade;
319                         }
320                         else if (part == Part.MIDDLE) {
321                                 startYear = decade + 4;
322                         }
323                         else if (part == Part.LATE) {
324                                 startYear = decade + 7;
325                         }
326                         else {
327                                 throw new IllegalArgumentException("unexpected part");
328                         }
329                 }
330                 
331                 return startYear;
332         }
333         
334         /**
335          * Gets the last year of a given part of a decade.
336          * 
337          * @param decade The decade, specified as a number ending in 0.
338          *               For decades A.D., this is the first year of the decade. For 
339          *               decades B.C., this is the last year of the decade.
340          * @param part   The part
341          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
342          * @return       The last year in the part
343          */
344         public static int getPartialDecadeEndYear(int decade, Part part, Era era) {
345                 if (era == null) {
346                         era = Date.DEFAULT_ERA;
347                 }
348                 
349                 int endYear;
350                 
351                 if (era == Era.BCE) {
352                         if (part == Part.EARLY) {
353                                 endYear = decade + 7;
354                         }
355                         else if (part == Part.MIDDLE) {
356                                 endYear = decade + 4;
357                         }
358                         else if (part == Part.LATE) {
359                                 endYear = decade;
360                         }
361                         else {
362                                 throw new IllegalArgumentException("unexpected part");
363                         }
364                 }
365                 else {
366                         if (part == Part.EARLY) {
367                                 endYear = decade + 3;
368                         }
369                         else if (part == Part.MIDDLE) {
370                                 endYear = decade + 6;
371                         }
372                         else if (part == Part.LATE) {
373                                 endYear = decade + 9;
374                         }
375                         else {
376                                 throw new IllegalArgumentException("unexpected part");
377                         }
378                 }
379                 
380                 return endYear;
381         }
382
383         /**
384          * Gets the Date representing the first day of a given decade.
385          * 
386          * @param decade The decade, specified as a number ending in 0.
387          *               For decades A.D., this is the first year of the decade. For 
388          *               decades B.C., this is the last year of the decade.
389          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
390          * @return       The first day of the decade
391          */
392         public static Date getDecadeStartDate(int decade, Era era) {
393                 if (era == null) {
394                         era = Date.DEFAULT_ERA;
395                 }
396
397                 int startYear = getDecadeStartYear(decade, era);
398                 
399                 return new Date(startYear, 1, 1, era);
400         }
401         
402         /**
403          * Gets the Date representing the last day of a given decade.
404          * 
405          * @param decade The decade, specified as a number ending in 0.
406          *               For decades A.D., this is the first year of the decade. For 
407          *               decades B.C., this is the last year of the decade.
408          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
409          * @return       The last day of the decade
410          */
411         public static Date getDecadeEndDate(int decade, Era era) {
412                 if (era == null) {
413                         era = Date.DEFAULT_ERA;
414                 }
415
416                 int endYear = getDecadeEndYear(decade, era);
417                 
418                 return new Date(endYear, 12, 31, era);
419         }
420         
421         /**
422          * Gets the first year of a given decade.
423          * 
424          * @param decade The decade, specified as a number ending in 0.
425          *               For decades A.D., this is the first year of the decade. For 
426          *               decades B.C., this is the last year of the decade.
427          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
428          * @return       The first year of the decade
429          */
430         public static int getDecadeStartYear(int decade, Era era) {
431                 if (era == null) {
432                         era = Date.DEFAULT_ERA;
433                 }
434                 
435                 int startYear;
436                 
437                 if (era == Era.BCE) {
438                         startYear = decade + 9;
439                 }
440                 else {
441                         startYear = decade;
442                 }
443                 
444                 return startYear;
445         }
446
447         /**
448          * Gets the last year of a given decade.
449          * 
450          * @param decade The decade, specified as a number ending in 0.
451          *               For decades A.D., this is the first year of the decade. For 
452          *               decades B.C., this is the last year of the decade.
453          * @param era    The era of the decade. If null, Date.DEFAULT_ERA is assumed.
454          * @return       The last year of the decade
455          */
456         public static int getDecadeEndYear(int decade, Era era) {
457                 if (era == null) {
458                         era = Date.DEFAULT_ERA;
459                 }
460                 
461                 int endYear;
462                 
463                 if (era == Era.BCE) {
464                         endYear = decade;
465                 }
466                 else {
467                         endYear = decade + 9;
468                 }
469                 
470                 return endYear;
471         }
472                 
473         /**
474          * Gets the Date representing the first day of a given century.
475          * 
476          * @param century The century, specified as a number ending in 00 or 01.
477          *                For centuries A.D., this is the first year of the century. For 
478          *                centuries B.C., this is the last year of the century. For example,
479          *                the "21st century" would be specified as 2001, whereas the "2000's"
480          *                would be specified as 2000. The "2nd century B.C." would be specified
481          *                as 101. The "100's B.C." would be specified as 100.
482          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
483          * @return        The first day of the century
484          */
485         public static Date getCenturyStartDate(int century, Era era) {
486                 if (era == null) {
487                         era = Date.DEFAULT_ERA;
488                 }
489
490                 int startYear = getCenturyStartYear(century, era);
491                 
492                 return new Date(startYear, 1, 1, era);
493         }
494
495         /**
496          * Gets the Date representing the last day of a given century.
497          * 
498          * @param century The century, specified as a number ending in 00 or 01.
499          *                For centuries A.D., this is the first year of the century. For 
500          *                centuries B.C., this is the last year of the century. For example,
501          *                the "21st century" would be specified as 2001, whereas the "2000's"
502          *                would be specified as 2000. The "2nd century B.C." would be specified
503          *                as 101. The "100's B.C." would be specified as 100.
504          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
505          * @return        The last day of the century
506          */
507         public static Date getCenturyEndDate(int century, Era era) {
508                 if (era == null) {
509                         era = Date.DEFAULT_ERA;
510                 }
511
512                 int endYear = getCenturyEndYear(century, era);
513                 
514                 return new Date(endYear, 12, 31, era);
515         }
516         
517         /**
518          * Gets the first year of a given century.
519          * 
520          * @param century The century, specified as a number ending in 00 or 01.
521          *                For centuries A.D., this is the first year of the century. For 
522          *                centuries B.C., this is the last year of the century. For example,
523          *                the "21st century" would be specified as 2001, whereas the "2000's"
524          *                would be specified as 2000. The "2nd century B.C." would be specified
525          *                as 101. The "100's B.C." would be specified as 100.
526          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
527          * @return        The first year of the century
528          */
529         public static int getCenturyStartYear(int century, Era era) {
530                 if (era == null) {
531                         era = Date.DEFAULT_ERA;
532                 }
533                 
534                 int startYear;
535                 
536                 if (era == Era.BCE) {
537                         startYear = century + 99;
538                 }
539                 else {
540                         startYear = century;
541                 }
542                 
543                 return startYear;
544         }
545         
546         /**
547          * Gets the last year of a given century.
548          * 
549          * @param century The century, specified as a number ending in 00 or 01.
550          *                For centuries A.D., this is the first year of the century. For 
551          *                centuries B.C., this is the last year of the century. For example,
552          *                the "21st century" would be specified as 2001, whereas the "2000's"
553          *                would be specified as 2000. The "2nd century B.C." would be specified
554          *                as 101. The "100's B.C." would be specified as 100.
555          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
556          * @return        The last year of the century
557          */
558         public static int getCenturyEndYear(int century, Era era) {
559                 if (era == null) {
560                         era = Date.DEFAULT_ERA;
561                 }
562                 
563                 int endYear;
564                 
565                 if (era == Era.BCE) {
566                         endYear = century;
567                 }
568                 else {
569                         endYear = century + 99;
570                 }
571                 
572                 return endYear;
573         }
574         
575         /**
576          * Gets the Date representing the first day of a given partial century.
577          * 
578          * @param century The century, specified as a number ending in 00 or 01.
579          *                For centuries A.D., this is the first year of the century. For 
580          *                centuries B.C., this is the last year of the century. For example,
581          *                the "21st century" would be specified as 2001, whereas the "2000's"
582          *                would be specified as 2000. The "2nd century B.C." would be specified
583          *                as 101. The "100's B.C." would be specified as 100.
584          * @param part    The part
585          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
586          * @return        The first day of the partial century
587          */
588         public static Date getPartialCenturyStartDate(int century, Part part, Era era) {
589                 if (era == null) {
590                         era = Date.DEFAULT_ERA;
591                 }
592
593                 int startYear = getPartialCenturyStartYear(century, part, era);
594                 
595                 return new Date(startYear, 1, 1, era);
596         }
597         
598         /**
599          * Gets the Date representing the last day of a given partial century.
600          * 
601          * @param century The century, specified as a number ending in 00 or 01.
602          *                For centuries A.D., this is the first year of the century. For 
603          *                centuries B.C., this is the last year of the century. For example,
604          *                the "21st century" would be specified as 2001, whereas the "2000's"
605          *                would be specified as 2000. The "2nd century B.C." would be specified
606          *                as 101. The "100's B.C." would be specified as 100.
607          * @param part    The part
608          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
609          * @return        The last day of the partial century
610          */
611         public static Date getPartialCenturyEndDate(int century, Part part, Era era) {
612                 if (era == null) {
613                         era = Date.DEFAULT_ERA;
614                 }
615
616                 int endYear = getPartialCenturyEndYear(century, part, era);
617                 
618                 return new Date(endYear, 12, 31, era);
619         }
620         
621         /**
622          * Gets the first year of a given partial century.
623          * 
624          * @param century The century, specified as a number ending in 00 or 01.
625          *                For centuries A.D., this is the first year of the century. For 
626          *                centuries B.C., this is the last year of the century. For example,
627          *                the "21st century" would be specified as 2001, whereas the "2000's"
628          *                would be specified as 2000. The "2nd century B.C." would be specified
629          *                as 101. The "100's B.C." would be specified as 100.
630          * @param part    The part
631          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
632          * @return        The first year of the partial century
633          */
634         public static int getPartialCenturyStartYear(int century, Part part, Era era) {
635                 if (era == null) {
636                         era = Date.DEFAULT_ERA;
637                 }
638                 
639                 int startYear;
640                 
641                 if (era == Era.BCE) {
642                         if (part == Part.EARLY) {
643                                 startYear = century + 99;
644                         }
645                         else if (part == Part.MIDDLE) {
646                                 startYear = century + 66;
647                         }
648                         else if (part == Part.LATE) {
649                                 startYear = century + 33;
650                         }
651                         else {
652                                 throw new IllegalArgumentException("unexpected part");
653                         }
654                 }
655                 else {
656                         if (part == Part.EARLY) {
657                                 startYear = century;
658                         }
659                         else if (part == Part.MIDDLE) {
660                                 startYear = century + 33;
661                         }
662                         else if (part == Part.LATE) {
663                                 startYear = century + 66;
664                         }
665                         else {
666                                 throw new IllegalArgumentException("unexpected part");
667                         }
668                 }
669                 
670                 return startYear;
671         }
672         
673         /**
674          * Gets the last year of a given partial century.
675          * 
676          * @param century The century, specified as a number ending in 00 or 01.
677          *                For centuries A.D., this is the first year of the century. For 
678          *                centuries B.C., this is the last year of the century. For example,
679          *                the "21st century" would be specified as 2001, whereas the "2000's"
680          *                would be specified as 2000. The "2nd century B.C." would be specified
681          *                as 101. The "100's B.C." would be specified as 100.
682          * @param part    The part
683          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
684          * @return        The last year of the partial century
685          */
686         public static int getPartialCenturyEndYear(int century, Part part, Era era) {
687                 if (era == null) {
688                         era = Date.DEFAULT_ERA;
689                 }
690                 
691                 int endYear;
692                 
693                 if (era == Era.BCE) {
694                         if (part == Part.EARLY) {
695                                 endYear = century + 66;
696                         }
697                         else if (part == Part.MIDDLE) {
698                                 endYear = century + 33;
699                         }
700                         else if (part == Part.LATE) {
701                                 endYear = century;
702                         }
703                         else {
704                                 throw new IllegalArgumentException("unexpected part");
705                         }
706                 }
707                 else {
708                         if (part == Part.EARLY) {
709                                 endYear = century + 33;
710                         }
711                         else if (part == Part.MIDDLE) {
712                                 endYear = century + 66;
713                         }
714                         else if (part == Part.LATE) {
715                                 endYear = century + 99;
716                         }
717                         else {
718                                 throw new IllegalArgumentException("unexpected part");
719                         }
720                 }
721                 
722                 return endYear;
723         }
724         
725         /**
726          * Gets the Date representing the first day of a given half century.
727          * 
728          * @param century The century, specified as a number ending in 00 or 01.
729          *                For centuries A.D., this is the first year of the century. For 
730          *                centuries B.C., this is the last year of the century. For example,
731          *                the "21st century" would be specified as 2001, whereas the "2000's"
732          *                would be specified as 2000. The "2nd century B.C." would be specified
733          *                as 101. The "100's B.C." would be specified as 100.
734          * @param half    The half
735          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
736          * @return        The first day of the half century
737          */
738         public static Date getHalfCenturyStartDate(int century, int half, Era era) {
739                 if (era == null) {
740                         era = Date.DEFAULT_ERA;
741                 }
742
743                 int startYear = getHalfCenturyStartYear(century, half, era);
744                 
745                 return new Date(startYear, 1, 1, era);
746         }
747
748         /**
749          * Gets the Date representing the last day of a given half century.
750          * 
751          * @param century The century, specified as a number ending in 00 or 01.
752          *                For centuries A.D., this is the first year of the century. For 
753          *                centuries B.C., this is the last year of the century. For example,
754          *                the "21st century" would be specified as 2001, whereas the "2000's"
755          *                would be specified as 2000. The "2nd century B.C." would be specified
756          *                as 101. The "100's B.C." would be specified as 100.
757          * @param half    The half
758          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
759          * @return        The last day of the half century
760          */
761         public static Date getHalfCenturyEndDate(int century, int half, Era era) {
762                 if (era == null) {
763                         era = Date.DEFAULT_ERA;
764                 }
765
766                 int endYear = getHalfCenturyEndYear(century, half, era);
767                 
768                 return new Date(endYear, 12, 31, era);
769         }
770         
771         /**
772          * Gets the first year of a given half century.
773          * 
774          * @param century The century, specified as a number ending in 00 or 01.
775          *                For centuries A.D., this is the first year of the century. For 
776          *                centuries B.C., this is the last year of the century. For example,
777          *                the "21st century" would be specified as 2001, whereas the "2000's"
778          *                would be specified as 2000. The "2nd century B.C." would be specified
779          *                as 101. The "100's B.C." would be specified as 100.
780          * @param half    The half
781          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
782          * @return        The first year of the half century
783          */
784         public static int getHalfCenturyStartYear(int century, int half, Era era) {
785                 if (era == null) {
786                         era = Date.DEFAULT_ERA;
787                 }
788                 
789                 int startYear;
790                 
791                 if (era == Era.BCE) {
792                         startYear = (century + 99) - (50 * (half - 1));
793                 }
794                 else {
795                         startYear = century + (50 * (half - 1));
796                 }
797                 
798                 return startYear;
799         }
800         
801         /**
802          * Gets the last year of a given half century.
803          * 
804          * @param century The century, specified as a number ending in 00 or 01.
805          *                For centuries A.D., this is the first year of the century. For 
806          *                centuries B.C., this is the last year of the century. For example,
807          *                the "21st century" would be specified as 2001, whereas the "2000's"
808          *                would be specified as 2000. The "2nd century B.C." would be specified
809          *                as 101. The "100's B.C." would be specified as 100.
810          * @param half    The half
811          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
812          * @return        The last year of the half century
813          */
814         public static int getHalfCenturyEndYear(int century, int half, Era era) {
815                 if (era == null) {
816                         era = Date.DEFAULT_ERA;
817                 }
818                 
819                 int endYear;
820                 
821                 if (era == Era.BCE) {
822                         endYear = (century + 99) - (50 * half) + 1;
823                 }
824                 else {
825                         endYear = century + (50 * half) - 1;
826                 }
827                 
828                 return endYear;
829         }
830         
831         /**
832          * Gets the Date representing the first day of a given quarter century.
833          * 
834          * @param century The century, specified as a number ending in 00 or 01.
835          *                For centuries A.D., this is the first year of the century. For 
836          *                centuries B.C., this is the last year of the century. For example,
837          *                the "21st century" would be specified as 2001, whereas the "2000's"
838          *                would be specified as 2000. The "2nd century B.C." would be specified
839          *                as 101. The "100's B.C." would be specified as 100.
840          * @param quarter The quarter
841          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
842          * @return        The first day of the quarter century
843          */
844         public static Date getQuarterCenturyStartDate(int century, int quarter, Era era) {
845                 if (era == null) {
846                         era = Date.DEFAULT_ERA;
847                 }
848                 
849                 int startYear = getQuarterCenturyStartYear(century, quarter, era);
850                 
851                 return new Date(startYear, 1, 1, era);
852         }
853
854         /**
855          * Gets the Date representing the last day of a given quarter century.
856          * 
857          * @param century The century, specified as a number ending in 00 or 01.
858          *                For centuries A.D., this is the first year of the century. For 
859          *                centuries B.C., this is the last year of the century. For example,
860          *                the "21st century" would be specified as 2001, whereas the "2000's"
861          *                would be specified as 2000. The "2nd century B.C." would be specified
862          *                as 101. The "100's B.C." would be specified as 100.
863          * @param quarter The quarter
864          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
865          * @return        The last day of the quarter century
866          */
867         public static Date getQuarterCenturyEndDate(int century, int quarter, Era era) {
868                 if (era == null) {
869                         era = Date.DEFAULT_ERA;
870                 }
871                 
872                 int endYear = getQuarterCenturyEndYear(century, quarter, era);
873                 
874                 return new Date(endYear, 12, 31, era);
875         }
876         
877         /**
878          * Gets the first year of a given quarter century.
879          * 
880          * @param century The century, specified as a number ending in 00 or 01.
881          *                For centuries A.D., this is the first year of the century. For 
882          *                centuries B.C., this is the last year of the century. For example,
883          *                the "21st century" would be specified as 2001, whereas the "2000's"
884          *                would be specified as 2000. The "2nd century B.C." would be specified
885          *                as 101. The "100's B.C." would be specified as 100.
886          * @param quarter The quarter
887          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
888          * @return        The first year of the quarter century
889          */
890         public static int getQuarterCenturyStartYear(int century, int quarter, Era era) {
891                 if (era == null) {
892                         era = Date.DEFAULT_ERA;
893                 }
894                 
895                 int startYear;
896                 
897                 if (era == Era.BCE) {
898                         startYear = (century + 99) - (25 * (quarter - 1));
899                 }
900                 else {
901                         startYear = century + (25 * (quarter - 1));
902                 }
903                 
904                 return startYear;
905         }
906         
907         /**
908          * Gets the last year of a given quarter century.
909          * 
910          * @param century The century, specified as a number ending in 00 or 01.
911          *                For centuries A.D., this is the first year of the century. For 
912          *                centuries B.C., this is the last year of the century. For example,
913          *                the "21st century" would be specified as 2001, whereas the "2000's"
914          *                would be specified as 2000. The "2nd century B.C." would be specified
915          *                as 101. The "100's B.C." would be specified as 100.
916          * @param quarter The quarter
917          * @param era     The era of the century. If null, Date.DEFAULT_ERA is assumed.
918          * @return        The last year of the quarter century
919          */
920         public static int getQuarterCenturyEndYear(int century, int quarter, Era era) {
921                 if (era == null) {
922                         era = Date.DEFAULT_ERA;
923                 }
924                 
925                 int endYear;
926                 
927                 if (era == Era.BCE) {
928                         endYear = (century + 99) - (25 * quarter) + 1;
929                 }
930                 else {
931                         endYear = century + (25 * quarter) - 1;
932                 }
933                 
934                 return endYear;
935         }
936         
937         /**
938          * Converts an nth century number to a year. For example, to convert "21st century"
939          * to a year, call nthCenturyToYear(21), which returns 2001. For centuries A.D., the
940          * year returned is the first year of the nth century. For centuries B.C., the
941          * year returned is the last year of the nth century. 
942          * 
943          * @param n The nth century number
944          * @return  The first year in the nth century, for centuries A.D.
945          *          The last year of the nth century, for centuries B.C.
946          */
947         public static int nthCenturyToYear(int n) {
948                 int year = (n-1) * 100 + 1;
949                 
950                 return year;
951         }
952         
953         /**
954          * Gets the Date representing the first day of a given millennium.
955          * 
956          * @param n   The nth millennium number
957          * @param era The era of the millennium. If null, Date.DEFAULT_ERA is assumed.
958          * @return    The first day of the millennium
959          */
960         public static Date getMillenniumStartDate(int n, Era era) {
961                 if (era == null) {
962                         era = Date.DEFAULT_ERA;
963                 }
964
965                 int startYear = getMillenniumStartYear(n, era);
966                 
967                 return new Date(startYear, 1, 1, era);
968         }
969
970         /**
971          * Gets the Date representing the last day of a given millennium.
972          * 
973          * @param n   The nth millennium number
974          * @param era The era of the millennium. If null, Date.DEFAULT_ERA is assumed.
975          * @return    The last day of the millennium
976          */
977         public static Date getMillenniumEndDate(int n, Era era) {
978                 if (era == null) {
979                         era = Date.DEFAULT_ERA;
980                 }
981
982                 int endYear = getMillenniumEndYear(n, era);
983                 
984                 return new Date(endYear, 12, 31, era);
985         }
986         
987         /**
988          * Gets the first year of a given millennium.
989          * 
990          * @param n   The nth millennium number
991          * @param era The era of the millennium. If null, Date.DEFAULT_ERA is assumed.
992          * @return    The first year of the millennium
993          */
994         public static int getMillenniumStartYear(int n, Era era) {
995                 if (era == null) {
996                         era = Date.DEFAULT_ERA;
997                 }
998                 
999                 int year;
1000
1001                 if (era == Era.BCE) {
1002                         year = n * 1000;
1003                 }
1004                 else {
1005                         year = (n - 1) * 1000 + 1;
1006                 }
1007                 
1008                 return year;
1009         }
1010
1011         /**
1012          * Gets the last year of a given millennium.
1013          * 
1014          * @param n   The nth millennium number
1015          * @param era The era of the millennium. If null, Date.DEFAULT_ERA is assumed.
1016          * @return    The last year of the millennium
1017          */
1018         public static int getMillenniumEndYear(int n, Era era) {
1019                 if (era == null) {
1020                         era = Date.DEFAULT_ERA;
1021                 }
1022                 
1023                 int year;
1024
1025                 if (era == Era.BCE) {
1026                         year = (n - 1) * 1000 + 1;
1027                 }
1028                 else {
1029                         year = n * 1000;
1030                 }
1031                 
1032                 return year;
1033         }
1034         
1035         /**
1036          * Calculates the earliest date that may be considered to be "before"
1037          * a given date.
1038          * 
1039          * @param date The date
1040          * @return     The earliest date "before" the date
1041          */
1042         public static Date getEarliestBeforeDate(Date date) {
1043                 return getEarliestBeforeDate(date, null);
1044         }
1045         
1046         /**
1047          * Calculates the latest date that may be considered to be "after"
1048          * a given date.
1049          * 
1050          * @param date The date
1051          * @return     The latest date "after" the date
1052          */
1053         public static Date getLatestAfterDate(Date date) {
1054                 return getLatestAfterDate(date, null);
1055         }
1056         
1057         /**
1058          * Calculates the earliest date that may be considered to be "before"
1059          * a given date range.
1060          * 
1061          * @param startDate The first date in the range
1062          * @param endDate   The last date in the range
1063          * @return          The earliest date "before" the range
1064          */
1065         public static Date getEarliestBeforeDate(Date startDate, Date endDate) {
1066                 // TODO
1067                 // Return an empty date to be used in before date cases
1068                 return new Date();
1069                 
1070                 /*
1071                 // This algorithm is inherited from the XDB fuzzydate parser,
1072                 // which considers "before" to mean "within a lifetime before".
1073
1074                 if (endDate == null) {
1075                         endDate = startDate;
1076                 }
1077                 
1078                 int difference = getYearsBetween(startDate, endDate);
1079                 
1080                 Date earliestDate = startDate.copy();
1081                 subtractYears(earliestDate, 1);
1082                 earliestDate.setMonth(1);
1083                 earliestDate.setDay(1);
1084                 
1085                 if (difference < 100) {
1086                         // The comment from the XDB fuzzydate parser states:
1087                         //
1088                         //    Before/after years are really about birth/death dates
1089                         //    so we use average life-span of 75 years
1090
1091                         subtractYears(earliestDate, 75);
1092                 }
1093                 else {
1094                         // The comment from the XDB fuzzydate parser states:
1095                         //
1096                         //    Before/after years are really about birth/death dates
1097                         //    so we use average life-span of 75 years
1098                         //    but since  the spec was a century, e.g. pre 20th century
1099                         //    we'll make the range a bit bigger
1100                         //    sheesh...
1101
1102                         subtractYears(earliestDate, 175);
1103                 }
1104                 
1105                 return earliestDate;
1106                 */
1107         }
1108         
1109         /**
1110          * Calculates the latest date that may be considered to be "after"
1111          * a given date range. 
1112          * 
1113          * @param startDate The first date in the range
1114          * @param endDate   The last date in the range
1115          * @return          The latest date "after" the range
1116          */
1117         public static Date getLatestAfterDate(Date startDate, Date endDate) {
1118                 Date currentDate = getCurrentDate();
1119                 if (endDate == null) {
1120                         return currentDate;
1121                 }
1122
1123                 MutableDateTime currentDateTime = convertToDateTime(currentDate);
1124                 MutableDateTime endDateTime = convertToDateTime(endDate);
1125                 
1126                 int comparisonResult = currentDateTime.compareTo(endDateTime);
1127                 if (comparisonResult == 1 || comparisonResult == 0) {
1128                         return currentDate;
1129                 }
1130                 return null;
1131         }
1132
1133         public static Date getCurrentDate() {
1134                 LocalDate localDate = new LocalDate();
1135                 Integer year = (Integer) localDate.getYear();
1136                 Integer month = (Integer) localDate.getMonthOfYear();
1137                 Integer dayOfMonth = (Integer) localDate.getDayOfMonth();
1138                 Era era = (localDate.getEra() == DateTimeConstants.BC) ? Era.BCE : Era.CE;
1139                 return new Date(year, month, dayOfMonth, era);
1140         }
1141
1142         public static int getYearsBetween(Date startDate, Date endDate) {
1143                 if (startDate == null || endDate == null) {
1144                         throw new InvalidDateException("date must not be null");
1145                 }
1146                 
1147                 Integer startYear = startDate.getYear();
1148                 Integer endYear = endDate.getYear();
1149                 
1150                 if (startYear == null || endYear == null) {
1151                         throw new IllegalArgumentException("year must not be null");
1152                 }
1153                 
1154                 Era startEra = startDate.getEra();
1155                 Era endEra = endDate.getEra();
1156                 
1157                 if (startEra == null || endEra == null) {
1158                         throw new IllegalArgumentException("era must not be null");
1159                 }
1160                 
1161                 MutableDateTime startDateTime = convertToDateTime(startDate);
1162                 MutableDateTime endDateTime = convertToDateTime(endDate);
1163                 
1164                 int years = Years.yearsBetween(startDateTime, endDateTime).getYears();
1165                 
1166                 return years;
1167         }
1168         
1169         /**
1170          * Calculates the interval, in years, that should be padded around a date so
1171          * that any date within that interval may be considered to be "circa" the
1172          * given date. 
1173          * 
1174          * @param  year The year of the date
1175          * @param  era  The era of the date. If null, Date.DEFAULT_ERA is assumed.
1176          * @return      The number of "circa" years before and after the date
1177          */
1178         public static int getCircaIntervalYears(int year, Era era) {
1179                 /*
1180                  * This algorithm is inherited from the fuzzydate parser
1181                  * in XDB. Its comment states:
1182                  * 
1183                  *   We define circa year/century specifications offsets
1184                  *   as +/- 5% of the difference between that year/century
1185                  *   and the present (2100), so that the farther we go back
1186                  *   in time, the wider the range of meaning of "circa."
1187                  *    
1188                  */
1189                 
1190                 if (era == null) {
1191                         era = Date.DEFAULT_ERA;
1192                 }
1193                 
1194                 MutableDateTime dateTime = new MutableDateTime(chronology);
1195                 dateTime.era().set((era == Era.BCE) ? DateTimeConstants.BC : DateTimeConstants.AD);
1196                 dateTime.yearOfEra().set(year);
1197                 dateTime.monthOfYear().set(1);
1198                 dateTime.dayOfMonth().set(1);
1199                 dateTime.setTime(0, 0, 0, 0);
1200                 
1201                 int years = Years.yearsBetween(dateTime, circaBaseDateTime).getYears();
1202
1203                 return ((int) Math.round(years * 0.05));
1204         }
1205         
1206         /**
1207          * Adds a number of days to a date.
1208          * 
1209          * @param date The date 
1210          * @param days The number of days to add to the date
1211          */
1212         public static void addDays(Date date, int days) {
1213                 MutableDateTime dateTime = convertToDateTime(date);
1214                 
1215                 dateTime.add(Days.days(days));
1216                 
1217                 setFromDateTime(date, dateTime);
1218         }
1219         
1220         /**
1221          * Adds a number of years to a date's year.
1222          * 
1223          * @param date  The date        
1224          * @param years The number of years to add to the date
1225          */
1226         public static void addYears(Date date, int years) {
1227                 MutableDateTime dateTime = convertToDateTime(date);
1228
1229                 dateTime.add(Years.years(years));
1230                 
1231                 setFromDateTime(date, dateTime);
1232         }
1233         
1234         /**
1235          * Subtracts a number of years from a date's year.
1236          * 
1237          * @param date  The date        
1238          * @param years The number of years to subtract from the date
1239          */
1240         public static void subtractYears(Date date, int years) {
1241                 addYears(date, -years);
1242         }
1243         
1244         public static String getEarliestTimestamp(Date date) {
1245                 Era era = date.getEra();
1246                 
1247                 if (era == null) {
1248                         era = Date.DEFAULT_ERA;
1249                 }
1250                 
1251                 MutableDateTime dateTime = null;
1252                 
1253                 try {
1254                         dateTime = convertToDateTime(date);
1255                 }
1256                 catch(IllegalFieldValueException e) {
1257                         throw new InvalidDateException(e.getMessage());
1258                 }
1259                 
1260                 String scalarDate = scalarDateFormatter.print(dateTime);
1261                 
1262                 return scalarDate;
1263         }
1264         
1265         public static String getLatestTimestamp(Date date) {
1266                 Era era = date.getEra();
1267                 
1268                 if (era == null) {
1269                         era = Date.DEFAULT_ERA;
1270                 }
1271                 
1272                 MutableDateTime dateTime = null;
1273                 
1274                 try {
1275                         dateTime = convertToDateTime(date);
1276                 }
1277                 catch(IllegalFieldValueException e) {
1278                         throw new InvalidDateException(e.getMessage());
1279                 }
1280                 
1281                 dateTime.setTime(23, 59, 59, 999);
1282                 
1283                 String scalarDate = scalarDateFormatter.print(dateTime);
1284                 
1285                 return scalarDate;
1286         }
1287         
1288         public static boolean isValidDate(int year, int month, int day, Era era) {
1289                 boolean isValid = true;
1290                 
1291                 try {
1292                         convertToDateTime(new Date(year, month,day, era));
1293                 }
1294                 catch(IllegalFieldValueException e) {
1295                         isValid = false;
1296                 }
1297                 
1298                 return isValid;
1299         }
1300         
1301         /**
1302          * Converts a Date to a joda-time DateTime.
1303          * 
1304          * @param  date The Date
1305          * @return      A MutableDateTime representing the same date
1306          */
1307         private static MutableDateTime convertToDateTime(Date date) {
1308                 Era era = date.getEra();
1309                 
1310                 if (era == null) {
1311                         era = Date.DEFAULT_ERA;
1312                 }
1313
1314                 MutableDateTime dateTime = new MutableDateTime(chronology);
1315                 dateTime.era().set((era == Era.BCE) ? DateTimeConstants.BC : DateTimeConstants.AD);
1316                 dateTime.yearOfEra().set(date.getYear());
1317                 dateTime.monthOfYear().set(date.getMonth());
1318                 dateTime.dayOfMonth().set(date.getDay());
1319                 dateTime.setTime(0, 0, 0, 0);
1320
1321                 return dateTime;
1322         }
1323         
1324         /**
1325          * Sets the fields in a Date so that it represents the same date
1326          * as a given DateTime.
1327          * 
1328          * @param date     The Date to set
1329          * @param dateTime A MutableDateTime representing the desired date
1330          */
1331         private static void setFromDateTime(Date date, MutableDateTime dateTime) {
1332                 date.setYear(dateTime.getYearOfEra());
1333                 date.setMonth(dateTime.getMonthOfYear());
1334                 date.setDay(dateTime.getDayOfMonth());
1335                 date.setEra((dateTime.getEra() == DateTimeConstants.BC) ? Era.BCE : Era.CE);
1336         }
1337 }