001: /*
002: * @(#)Gregorian.java 1.7 06/10/10
003: *
004: * Copyright 1990-2006 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 sun.util.calendar;
028:
029: /**
030: * Gregorian calendar calculations. The algorithms are from "Calendrical
031: * Calculation" by Nachum Dershowitz and Edward M. Reingold (ISBN:
032: * 0-521-56474-3).
033: */
034:
035: public class Gregorian implements CalendarSystem {
036:
037: /**
038: * The number of days between Gregorian January 1, 1 and January
039: * 1, 1970.
040: */
041: public static final int EPOCH_DATE = 719163;
042:
043: /**
044: * Calculates Gregorian calendar fields from the given UTC value
045: * which is the difference from Gregorian January 1, 1970 00:00:00
046: * GMT.
047: * @param utc the UTC value in milliseconds
048: * @return the CaledarDate object that contains the calculated Gregorian calendar field values.
049: */
050: public static CalendarDate getCalendarDate(long utc) {
051: long days;
052: int millis;
053:
054: days = utc / ONE_DAY;
055: millis = (int) (utc % ONE_DAY);
056: if (millis < 0) {
057: millis += ONE_DAY;
058: days--;
059: }
060: days += EPOCH_DATE;
061: CalendarDate cdate = getCalendarDateFromFixedDate(days);
062: cdate.setTimeOfDay(millis);
063: return cdate;
064: }
065:
066: /**
067: * Calculates milliseconds of given time from EPOCH, 1970-01-01 00:00AM.
068: */
069: public static long dateToMillis(CalendarDate date) {
070: long gd = getFixedDate(date.getYear(), date.getMonth(), date
071: .getDate());
072: return ((gd - EPOCH_DATE) * ONE_DAY + date.getTimeOfDay());
073: }
074:
075: /**
076: * Calculates milliseconds of given time from EPOCH, 1970-01-01 00:00AM.
077: */
078: public static long dateToMillis(int year, int month, int day,
079: int milliseconds) {
080: long gd = getFixedDate(year, month, day);
081: return ((gd - EPOCH_DATE) * ONE_DAY + milliseconds);
082: }
083:
084: public static boolean validate(CalendarDate date) {
085: int month = date.getMonth();
086: if (month < JANUARY || month > DECEMBER) {
087: return false;
088: }
089: int days = getMonthLength(date.getYear(), month);
090: if (date.getDate() <= 0 || date.getDate() > days) {
091: return false;
092: }
093: return true;
094: }
095:
096: private static final int[] days_in_month = { 31, 28, 31, 30, 31,
097: 30, 31, 31, 30, 31, 30, 31 };
098:
099: /**
100: * @param month 0-based
101: */
102: public static int getMonthLength(int year, int month) {
103: int days = days_in_month[month];
104: if (month == FEBRUARY && isLeapYear(year)) {
105: days++;
106: }
107: return days;
108: }
109:
110: /**
111: * Returns number of days from 0001-01-01. Counting leap correction.
112: */
113: public static final long getFixedDate(int year, int month, int day) {
114: int prevyear = year - 1;
115: month++; // 1-based month numbering
116: long days;
117:
118: if (prevyear >= 0) {
119: days = (365 * (long) prevyear) + (prevyear / 4)
120: - (prevyear / 100) + (prevyear / 400)
121: + ((367 * month - 362) / 12) + day;
122: } else {
123: days = (365 * (long) prevyear) + floorDivide(prevyear, 4)
124: - floorDivide(prevyear, 100)
125: + floorDivide(prevyear, 400)
126: + floorDivide((367 * month - 362), 12) + day;
127: }
128: if (month > 2) {
129: days -= (isLeapYear(year)) ? 1 : 2;
130: }
131: return days;
132: }
133:
134: /**
135: * Calculates year/month/day from given date. The date is from 0001-01-01.
136: */
137: public static CalendarDate getCalendarDateFromFixedDate(
138: long fixedDate) {
139: int year = getYear(fixedDate);
140: int pday = (int) (fixedDate - getFixedDate(year, JANUARY, 1));
141: int corr = 2;
142: long mar1 = getFixedDate(year, MARCH, 1);
143: if (fixedDate < mar1) {
144: corr = 0;
145: } else if (fixedDate >= mar1 && isLeapYear(year)) {
146: corr = 1;
147: }
148: int month = floorDivide((12 * (pday + corr) + 373), 367) - 1;
149: int day = (int) (fixedDate - getFixedDate(year, month, 1) + 1);
150: int dow = getDayOfWeekFromFixedDate(fixedDate);
151: CalendarDate cdate = new CalendarDate(year, month, day);
152: cdate.setDayOfWeek(dow);
153: return cdate;
154: }
155:
156: /**
157: * Returns day of week of given day
158: */
159: public static int getDayOfWeek(CalendarDate date) {
160: long fixedDate = getFixedDate(date.getYear(), date.getMonth(),
161: date.getDate());
162: return getDayOfWeekFromFixedDate(fixedDate);
163: }
164:
165: private static final int getDayOfWeekFromFixedDate(long fixedDate) {
166: if (fixedDate >= 0) {
167: return (int) (fixedDate % 7) + SUNDAY;
168: }
169: return (int) mod(fixedDate, 7) + SUNDAY;
170: }
171:
172: /**
173: * Returns Gregorian year number of given date
174: */
175: private static final int getYear(long fixedDate) {
176: long d0;
177: int d1, d2, d3;
178: int n400, n100, n4, n1;
179: int year;
180:
181: if (fixedDate >= 0) {
182: d0 = fixedDate - 1;
183: n400 = (int) (d0 / 146097);
184: d1 = (int) (d0 % 146097);
185: n100 = d1 / 36524;
186: d2 = d1 % 36524;
187: n4 = d2 / 1461;
188: d3 = d2 % 1461;
189: n1 = d3 / 365;
190: } else {
191: d0 = fixedDate - 1;
192: n400 = (int) floorDivide(d0, 146097L);
193: d1 = (int) mod(d0, 146097L);
194: n100 = floorDivide(d1, 36524);
195: d2 = mod(d1, 36524);
196: n4 = floorDivide(d2, 1461);
197: d3 = mod(d2, 1461);
198: n1 = floorDivide(d3, 365);
199: }
200: year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
201: if (!(n100 == 4 || n1 == 4)) {
202: ++year;
203: }
204: return year;
205: }
206:
207: /**
208: * @return true if the given year is a Gregorian leap year.
209: */
210: public static final boolean isLeapYear(int year) {
211: if (year >= 0) {
212: return (((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0)));
213: }
214: return (((mod(year, 4) == 0) && ((mod(year, 100) != 0) || (mod(
215: year, 400) == 0))));
216: }
217:
218: /**
219: * Floor function working with negative number.
220: * floor(3.14) = 3 and floor(-3.14) = -4.
221: */
222: private static final long floorDivide(long n, long d) {
223: return ((n >= 0) ? (n / d) : (((n + 1L) / d) - 1L));
224: }
225:
226: private static final int floorDivide(int n, int d) {
227: return ((n >= 0) ? (n / d) : (((n + 1) / d) - 1));
228: }
229:
230: private static final long mod(long x, long y) {
231: return (x - y * floorDivide(x, y));
232: }
233:
234: private static final int mod(int x, int y) {
235: return (x - y * floorDivide(x, y));
236: }
237: }
|