001: /*
002: * Copyright 2001-2005 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.chrono;
017:
018: import java.util.Locale;
019:
020: import org.joda.time.Chronology;
021: import org.joda.time.DateTimeConstants;
022: import org.joda.time.DateTimeField;
023: import org.joda.time.DateTimeFieldType;
024: import org.joda.time.DateTimeZone;
025: import org.joda.time.DurationField;
026: import org.joda.time.DurationFieldType;
027: import org.joda.time.field.DividedDateTimeField;
028: import org.joda.time.field.FieldUtils;
029: import org.joda.time.field.MillisDurationField;
030: import org.joda.time.field.ZeroIsMaxDateTimeField;
031: import org.joda.time.field.OffsetDateTimeField;
032: import org.joda.time.field.PreciseDateTimeField;
033: import org.joda.time.field.PreciseDurationField;
034: import org.joda.time.field.RemainderDateTimeField;
035:
036: /**
037: * Abstract implementation for calendar systems that use a typical
038: * day/month/year/leapYear model.
039: * Most of the utility methods required by subclasses are package-private,
040: * reflecting the intention that they be defined in the same package.
041: * <p>
042: * BasicChronology is thread-safe and immutable, and all subclasses must
043: * be as well.
044: *
045: * @author Stephen Colebourne
046: * @author Brian S O'Neill
047: * @author Guy Allard
048: * @since 1.2, renamed from BaseGJChronology
049: */
050: abstract class BasicChronology extends AssembledChronology {
051:
052: /** Serialization lock */
053: private static final long serialVersionUID = 8283225332206808863L;
054:
055: private static final DurationField cMillisField;
056: private static final DurationField cSecondsField;
057: private static final DurationField cMinutesField;
058: private static final DurationField cHoursField;
059: private static final DurationField cHalfdaysField;
060: private static final DurationField cDaysField;
061: private static final DurationField cWeeksField;
062:
063: private static final DateTimeField cMillisOfSecondField;
064: private static final DateTimeField cMillisOfDayField;
065: private static final DateTimeField cSecondOfMinuteField;
066: private static final DateTimeField cSecondOfDayField;
067: private static final DateTimeField cMinuteOfHourField;
068: private static final DateTimeField cMinuteOfDayField;
069: private static final DateTimeField cHourOfDayField;
070: private static final DateTimeField cHourOfHalfdayField;
071: private static final DateTimeField cClockhourOfDayField;
072: private static final DateTimeField cClockhourOfHalfdayField;
073: private static final DateTimeField cHalfdayOfDayField;
074:
075: static {
076: cMillisField = MillisDurationField.INSTANCE;
077: cSecondsField = new PreciseDurationField(DurationFieldType
078: .seconds(), DateTimeConstants.MILLIS_PER_SECOND);
079: cMinutesField = new PreciseDurationField(DurationFieldType
080: .minutes(), DateTimeConstants.MILLIS_PER_MINUTE);
081: cHoursField = new PreciseDurationField(DurationFieldType
082: .hours(), DateTimeConstants.MILLIS_PER_HOUR);
083: cHalfdaysField = new PreciseDurationField(DurationFieldType
084: .halfdays(), DateTimeConstants.MILLIS_PER_DAY / 2);
085: cDaysField = new PreciseDurationField(DurationFieldType.days(),
086: DateTimeConstants.MILLIS_PER_DAY);
087: cWeeksField = new PreciseDurationField(DurationFieldType
088: .weeks(), DateTimeConstants.MILLIS_PER_WEEK);
089:
090: cMillisOfSecondField = new PreciseDateTimeField(
091: DateTimeFieldType.millisOfSecond(), cMillisField,
092: cSecondsField);
093:
094: cMillisOfDayField = new PreciseDateTimeField(DateTimeFieldType
095: .millisOfDay(), cMillisField, cDaysField);
096:
097: cSecondOfMinuteField = new PreciseDateTimeField(
098: DateTimeFieldType.secondOfMinute(), cSecondsField,
099: cMinutesField);
100:
101: cSecondOfDayField = new PreciseDateTimeField(DateTimeFieldType
102: .secondOfDay(), cSecondsField, cDaysField);
103:
104: cMinuteOfHourField = new PreciseDateTimeField(DateTimeFieldType
105: .minuteOfHour(), cMinutesField, cHoursField);
106:
107: cMinuteOfDayField = new PreciseDateTimeField(DateTimeFieldType
108: .minuteOfDay(), cMinutesField, cDaysField);
109:
110: cHourOfDayField = new PreciseDateTimeField(DateTimeFieldType
111: .hourOfDay(), cHoursField, cDaysField);
112:
113: cHourOfHalfdayField = new PreciseDateTimeField(
114: DateTimeFieldType.hourOfHalfday(), cHoursField,
115: cHalfdaysField);
116:
117: cClockhourOfDayField = new ZeroIsMaxDateTimeField(
118: cHourOfDayField, DateTimeFieldType.clockhourOfDay());
119:
120: cClockhourOfHalfdayField = new ZeroIsMaxDateTimeField(
121: cHourOfHalfdayField, DateTimeFieldType
122: .clockhourOfHalfday());
123:
124: cHalfdayOfDayField = new HalfdayField();
125: }
126:
127: private static final int CACHE_SIZE = 1 << 10;
128: private static final int CACHE_MASK = CACHE_SIZE - 1;
129:
130: private transient final YearInfo[] iYearInfoCache = new YearInfo[CACHE_SIZE];
131:
132: private final int iMinDaysInFirstWeek;
133:
134: BasicChronology(Chronology base, Object param,
135: int minDaysInFirstWeek) {
136: super (base, param);
137:
138: if (minDaysInFirstWeek < 1 || minDaysInFirstWeek > 7) {
139: throw new IllegalArgumentException(
140: "Invalid min days in first week: "
141: + minDaysInFirstWeek);
142: }
143:
144: iMinDaysInFirstWeek = minDaysInFirstWeek;
145: }
146:
147: public DateTimeZone getZone() {
148: Chronology base;
149: if ((base = getBase()) != null) {
150: return base.getZone();
151: }
152: return DateTimeZone.UTC;
153: }
154:
155: public long getDateTimeMillis(int year, int monthOfYear,
156: int dayOfMonth, int millisOfDay)
157: throws IllegalArgumentException {
158: Chronology base;
159: if ((base = getBase()) != null) {
160: return base.getDateTimeMillis(year, monthOfYear,
161: dayOfMonth, millisOfDay);
162: }
163:
164: FieldUtils.verifyValueBounds(DateTimeFieldType.millisOfDay(),
165: millisOfDay, 0, DateTimeConstants.MILLIS_PER_DAY);
166: return getDateMidnightMillis(year, monthOfYear, dayOfMonth)
167: + millisOfDay;
168: }
169:
170: public long getDateTimeMillis(int year, int monthOfYear,
171: int dayOfMonth, int hourOfDay, int minuteOfHour,
172: int secondOfMinute, int millisOfSecond)
173: throws IllegalArgumentException {
174: Chronology base;
175: if ((base = getBase()) != null) {
176: return base.getDateTimeMillis(year, monthOfYear,
177: dayOfMonth, hourOfDay, minuteOfHour,
178: secondOfMinute, millisOfSecond);
179: }
180:
181: FieldUtils.verifyValueBounds(DateTimeFieldType.hourOfDay(),
182: hourOfDay, 0, 23);
183: FieldUtils.verifyValueBounds(DateTimeFieldType.minuteOfHour(),
184: minuteOfHour, 0, 59);
185: FieldUtils.verifyValueBounds(
186: DateTimeFieldType.secondOfMinute(), secondOfMinute, 0,
187: 59);
188: FieldUtils.verifyValueBounds(
189: DateTimeFieldType.millisOfSecond(), millisOfSecond, 0,
190: 999);
191:
192: return getDateMidnightMillis(year, monthOfYear, dayOfMonth)
193: + hourOfDay * DateTimeConstants.MILLIS_PER_HOUR
194: + minuteOfHour * DateTimeConstants.MILLIS_PER_MINUTE
195: + secondOfMinute * DateTimeConstants.MILLIS_PER_SECOND
196: + millisOfSecond;
197: }
198:
199: public int getMinimumDaysInFirstWeek() {
200: return iMinDaysInFirstWeek;
201: }
202:
203: // Output
204: //-----------------------------------------------------------------------
205: /**
206: * Gets a debugging toString.
207: *
208: * @return a debugging string
209: */
210: public String toString() {
211: StringBuffer sb = new StringBuffer(60);
212: String name = getClass().getName();
213: int index = name.lastIndexOf('.');
214: if (index >= 0) {
215: name = name.substring(index + 1);
216: }
217: sb.append(name);
218: sb.append('[');
219: DateTimeZone zone = getZone();
220: if (zone != null) {
221: sb.append(zone.getID());
222: }
223: if (getMinimumDaysInFirstWeek() != 4) {
224: sb.append(",mdfw=");
225: sb.append(getMinimumDaysInFirstWeek());
226: }
227: sb.append(']');
228: return sb.toString();
229: }
230:
231: protected void assemble(Fields fields) {
232: // First copy fields that are the same for all Gregorian and Julian
233: // chronologies.
234:
235: fields.millis = cMillisField;
236: fields.seconds = cSecondsField;
237: fields.minutes = cMinutesField;
238: fields.hours = cHoursField;
239: fields.halfdays = cHalfdaysField;
240: fields.days = cDaysField;
241: fields.weeks = cWeeksField;
242:
243: fields.millisOfSecond = cMillisOfSecondField;
244: fields.millisOfDay = cMillisOfDayField;
245: fields.secondOfMinute = cSecondOfMinuteField;
246: fields.secondOfDay = cSecondOfDayField;
247: fields.minuteOfHour = cMinuteOfHourField;
248: fields.minuteOfDay = cMinuteOfDayField;
249: fields.hourOfDay = cHourOfDayField;
250: fields.hourOfHalfday = cHourOfHalfdayField;
251: fields.clockhourOfDay = cClockhourOfDayField;
252: fields.clockhourOfHalfday = cClockhourOfHalfdayField;
253: fields.halfdayOfDay = cHalfdayOfDayField;
254:
255: // Now create fields that have unique behavior for Gregorian and Julian
256: // chronologies.
257:
258: fields.year = new BasicYearDateTimeField(this );
259: fields.yearOfEra = new GJYearOfEraDateTimeField(fields.year,
260: this );
261:
262: // Define one-based centuryOfEra and yearOfCentury.
263: DateTimeField field = new OffsetDateTimeField(fields.yearOfEra,
264: 99);
265: fields.centuryOfEra = new DividedDateTimeField(field,
266: DateTimeFieldType.centuryOfEra(), 100);
267:
268: field = new RemainderDateTimeField(
269: (DividedDateTimeField) fields.centuryOfEra);
270: fields.yearOfCentury = new OffsetDateTimeField(field,
271: DateTimeFieldType.yearOfCentury(), 1);
272:
273: fields.era = new GJEraDateTimeField(this );
274: fields.dayOfWeek = new GJDayOfWeekDateTimeField(this ,
275: fields.days);
276: fields.dayOfMonth = new BasicDayOfMonthDateTimeField(this ,
277: fields.days);
278: fields.dayOfYear = new BasicDayOfYearDateTimeField(this ,
279: fields.days);
280: fields.monthOfYear = new GJMonthOfYearDateTimeField(this );
281: fields.weekyear = new BasicWeekyearDateTimeField(this );
282: fields.weekOfWeekyear = new BasicWeekOfWeekyearDateTimeField(
283: this , fields.weeks);
284:
285: field = new RemainderDateTimeField(fields.weekyear,
286: DateTimeFieldType.weekyearOfCentury(), 100);
287: fields.weekyearOfCentury = new OffsetDateTimeField(field,
288: DateTimeFieldType.weekyearOfCentury(), 1);
289:
290: // The remaining (imprecise) durations are available from the newly
291: // created datetime fields.
292:
293: fields.years = fields.year.getDurationField();
294: fields.centuries = fields.centuryOfEra.getDurationField();
295: fields.months = fields.monthOfYear.getDurationField();
296: fields.weekyears = fields.weekyear.getDurationField();
297: }
298:
299: //-----------------------------------------------------------------------
300: /**
301: * Get the number of days in the year.
302: *
303: * @return 366
304: */
305: int getDaysInYearMax() {
306: return 366;
307: }
308:
309: /**
310: * Get the number of days in the year.
311: *
312: * @param year the year to use
313: * @return 366 if a leap year, otherwise 365
314: */
315: int getDaysInYear(int year) {
316: return isLeapYear(year) ? 366 : 365;
317: }
318:
319: /**
320: * Get the number of weeks in the year.
321: *
322: * @param year the year to use
323: * @return number of weeks in the year
324: */
325: int getWeeksInYear(int year) {
326: long firstWeekMillis1 = getFirstWeekOfYearMillis(year);
327: long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1);
328: return (int) ((firstWeekMillis2 - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK);
329: }
330:
331: /**
332: * Get the millis for the first week of a year.
333: *
334: * @param year the year to use
335: * @return millis
336: */
337: long getFirstWeekOfYearMillis(int year) {
338: long jan1millis = getYearMillis(year);
339: int jan1dayOfWeek = getDayOfWeek(jan1millis);
340:
341: if (jan1dayOfWeek > (8 - iMinDaysInFirstWeek)) {
342: // First week is end of previous year because it doesn't have enough days.
343: return jan1millis + (8 - jan1dayOfWeek)
344: * (long) DateTimeConstants.MILLIS_PER_DAY;
345: } else {
346: // First week is start of this year because it has enough days.
347: return jan1millis - (jan1dayOfWeek - 1)
348: * (long) DateTimeConstants.MILLIS_PER_DAY;
349: }
350: }
351:
352: /**
353: * Get the milliseconds for the start of a year.
354: *
355: * @param year The year to use.
356: * @return millis from 1970-01-01T00:00:00Z
357: */
358: long getYearMillis(int year) {
359: return getYearInfo(year).iFirstDayMillis;
360: }
361:
362: /**
363: * Get the milliseconds for the start of a month.
364: *
365: * @param year The year to use.
366: * @param month The month to use
367: * @return millis from 1970-01-01T00:00:00Z
368: */
369: long getYearMonthMillis(int year, int month) {
370: long millis = getYearMillis(year);
371: millis += getTotalMillisByYearMonth(year, month);
372: return millis;
373: }
374:
375: /**
376: * Get the milliseconds for a particular date.
377: *
378: * @param year The year to use.
379: * @param month The month to use
380: * @param dayOfMonth The day of the month to use
381: * @return millis from 1970-01-01T00:00:00Z
382: */
383: long getYearMonthDayMillis(int year, int month, int dayOfMonth) {
384: long millis = getYearMillis(year);
385: millis += getTotalMillisByYearMonth(year, month);
386: return millis + (dayOfMonth - 1)
387: * (long) DateTimeConstants.MILLIS_PER_DAY;
388: }
389:
390: /**
391: * @param instant millis from 1970-01-01T00:00:00Z
392: */
393: int getYear(long instant) {
394: // Get an initial estimate of the year, and the millis value that
395: // represents the start of that year. Then verify estimate and fix if
396: // necessary.
397:
398: // Initial estimate uses values divided by two to avoid overflow.
399: long unitMillis = getAverageMillisPerYearDividedByTwo();
400: long i2 = (instant >> 1) + getApproxMillisAtEpochDividedByTwo();
401: if (i2 < 0) {
402: i2 = i2 - unitMillis + 1;
403: }
404: int year = (int) (i2 / unitMillis);
405:
406: long yearStart = getYearMillis(year);
407: long diff = instant - yearStart;
408:
409: if (diff < 0) {
410: year--;
411: } else if (diff >= DateTimeConstants.MILLIS_PER_DAY * 365L) {
412: // One year may need to be added to fix estimate.
413: long oneYear;
414: if (isLeapYear(year)) {
415: oneYear = DateTimeConstants.MILLIS_PER_DAY * 366L;
416: } else {
417: oneYear = DateTimeConstants.MILLIS_PER_DAY * 365L;
418: }
419:
420: yearStart += oneYear;
421:
422: if (yearStart <= instant) {
423: // Didn't go too far, so actually add one year.
424: year++;
425: }
426: }
427:
428: return year;
429: }
430:
431: /**
432: * @param millis from 1970-01-01T00:00:00Z
433: */
434: int getMonthOfYear(long millis) {
435: return getMonthOfYear(millis, getYear(millis));
436: }
437:
438: /**
439: * @param millis from 1970-01-01T00:00:00Z
440: * @param year precalculated year of millis
441: */
442: abstract int getMonthOfYear(long millis, int year);
443:
444: /**
445: * @param millis from 1970-01-01T00:00:00Z
446: */
447: int getDayOfMonth(long millis) {
448: int year = getYear(millis);
449: int month = getMonthOfYear(millis, year);
450: return getDayOfMonth(millis, year, month);
451: }
452:
453: /**
454: * @param millis from 1970-01-01T00:00:00Z
455: * @param year precalculated year of millis
456: */
457: int getDayOfMonth(long millis, int year) {
458: int month = getMonthOfYear(millis, year);
459: return getDayOfMonth(millis, year, month);
460: }
461:
462: /**
463: * @param millis from 1970-01-01T00:00:00Z
464: * @param year precalculated year of millis
465: * @param month precalculated month of millis
466: */
467: int getDayOfMonth(long millis, int year, int month) {
468: long dateMillis = getYearMillis(year);
469: dateMillis += getTotalMillisByYearMonth(year, month);
470: return (int) ((millis - dateMillis) / DateTimeConstants.MILLIS_PER_DAY) + 1;
471: }
472:
473: /**
474: * @param instant millis from 1970-01-01T00:00:00Z
475: */
476: int getDayOfYear(long instant) {
477: return getDayOfYear(instant, getYear(instant));
478: }
479:
480: /**
481: * @param instant millis from 1970-01-01T00:00:00Z
482: * @param year precalculated year of millis
483: */
484: int getDayOfYear(long instant, int year) {
485: long yearStart = getYearMillis(year);
486: return (int) ((instant - yearStart) / DateTimeConstants.MILLIS_PER_DAY) + 1;
487: }
488:
489: /**
490: * @param instant millis from 1970-01-01T00:00:00Z
491: */
492: int getWeekyear(long instant) {
493: int year = getYear(instant);
494: int week = getWeekOfWeekyear(instant, year);
495: if (week == 1) {
496: return getYear(instant + DateTimeConstants.MILLIS_PER_WEEK);
497: } else if (week > 51) {
498: return getYear(instant
499: - (2 * DateTimeConstants.MILLIS_PER_WEEK));
500: } else {
501: return year;
502: }
503: }
504:
505: /**
506: * @param instant millis from 1970-01-01T00:00:00Z
507: */
508: int getWeekOfWeekyear(long instant) {
509: return getWeekOfWeekyear(instant, getYear(instant));
510: }
511:
512: /**
513: * @param instant millis from 1970-01-01T00:00:00Z
514: * @param year precalculated year of millis
515: */
516: int getWeekOfWeekyear(long instant, int year) {
517: long firstWeekMillis1 = getFirstWeekOfYearMillis(year);
518: if (instant < firstWeekMillis1) {
519: return getWeeksInYear(year - 1);
520: }
521: long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1);
522: if (instant >= firstWeekMillis2) {
523: return 1;
524: }
525: return (int) ((instant - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK) + 1;
526: }
527:
528: /**
529: * @param instant millis from 1970-01-01T00:00:00Z
530: */
531: int getDayOfWeek(long instant) {
532: // 1970-01-01 is day of week 4, Thursday.
533:
534: long daysSince19700101;
535: if (instant >= 0) {
536: daysSince19700101 = instant
537: / DateTimeConstants.MILLIS_PER_DAY;
538: } else {
539: daysSince19700101 = (instant - (DateTimeConstants.MILLIS_PER_DAY - 1))
540: / DateTimeConstants.MILLIS_PER_DAY;
541: if (daysSince19700101 < -3) {
542: return 7 + (int) ((daysSince19700101 + 4) % 7);
543: }
544: }
545:
546: return 1 + (int) ((daysSince19700101 + 3) % 7);
547: }
548:
549: /**
550: * @param instant millis from 1970-01-01T00:00:00Z
551: */
552: int getMillisOfDay(long instant) {
553: if (instant >= 0) {
554: return (int) (instant % DateTimeConstants.MILLIS_PER_DAY);
555: } else {
556: return (DateTimeConstants.MILLIS_PER_DAY - 1)
557: + (int) ((instant + 1) % DateTimeConstants.MILLIS_PER_DAY);
558: }
559: }
560:
561: /**
562: * Gets the maximum number of days in any month.
563: *
564: * @return 31
565: */
566: int getDaysInMonthMax() {
567: return 31;
568: }
569:
570: /**
571: * Gets the maximum number of days in the month specified by the instant.
572: *
573: * @param instant millis from 1970-01-01T00:00:00Z
574: * @return the maximum number of days in the month
575: */
576: int getDaysInMonthMax(long instant) {
577: int this Year = getYear(instant);
578: int this Month = getMonthOfYear(instant, this Year);
579: return getDaysInYearMonth(this Year, this Month);
580: }
581:
582: /**
583: * Gets the maximum number of days in the month specified by the instant.
584: * The value represents what the user is trying to set, and can be
585: * used to optimise this method.
586: *
587: * @param instant millis from 1970-01-01T00:00:00Z
588: * @param value the value being set
589: * @return the maximum number of days in the month
590: */
591: int getDaysInMonthMaxForSet(long instant, int value) {
592: return getDaysInMonthMax(instant);
593: }
594:
595: //-----------------------------------------------------------------------
596: /**
597: * Gets the milliseconds for a date at midnight.
598: *
599: * @param year the year
600: * @param monthOfYear the month
601: * @param dayOfMonth the day
602: * @return the milliseconds
603: */
604: long getDateMidnightMillis(int year, int monthOfYear, int dayOfMonth) {
605: FieldUtils.verifyValueBounds(DateTimeFieldType.year(), year,
606: getMinYear(), getMaxYear());
607: FieldUtils.verifyValueBounds(DateTimeFieldType.monthOfYear(),
608: monthOfYear, 1, getMaxMonth(year));
609: FieldUtils.verifyValueBounds(DateTimeFieldType.dayOfMonth(),
610: dayOfMonth, 1, getDaysInYearMonth(year, monthOfYear));
611: return getYearMonthDayMillis(year, monthOfYear, dayOfMonth);
612: }
613:
614: /**
615: * Gets the difference between the two instants in years.
616: *
617: * @param minuendInstant the first instant
618: * @param subtrahendInstant the second instant
619: * @return the difference
620: */
621: abstract long getYearDifference(long minuendInstant,
622: long subtrahendInstant);
623:
624: /**
625: * Is the specified year a leap year?
626: *
627: * @param year the year to test
628: * @return true if leap
629: */
630: abstract boolean isLeapYear(int year);
631:
632: /**
633: * Gets the number of days in the specified month and year.
634: *
635: * @param year the year
636: * @param month the month
637: * @return the number of days
638: */
639: abstract int getDaysInYearMonth(int year, int month);
640:
641: /**
642: * Gets the maximum days in the specified month.
643: *
644: * @param month the month
645: * @return the max days
646: */
647: abstract int getDaysInMonthMax(int month);
648:
649: /**
650: * Gets the total number of millis elapsed in this year at the start
651: * of the specified month, such as zero for month 1.
652: *
653: * @param year the year
654: * @param month the month
655: * @return the elapsed millis at the start of the month
656: */
657: abstract long getTotalMillisByYearMonth(int year, int month);
658:
659: /**
660: * Gets the millisecond value of the first day of the year.
661: *
662: * @return the milliseconds for the first of the year
663: */
664: abstract long calculateFirstDayOfYearMillis(int year);
665:
666: /**
667: * Gets the minimum supported year.
668: *
669: * @return the year
670: */
671: abstract int getMinYear();
672:
673: /**
674: * Gets the maximum supported year.
675: *
676: * @return the year
677: */
678: abstract int getMaxYear();
679:
680: /**
681: * Gets the maximum month for the specified year.
682: * This implementation calls getMaxMonth().
683: *
684: * @param year the year
685: * @return the maximum month value
686: */
687: int getMaxMonth(int year) {
688: return getMaxMonth();
689: }
690:
691: /**
692: * Gets the maximum number of months.
693: *
694: * @return 12
695: */
696: int getMaxMonth() {
697: return 12;
698: }
699:
700: /**
701: * Gets an average value for the milliseconds per year.
702: *
703: * @return the millis per year
704: */
705: abstract long getAverageMillisPerYear();
706:
707: /**
708: * Gets an average value for the milliseconds per year, divided by two.
709: *
710: * @return the millis per year divided by two
711: */
712: abstract long getAverageMillisPerYearDividedByTwo();
713:
714: /**
715: * Gets an average value for the milliseconds per month.
716: *
717: * @return the millis per month
718: */
719: abstract long getAverageMillisPerMonth();
720:
721: /**
722: * Returns a constant representing the approximate number of milliseconds
723: * elapsed from year 0 of this chronology, divided by two. This constant
724: * <em>must</em> be defined as:
725: * <pre>
726: * (yearAtEpoch * averageMillisPerYear + millisOfYearAtEpoch) / 2
727: * </pre>
728: * where epoch is 1970-01-01 (Gregorian).
729: */
730: abstract long getApproxMillisAtEpochDividedByTwo();
731:
732: /**
733: * Sets the year from an instant and year.
734: *
735: * @param instant millis from 1970-01-01T00:00:00Z
736: * @param year the year to set
737: * @return the updated millis
738: */
739: abstract long setYear(long instant, int year);
740:
741: //-----------------------------------------------------------------------
742: // Although accessed by multiple threads, this method doesn't need to be synchronized.
743: private YearInfo getYearInfo(int year) {
744: YearInfo info = iYearInfoCache[year & CACHE_MASK];
745: if (info == null || info.iYear != year) {
746: info = new YearInfo(year,
747: calculateFirstDayOfYearMillis(year));
748: iYearInfoCache[year & CACHE_MASK] = info;
749: }
750: return info;
751: }
752:
753: private static class HalfdayField extends PreciseDateTimeField {
754: private static final long serialVersionUID = 581601443656929254L;
755:
756: HalfdayField() {
757: super (DateTimeFieldType.halfdayOfDay(), cHalfdaysField,
758: cDaysField);
759: }
760:
761: public String getAsText(int fieldValue, Locale locale) {
762: return GJLocaleSymbols.forLocale(locale)
763: .halfdayValueToText(fieldValue);
764: }
765:
766: public long set(long millis, String text, Locale locale) {
767: return set(millis, GJLocaleSymbols.forLocale(locale)
768: .halfdayTextToValue(text));
769: }
770:
771: public int getMaximumTextLength(Locale locale) {
772: return GJLocaleSymbols.forLocale(locale)
773: .getHalfdayMaxTextLength();
774: }
775: }
776:
777: private static class YearInfo {
778: public final int iYear;
779: public final long iFirstDayMillis;
780:
781: YearInfo(int year, long firstDayMillis) {
782: iYear = year;
783: iFirstDayMillis = firstDayMillis;
784: }
785: }
786:
787: }
|