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