001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.cldc.util.j2me;
028:
029: import java.util.*;
030: import java.io.*;
031:
032: /**
033: * This class is an implementation of the subsetted
034: * CLDC 1.1 Calendar class.
035: *
036: * @see java.util.Calendar
037: * @see java.util.TimeZone
038: */
039: public class CalendarImpl extends Calendar {
040:
041: /* ERA */
042: private static final int BC = 0;
043: private static final int AD = 1;
044:
045: /* January 1, year 1 (Gregorian) */
046: private static final int JAN_1_1_JULIAN_DAY = 1721426;
047:
048: /* January 1, 1970 (Gregorian) */
049: private static final int EPOCH_JULIAN_DAY = 2440588;
050:
051: /* 0-based, for day-in-year */
052: private static final int NUM_DAYS[] = { 0, 31, 59, 90, 120, 151,
053: 181, 212, 243, 273, 304, 334 };
054:
055: /* 0-based, for day-in-year */
056: private static final int LEAP_NUM_DAYS[] = { 0, 31, 60, 91, 121,
057: 152, 182, 213, 244, 274, 305, 335 };
058:
059: /**
060: * Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit
061: * into ints, they must be longs in order to prevent arithmetic overflow
062: * when performing (CR 4173516).
063: */
064: private static final int ONE_SECOND = 1000;
065: private static final int ONE_MINUTE = 60 * ONE_SECOND;
066: private static final int ONE_HOUR = 60 * ONE_MINUTE;
067: private static final long ONE_DAY = 24 * ONE_HOUR;
068:
069: /**
070: * The point at which the Gregorian calendar rules are used, measured in
071: * milliseconds from the standard epoch. Default is October 15, 1582
072: * (Gregorian) 00:00:00 UTC or -12219292800000L. For this value, October 4,
073: * 1582 (Julian) is followed by October 15, 1582 (Gregorian). This
074: * corresponds to Julian day number 2299161.
075: */
076: private static final long gregorianCutover = -12219292800000L;
077:
078: /**
079: * The year of the gregorianCutover, with 0 representing
080: * 1 BC, -1 representing 2 BC, etc.
081: */
082: private static final int gregorianCutoverYear = 1582;
083:
084: public CalendarImpl() {
085: super ();
086: }
087:
088: /**
089: * Converts UTC as milliseconds to time field values.
090: */
091: protected void computeFields() {
092: int rawOffset = getTimeZone().getRawOffset();
093: long localMillis = time + rawOffset;
094:
095: // Check for very extreme values -- millis near Long.MIN_VALUE or
096: // Long.MAX_VALUE. For these values, adding the zone offset can push
097: // the millis past MAX_VALUE to MIN_VALUE, or vice versa. This produces
098: // the undesirable effect that the time can wrap around at the ends,
099: // yielding, for example, a Date(Long.MAX_VALUE) with a big BC year
100: // (should be AD). Handle this by pinning such values to Long.MIN_VALUE
101: // or Long.MAX_VALUE. - liu 8/11/98 CR 4149677
102: if (time > 0 && localMillis < 0 && rawOffset > 0) {
103: localMillis = Long.MAX_VALUE;
104: } else if (time < 0 && localMillis > 0 && rawOffset < 0) {
105: localMillis = Long.MIN_VALUE;
106: }
107:
108: // Time to fields takes the wall millis (Standard or DST).
109: timeToFields(localMillis);
110:
111: long days = (long) (localMillis / ONE_DAY);
112: int millisInDay = (int) (localMillis - (days * ONE_DAY));
113:
114: if (millisInDay < 0)
115: millisInDay += ONE_DAY;
116:
117: // Call getOffset() to get the TimeZone offset.
118: // The millisInDay value must be standard local millis.
119: int dstOffset = getTimeZone().getOffset(AD, this .fields[YEAR],
120: this .fields[MONTH], this .fields[DATE],
121: this .fields[DAY_OF_WEEK], millisInDay)
122: - rawOffset;
123:
124: // Adjust our millisInDay for DST, if necessary.
125: millisInDay += dstOffset;
126:
127: // If DST has pushed us into the next day,
128: // we must call timeToFields() again.
129: // This happens in DST between 12:00 am and 1:00 am every day.
130: // The call to timeToFields() will give the wrong day,
131: // since the Standard time is in the previous day
132: if (millisInDay >= ONE_DAY) {
133: long dstMillis = localMillis + dstOffset;
134: millisInDay -= ONE_DAY;
135: // As above, check for and pin extreme values
136: if (localMillis > 0 && dstMillis < 0 && dstOffset > 0) {
137: dstMillis = Long.MAX_VALUE;
138: } else if (localMillis < 0 && dstMillis > 0
139: && dstOffset < 0) {
140: dstMillis = Long.MIN_VALUE;
141: }
142: timeToFields(dstMillis);
143: }
144:
145: // Fill in all time-related fields based on millisInDay.
146: // so as not to perturb flags.
147: this .fields[MILLISECOND] = millisInDay % 1000;
148: millisInDay /= 1000;
149:
150: this .fields[SECOND] = millisInDay % 60;
151: millisInDay /= 60;
152:
153: this .fields[MINUTE] = millisInDay % 60;
154: millisInDay /= 60;
155:
156: this .fields[HOUR_OF_DAY] = millisInDay;
157: this .fields[AM_PM] = millisInDay / 12;
158: this .fields[HOUR] = millisInDay % 12;
159: }
160:
161: /**
162: * Convert the time as milliseconds to the date fields. Millis must be
163: * given as local wall millis to get the correct local day. For example,
164: * if it is 11:30 pm Standard, and DST is in effect, the correct DST millis
165: * must be passed in to get the right date.
166: * <p>
167: * Fields that are completed by this method: YEAR, MONTH, DATE, DAY_OF_WEEK.
168: * @param theTime the time in wall millis (either Standard or DST),
169: * whichever is in effect
170: */
171: private final void timeToFields(long theTime) {
172: int dayOfYear, weekCount, rawYear;
173: boolean isLeap;
174:
175: // Compute the year, month, and day of month from the given millis
176: if (theTime >= gregorianCutover) {
177:
178: // The Gregorian epoch day is zero for Monday January 1, year 1.
179: long gregorianEpochDay = millisToJulianDay(theTime)
180: - JAN_1_1_JULIAN_DAY;
181:
182: // Here we convert from the day number to the multiple radix
183: // representation. We use 400-year, 100-year, and 4-year cycles.
184: // For example, the 4-year cycle has 4 years + 1 leap day; giving
185: // 1461 == 365*4 + 1 days.
186: int[] rem = new int[1];
187:
188: // 400-year cycle length
189: int n400 = floorDivide(gregorianEpochDay, 146097, rem);
190:
191: // 100-year cycle length
192: int n100 = floorDivide(rem[0], 36524, rem);
193:
194: // 4-year cycle length
195: int n4 = floorDivide(rem[0], 1461, rem);
196:
197: int n1 = floorDivide(rem[0], 365, rem);
198: rawYear = 400 * n400 + 100 * n100 + 4 * n4 + n1;
199:
200: // zero-based day of year
201: dayOfYear = rem[0];
202:
203: // Dec 31 at end of 4- or 400-yr cycle
204: if (n100 == 4 || n1 == 4) {
205: dayOfYear = 365;
206: } else {
207: ++rawYear;
208: }
209:
210: // equiv. to (rawYear%4 == 0)
211: isLeap = ((rawYear & 0x3) == 0)
212: && (rawYear % 100 != 0 || rawYear % 400 == 0);
213:
214: // Gregorian day zero is a Monday
215: this .fields[DAY_OF_WEEK] = (int) ((gregorianEpochDay + 1) % 7);
216: } else {
217: // The Julian epoch day (not the same as Julian Day)
218: // is zero on Saturday December 30, 0 (Gregorian).
219: long julianEpochDay = millisToJulianDay(theTime)
220: - (JAN_1_1_JULIAN_DAY - 2);
221:
222: rawYear = (int) floorDivide(4 * julianEpochDay + 1464, 1461);
223:
224: // Compute the Julian calendar day number for January 1, year
225: long january1 = 365 * (rawYear - 1)
226: + floorDivide(rawYear - 1, 4);
227: dayOfYear = (int) (julianEpochDay - january1); // 0-based
228:
229: // Julian leap years occurred historically every 4 years starting
230: // with 8 AD. Before 8 AD the spacing is irregular; every 3 years
231: // from 45 BC to 9 BC, and then none until 8 AD. However, we don't
232: // implement this historical detail; instead, we implement the
233: // computationally cleaner proleptic calendar, which assumes
234: // consistent 4-year cycles throughout time.
235:
236: // equiv. to (rawYear%4 == 0)
237: isLeap = ((rawYear & 0x3) == 0);
238:
239: // Julian calendar day zero is a Saturday
240: this .fields[DAY_OF_WEEK] = (int) ((julianEpochDay - 1) % 7);
241: }
242:
243: // Common Julian/Gregorian calculation
244: int correction = 0;
245:
246: // zero-based DOY for March 1
247: int march1 = isLeap ? 60 : 59;
248:
249: if (dayOfYear >= march1)
250: correction = isLeap ? 1 : 2;
251:
252: // zero-based month
253: int month_field = (12 * (dayOfYear + correction) + 6) / 367;
254:
255: // one-based DOM
256: int date_field = dayOfYear
257: - (isLeap ? LEAP_NUM_DAYS[month_field]
258: : NUM_DAYS[month_field]) + 1;
259:
260: // Normalize day of week
261: this .fields[DAY_OF_WEEK] += (this .fields[DAY_OF_WEEK] < 0) ? (SUNDAY + 7)
262: : SUNDAY;
263:
264: this .fields[YEAR] = rawYear;
265:
266: // If year is < 1 we are in BC
267: if (this .fields[YEAR] < 1) {
268: this .fields[YEAR] = 1 - this .fields[YEAR];
269: }
270:
271: // 0-based
272: this .fields[MONTH] = month_field + JANUARY;
273: this .fields[DATE] = date_field;
274: }
275:
276: /*
277: * The following two static arrays are used privately by the
278: * <code>toString(Calendar calendar)</code> function below.
279: */
280: static String[] months = { "Jan", "Feb", "Mar", "Apr", "May",
281: "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
282:
283: static String[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
284: "Sat" };
285:
286: /**
287: * Converts this <code>Date</code> object to a <code>String</code>
288: * of the form:
289: * <blockquote><pre>
290: * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
291: * where:<ul>
292: * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
293: * Thu, Fri, Sat</tt>).
294: * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
295: * Jul, Aug, Sep, Oct, Nov, Dec</tt>).
296: * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
297: * <tt>31</tt>), as two decimal digits.
298: * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
299: * <tt>23</tt>), as two decimal digits.
300: * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
301: * <tt>59</tt>), as two decimal digits.
302: * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
303: * <tt>61</tt>, as two decimal digits.
304: * <li><tt>zzz</tt> is the time zone (and may reflect daylight savings
305: * time). If time zone information is not available,
306: * then <tt>zzz</tt> is empty - that is, it consists
307: * of no characters at all.
308: * <li><tt>yyyy</tt> is the year, as four decimal digits.
309: * </ul>
310: *
311: * @return a string representation of this date.
312: */
313: public static String toString(Calendar calendar) {
314: // Printing in the absence of a Calendar
315: // implementation class is not supported
316: if (calendar == null) {
317: return "Thu Jan 01 00:00:00 UTC 1970";
318: }
319:
320: int dow = calendar.get(Calendar.DAY_OF_WEEK);
321: int month = calendar.get(Calendar.MONTH);
322: int day = calendar.get(Calendar.DAY_OF_MONTH);
323: int hour_of_day = calendar.get(Calendar.HOUR_OF_DAY);
324: int minute = calendar.get(Calendar.MINUTE);
325: int seconds = calendar.get(Calendar.SECOND);
326: int year = calendar.get(Calendar.YEAR);
327:
328: String yr = Integer.toString(year);
329:
330: TimeZone zone = calendar.getTimeZone();
331: String zoneID = zone.getID();
332: if (zoneID == null)
333: zoneID = "";
334:
335: // The total size of the string buffer
336: // 3+1+3+1+2+1+2+1+2+1+2+1+zoneID.length+1+yr.length
337: // = 21 + zoneID.length + yr.length
338: StringBuffer sb = new StringBuffer(25 + zoneID.length()
339: + yr.length());
340:
341: sb.append(days[dow - 1]).append(' ');
342: sb.append(months[month]).append(' ');
343: appendTwoDigits(sb, day).append(' ');
344: appendTwoDigits(sb, hour_of_day).append(':');
345: appendTwoDigits(sb, minute).append(':');
346: appendTwoDigits(sb, seconds).append(' ');
347: if (zoneID.length() > 0)
348: sb.append(zoneID).append(' ');
349: appendFourDigits(sb, year);
350:
351: return sb.toString();
352: }
353:
354: /**
355: * Converts this <code>Date</code> object to a <code>String</code>.
356: * The output format is as follows:
357: * <blockquote><pre>yyyy MM dd hh mm ss +zzzz</pre></blockquote>
358: * where:<ul>
359: * <li><dd>yyyy</dd> is the year, as four decimal digits.
360: * Year values larger than <dd>9999</dd> will be truncated
361: * to <dd>9999</dd>.
362: * <li><dd>MM</dd> is the month (<dd>01</dd> through <dd>12</dd>),
363: * as two decimal digits.
364: * <li><dd>dd</dd> is the day of the month (<dd>01</dd> through
365: * <dd>31</dd>), as two decimal digits.
366: * <li><dd>hh</dd> is the hour of the day (<dd>00</dd> through
367: * <dd>23</dd>), as two decimal digits.
368: * <li><dd>mm</dd> is the minute within the hour (<dd>00</dd>
369: * through <dd>59</dd>), as two decimal digits.
370: * <li><dd>ss</dd> is the second within the minute (<dd>00</dd>
371: * through <dd>59</dd>), as two decimal digits.
372: * <li><dd>zzzz</dd> is the time zone offset in hours and minutes
373: * (four decimal digits <dd>"hhmm"</dd>) relative to GMT,
374: * preceded by a "+" or "-" character (<dd>-1200</dd>
375: * through <dd>+1200</dd>).
376: * For instance, Pacific Standard Time zone is printed
377: * as <dd>-0800</dd>. GMT is printed as <dd>+0000</dd>.
378: * </ul>
379: *
380: * @return a string representation of this date.
381: */
382: public static String toISO8601String(Calendar calendar) {
383: // Printing in the absence of a Calendar
384: // implementation class is not supported
385: if (calendar == null) {
386: return "0000 00 00 00 00 00 +0000";
387: }
388:
389: int year = calendar.get(Calendar.YEAR);
390: int month = calendar.get(Calendar.MONTH) + 1;
391: int day = calendar.get(Calendar.DAY_OF_MONTH);
392: int hour_of_day = calendar.get(Calendar.HOUR_OF_DAY);
393: int hour = calendar.get(Calendar.HOUR);
394: int minute = calendar.get(Calendar.MINUTE);
395: int seconds = calendar.get(Calendar.SECOND);
396:
397: String yr = Integer.toString(year);
398:
399: // The total size of the string buffer
400: // yr.length+1+2+1+2+1+2+1+2+1+2+1+5 = 25 + yr.length
401: StringBuffer sb = new StringBuffer(25 + yr.length());
402:
403: appendFourDigits(sb, year).append(' ');
404: appendTwoDigits(sb, month).append(' ');
405: appendTwoDigits(sb, day).append(' ');
406: appendTwoDigits(sb, hour_of_day).append(' ');
407: appendTwoDigits(sb, minute).append(' ');
408: appendTwoDigits(sb, seconds).append(' ');
409:
410: // TimeZone offset is represented in milliseconds.
411: // Convert the offset to minutes:
412: TimeZone t = calendar.getTimeZone();
413: int zoneOffsetInMinutes = t.getRawOffset() / 1000 / 60;
414:
415: if (zoneOffsetInMinutes < 0) {
416: zoneOffsetInMinutes = Math.abs(zoneOffsetInMinutes);
417: sb.append('-');
418: } else {
419: sb.append('+');
420: }
421:
422: int zoneHours = zoneOffsetInMinutes / 60;
423: int zoneMinutes = zoneOffsetInMinutes % 60;
424:
425: appendTwoDigits(sb, zoneHours);
426: appendTwoDigits(sb, zoneMinutes);
427:
428: return sb.toString();
429: }
430:
431: private static final StringBuffer appendFourDigits(StringBuffer sb,
432: int number) {
433: if (number >= 0 && number < 1000) {
434: sb.append('0');
435: if (number < 100) {
436: sb.append('0');
437: }
438: if (number < 10) {
439: sb.append('0');
440: }
441: }
442: return sb.append(number);
443: }
444:
445: private static final StringBuffer appendTwoDigits(StringBuffer sb,
446: int number) {
447: if (number < 10) {
448: sb.append('0');
449: }
450: return sb.append(number);
451: }
452:
453: /////////////////////////////
454: // Fields => Time computation
455: /////////////////////////////
456:
457: /**
458: * Converts time field values to UTC as milliseconds.
459: * @exception IllegalArgumentException if any fields are invalid.
460: */
461: protected void computeTime() {
462:
463: correctTime();
464:
465: // This function takes advantage of the fact that unset fields in
466: // the time field list have a value of zero.
467:
468: // First, use the year to determine whether to use the Gregorian or the
469: // Julian calendar. If the year is not the year of the cutover, this
470: // computation will be correct. But if the year is the cutover year,
471: // this may be incorrect. In that case, assume the Gregorian calendar,
472: // make the computation, and then recompute if the resultant millis
473: // indicate the wrong calendar has been assumed.
474:
475: // A date such as Oct. 10, 1582 does not exist in a Gregorian calendar
476: // with the default changeover of Oct. 15, 1582, since in such a
477: // calendar Oct. 4 (Julian) is followed by Oct. 15 (Gregorian). This
478: // algorithm will interpret such a date using the Julian calendar,
479: // yielding Oct. 20, 1582 (Gregorian).
480: int year = this .fields[YEAR];
481: boolean isGregorian = year >= gregorianCutoverYear;
482: long julianDay = calculateJulianDay(isGregorian, year);
483: long millis = julianDayToMillis(julianDay);
484:
485: // The following check handles portions of the cutover year BEFORE the
486: // cutover itself happens. The check for the julianDate number is for a
487: // rare case; it's a hardcoded number, but it's efficient. The given
488: // Julian day number corresponds to Dec 3, 292269055 BC, which
489: // corresponds to millis near Long.MIN_VALUE. The need for the check
490: // arises because for extremely negative Julian day numbers, the millis
491: // actually overflow to be positive values. Without the check, the
492: // initial date is interpreted with the Gregorian calendar, even when
493: // the cutover doesn't warrant it.
494: if (isGregorian != (millis >= gregorianCutover)
495: && julianDay != -106749550580L) { // See above
496:
497: julianDay = calculateJulianDay(!isGregorian, year);
498: millis = julianDayToMillis(julianDay);
499: }
500:
501: // Do the time portion of the conversion.
502:
503: int millisInDay = 0;
504:
505: // Hours
506: // Don't normalize here; let overflow bump into the next period.
507: // This is consistent with how we handle other fields.
508: millisInDay += this .fields[HOUR_OF_DAY];
509: millisInDay *= 60;
510:
511: // now get minutes
512: millisInDay += this .fields[MINUTE];
513: millisInDay *= 60;
514:
515: // now get seconds
516: millisInDay += this .fields[SECOND];
517: millisInDay *= 1000;
518:
519: // now get millis
520: millisInDay += this .fields[MILLISECOND];
521:
522: // Compute the time zone offset and DST offset. There are two potential
523: // ambiguities here. We'll assume a 2:00 am (wall time) switchover time
524: // for discussion purposes here.
525: // 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
526: // can be in standard or in DST depending. However, 2:00 am is an invalid
527: // representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
528: // We assume standard time.
529: // 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
530: // can be in standard or DST. Both are valid representations (the rep
531: // jumps from 1:59:59 DST to 1:00:00 Std).
532: // Again, we assume standard time.
533: // We use the TimeZone object to get the zone offset
534: int zoneOffset = getTimeZone().getRawOffset();
535:
536: // Now add date and millisInDay together, to make millis contain local wall
537: // millis, with no zone or DST adjustments
538: millis += millisInDay;
539:
540: // Normalize the millisInDay to 0..ONE_DAY-1. If the millis is out
541: // of range, then we must call timeToFields() to recompute our
542: // fields.
543: int[] normalizedMillisInDay = new int[1];
544: floorDivide(millis, (int) ONE_DAY, normalizedMillisInDay);
545:
546: // We need to have the month, the day, and the day of the week.
547: // Calling timeToFields will compute the MONTH and DATE fields.
548: //
549: // It's tempting to try to use DAY_OF_WEEK here, if it
550: // is set, but we CAN'T. Even if it's set, it might have
551: // been set wrong by the user. We should rely only on
552: // the Julian day number, which has been computed correctly
553: // using the disambiguation algorithm above. [LIU]
554: int dow = julianDayToDayOfWeek(julianDay);
555:
556: // It's tempting to try to use DAY_OF_WEEK here, if it
557: // is set, but we CAN'T. Even if it's set, it might have
558: // been set wrong by the user. We should rely only on
559: // the Julian day number, which has been computed correctly
560: // using the disambiguation algorithm above. [LIU]
561: int dstOffset = getTimeZone().getOffset(AD, this .fields[YEAR],
562: this .fields[MONTH], this .fields[DATE], dow,
563: normalizedMillisInDay[0])
564: - zoneOffset;
565: // Note: Because we pass in wall millisInDay, rather than
566: // standard millisInDay, we interpret "1:00 am" on the day
567: // of cessation of DST as "1:00 am Std" (assuming the time
568: // of cessation is 2:00 am).
569:
570: // Store our final computed GMT time, with timezone adjustments.
571: time = millis - zoneOffset - dstOffset;
572: }
573:
574: /**
575: * Compute the Julian day number under either the Gregorian or the
576: * Julian calendar, using the given year and the remaining fields.
577: * @param isGregorian if true, use the Gregorian calendar
578: * @param year the adjusted year number, with 0 indicating the
579: * year 1 BC, -1 indicating 2 BC, etc.
580: * @return the Julian day number
581: */
582: private final long calculateJulianDay(boolean isGregorian, int year) {
583: int month = 0;
584: long millis = 0;
585:
586: month = this .fields[MONTH] - JANUARY;
587:
588: // If the month is out of range, adjust it into range
589: if (month < 0 || month > 11) {
590: int[] rem = new int[1];
591: year += floorDivide(month, 12, rem);
592: month = rem[0];
593: }
594:
595: boolean isLeap = year % 4 == 0;
596:
597: long julianDay = 365L * (year - 1) + floorDivide((year - 1), 4)
598: + (JAN_1_1_JULIAN_DAY - 3);
599:
600: if (isGregorian) {
601: isLeap = isLeap && ((year % 100 != 0) || (year % 400 == 0));
602: // Add 2 because Gregorian calendar starts 2 days after Julian calendar
603: julianDay += floorDivide((year - 1), 400)
604: - floorDivide((year - 1), 100) + 2;
605: }
606:
607: // At this point julianDay is the 0-based day BEFORE the first day of
608: // January 1, year 1 of the given calendar. If julianDay == 0, it
609: // specifies (Jan. 1, 1) - 1, in whatever calendar we are using (Julian
610: // or Gregorian).
611: julianDay += isLeap ? LEAP_NUM_DAYS[month] : NUM_DAYS[month];
612: julianDay += this .fields[DATE];
613: return julianDay;
614: }
615:
616: /**
617: * Validates the field values for HOUR_OF_DAY, AM_PM and HOUR
618: * The calendar will give preference in the following order
619: * HOUR_OF_DAY, AM_PM, HOUR
620: */
621: private void correctTime() {
622: int value;
623:
624: if (isSet[HOUR_OF_DAY]) {
625: value = this .fields[HOUR_OF_DAY] % 24;
626: this .fields[HOUR_OF_DAY] = value;
627: this .fields[AM_PM] = (value < 12) ? AM : PM;
628: this .isSet[HOUR_OF_DAY] = false;
629: return;
630: }
631:
632: if (isSet[AM_PM]) {
633: // Determines AM PM with the 24 hour clock
634: // This prevents the user from inputing an invalid one.
635: if (this .fields[AM_PM] != AM && this .fields[AM_PM] != PM) {
636: value = this .fields[HOUR_OF_DAY];
637: this .fields[AM_PM] = (value < 12) ? AM : PM;
638: }
639: this .isSet[AM_PM] = false;
640: }
641:
642: if (isSet[HOUR]) {
643: value = this .fields[HOUR];
644: if (value > 12) {
645: this .fields[HOUR_OF_DAY] = (value % 12) + 12;
646: this .fields[HOUR] = value % 12;
647: this .fields[AM_PM] = PM;
648: } else {
649: if (this .fields[AM_PM] == PM) {
650: this .fields[HOUR_OF_DAY] = value + 12;
651: } else {
652: this .fields[HOUR_OF_DAY] = value;
653: }
654: }
655: this .isSet[HOUR] = false;
656: }
657: }
658:
659: /////////////////
660: // Implementation
661: /////////////////
662:
663: /**
664: * Converts time as milliseconds to Julian day.
665: * @param millis the given milliseconds.
666: * @return the Julian day number.
667: */
668: private static final long millisToJulianDay(long millis) {
669: return EPOCH_JULIAN_DAY + floorDivide(millis, ONE_DAY);
670: }
671:
672: /**
673: * Converts Julian day to time as milliseconds.
674: * @param julian the given Julian day number.
675: * @return time as milliseconds.
676: */
677: private static final long julianDayToMillis(long julian) {
678: return (julian - EPOCH_JULIAN_DAY) * ONE_DAY;
679: }
680:
681: private static final int julianDayToDayOfWeek(long julian) {
682: // If julian is negative, then julian%7 will be negative, so we adjust
683: // accordingly. We add 1 because Julian day 0 is Monday.
684: int dayOfWeek = (int) ((julian + 1) % 7);
685: return dayOfWeek + ((dayOfWeek < 0) ? (7 + SUNDAY) : SUNDAY);
686: }
687:
688: /**
689: * Divide two long integers, returning the floor of the quotient.
690: * <p>
691: * Unlike the built-in division, this is mathematically well-behaved.
692: * E.g., <code>-1/4</code> => 0
693: * but <code>floorDivide(-1,4)</code> => -1.
694: * @param numerator the numerator
695: * @param denominator a divisor which must be > 0
696: * @return the floor of the quotient.
697: */
698: private static final long floorDivide(long numerator,
699: long denominator) {
700: // We do this computation in order to handle
701: // a numerator of Long.MIN_VALUE correctly
702: return (numerator >= 0) ? numerator / denominator
703: : ((numerator + 1) / denominator) - 1;
704: }
705:
706: /**
707: * Divide two integers, returning the floor of the quotient.
708: * <p>
709: * Unlike the built-in division, this is mathematically well-behaved.
710: * E.g., <code>-1/4</code> => 0
711: * but <code>floorDivide(-1,4)</code> => -1.
712: * @param numerator the numerator
713: * @param denominator a divisor which must be > 0
714: * @return the floor of the quotient.
715: */
716: private static final int floorDivide(int numerator, int denominator) {
717: // We do this computation in order to handle
718: // a numerator of Integer.MIN_VALUE correctly
719: return (numerator >= 0) ? numerator / denominator
720: : ((numerator + 1) / denominator) - 1;
721: }
722:
723: /**
724: * Divide two integers, returning the floor of the quotient, and
725: * the modulus remainder.
726: * <p>
727: * Unlike the built-in division, this is mathematically well-behaved.
728: * E.g., <code>-1/4</code> => 0 and <code>-1%4</code> => -1,
729: * but <code>floorDivide(-1,4)</code> => -1 with <code>remainder[0]</code> => 3.
730: * @param numerator the numerator
731: * @param denominator a divisor which must be > 0
732: * @param remainder an array of at least one element in which the value
733: * <code>numerator mod denominator</code> is returned. Unlike <code>numerator
734: * % denominator</code>, this will always be non-negative.
735: * @return the floor of the quotient.
736: */
737: private static final int floorDivide(int numerator,
738: int denominator, int[] remainder) {
739:
740: if (numerator >= 0) {
741: remainder[0] = numerator % denominator;
742: return numerator / denominator;
743: }
744: int quotient = ((numerator + 1) / denominator) - 1;
745: remainder[0] = numerator - (quotient * denominator);
746: return quotient;
747: }
748:
749: /**
750: * Divide two integers, returning the floor of the quotient, and
751: * the modulus remainder.
752: * <p>
753: * Unlike the built-in division, this is mathematically well-behaved.
754: * E.g., <code>-1/4</code> => 0 and <code>-1%4</code> => -1,
755: * but <code>floorDivide(-1,4)</code> => -1 with <code>remainder[0]</code> => 3.
756: * @param numerator the numerator
757: * @param denominator a divisor which must be > 0
758: * @param remainder an array of at least one element in which the value
759: * <code>numerator mod denominator</code> is returned. Unlike <code>numerator
760: * % denominator</code>, this will always be non-negative.
761: * @return the floor of the quotient.
762: */
763: private static final int floorDivide(long numerator,
764: int denominator, int[] remainder) {
765:
766: if (numerator >= 0) {
767: remainder[0] = (int) (numerator % denominator);
768: return (int) (numerator / denominator);
769: }
770: int quotient = (int) (((numerator + 1) / denominator) - 1);
771: remainder[0] = (int) (numerator - (quotient * denominator));
772: return quotient;
773: }
774: }
|