|
From: <ls...@us...> - 2007-06-23 05:02:05
|
Revision: 3292
http://jnode.svn.sourceforge.net/jnode/?rev=3292&view=rev
Author: lsantha
Date: 2007-06-22 22:02:03 -0700 (Fri, 22 Jun 2007)
Log Message:
-----------
Openjdk integration.
Added Paths:
-----------
trunk/core/src/openjdk/sun/sun/util/calendar/
trunk/core/src/openjdk/sun/sun/util/calendar/AbstractCalendar.java
trunk/core/src/openjdk/sun/sun/util/calendar/BaseCalendar.java
trunk/core/src/openjdk/sun/sun/util/calendar/CalendarDate.java
trunk/core/src/openjdk/sun/sun/util/calendar/CalendarSystem.java
trunk/core/src/openjdk/sun/sun/util/calendar/CalendarUtils.java
trunk/core/src/openjdk/sun/sun/util/calendar/Era.java
trunk/core/src/openjdk/sun/sun/util/calendar/Gregorian.java
trunk/core/src/openjdk/sun/sun/util/calendar/ImmutableGregorianDate.java
trunk/core/src/openjdk/sun/sun/util/calendar/JulianCalendar.java
trunk/core/src/openjdk/sun/sun/util/calendar/LocalGregorianCalendar.java
trunk/core/src/openjdk/sun/sun/util/calendar/ZoneInfo.java
trunk/core/src/openjdk/sun/sun/util/calendar/ZoneInfoFile.java
Added: trunk/core/src/openjdk/sun/sun/util/calendar/AbstractCalendar.java
===================================================================
--- trunk/core/src/openjdk/sun/sun/util/calendar/AbstractCalendar.java (rev 0)
+++ trunk/core/src/openjdk/sun/sun/util/calendar/AbstractCalendar.java 2007-06-23 05:02:03 UTC (rev 3292)
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.util.calendar;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * The <code>AbstractCalendar</code> class provides a framework for
+ * implementing a concrete calendar system.
+ *
+ * <p><a name="fixed_date"></a><B>Fixed Date</B><br>
+ *
+ * For implementing a concrete calendar system, each calendar must
+ * have the common date numbering, starting from midnight the onset of
+ * Monday, January 1, 1 (Gregorian). It is called a <I>fixed date</I>
+ * in this class. January 1, 1 (Gregorian) is fixed date 1. (See
+ * Nachum Dershowitz and Edward M. Reingold, <I>CALENDRICAL
+ * CALCULATION The Millennium Edition</I>, Section 1.2 for details.)
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.5
+ */
+
+public abstract class AbstractCalendar extends CalendarSystem {
+
+ // The constants assume no leap seconds support.
+ static final int SECOND_IN_MILLIS = 1000;
+ static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
+ static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
+ static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
+
+ // The number of days between January 1, 1 and January 1, 1970 (Gregorian)
+ static final int EPOCH_OFFSET = 719163;
+
+ private Era[] eras;
+
+ protected AbstractCalendar() {
+ }
+
+ public Era getEra(String eraName) {
+ if (eras != null) {
+ for (int i = 0; i < eras.length; i++) {
+ if (eras[i].equals(eraName)) {
+ return eras[i];
+ }
+ }
+ }
+ return null;
+ }
+
+ public Era[] getEras() {
+ Era[] e = null;
+ if (eras != null) {
+ e = new Era[eras.length];
+ System.arraycopy(eras, 0, e, 0, eras.length);
+ }
+ return e;
+ }
+
+ public void setEra(CalendarDate date, String eraName) {
+ if (eras == null) {
+ return; // should report an error???
+ }
+ for (int i = 0; i < eras.length; i++) {
+ Era e = eras[i];
+ if (e != null && e.getName().equals(eraName)) {
+ date.setEra(e);
+ return;
+ }
+ }
+ throw new IllegalArgumentException("unknown era name: " + eraName);
+ }
+
+ protected void setEras(Era[] eras) {
+ this.eras = eras;
+ }
+
+ public CalendarDate getCalendarDate() {
+ return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
+ }
+
+ public CalendarDate getCalendarDate(long millis) {
+ return getCalendarDate(millis, newCalendarDate());
+ }
+
+ public CalendarDate getCalendarDate(long millis, TimeZone zone) {
+ CalendarDate date = newCalendarDate(zone);
+ return getCalendarDate(millis, date);
+ }
+
+ public CalendarDate getCalendarDate(long millis, CalendarDate date) {
+ int ms = 0; // time of day
+ int zoneOffset = 0;
+ int saving = 0;
+ long days = 0; // fixed date
+
+ // adjust to local time if `date' has time zone.
+ TimeZone zi = date.getZone();
+ if (zi != null) {
+ int[] offsets = new int[2];
+ if (zi instanceof ZoneInfo) {
+ zoneOffset = ((ZoneInfo)zi).getOffsets(millis, offsets);
+ } else {
+ zoneOffset = zi.getOffset(millis);
+ offsets[0] = zi.getRawOffset();
+ offsets[1] = zoneOffset - offsets[0];
+ }
+
+ // We need to calculate the given millis and time zone
+ // offset separately for java.util.GregorianCalendar
+ // compatibility. (i.e., millis + zoneOffset could cause
+ // overflow or underflow, which must be avoided.) Usually
+ // days should be 0 and ms is in the range of -13:00 to
+ // +14:00. However, we need to deal with extreme cases.
+ days = zoneOffset / DAY_IN_MILLIS;
+ ms = zoneOffset % DAY_IN_MILLIS;
+ saving = offsets[1];
+ }
+ date.setZoneOffset(zoneOffset);
+ date.setDaylightSaving(saving);
+
+ days += millis / DAY_IN_MILLIS;
+ ms += (int) (millis % DAY_IN_MILLIS);
+ if (ms >= DAY_IN_MILLIS) {
+ // at most ms is (DAY_IN_MILLIS - 1) * 2.
+ ms -= DAY_IN_MILLIS;
+ ++days;
+ } else {
+ // at most ms is (1 - DAY_IN_MILLIS) * 2. Adding one
+ // DAY_IN_MILLIS results in still negative.
+ while (ms < 0) {
+ ms += DAY_IN_MILLIS;
+ --days;
+ }
+ }
+
+ // convert to fixed date (offset from Jan. 1, 1 (Gregorian))
+ days += EPOCH_OFFSET;
+
+ // calculate date fields from the fixed date
+ getCalendarDateFromFixedDate(date, days);
+
+ // calculate time fields from the time of day
+ setTimeOfDay(date, ms);
+ date.setLeapYear(isLeapYear(date));
+ date.setNormalized(true);
+ return date;
+ }
+
+ public long getTime(CalendarDate date) {
+ long gd = getFixedDate(date);
+ long ms = (gd - EPOCH_OFFSET) * DAY_IN_MILLIS + getTimeOfDay(date);
+ int zoneOffset = 0;
+ TimeZone zi = date.getZone();
+ if (zi != null) {
+ if (date.isNormalized()) {
+ return ms - date.getZoneOffset();
+ }
+ // adjust time zone and daylight saving
+ int[] offsets = new int[2];
+ if (date.isStandardTime()) {
+ // 1) 2:30am during starting-DST transition is
+ // intrepreted as 2:30am ST
+ // 2) 5:00pm during DST is still interpreted as 5:00pm ST
+ // 3) 1:30am during ending-DST transition is interpreted
+ // as 1:30am ST (after transition)
+ if (zi instanceof ZoneInfo) {
+ ((ZoneInfo)zi).getOffsetsByStandard(ms, offsets);
+ zoneOffset = offsets[0];
+ } else {
+ zoneOffset = zi.getOffset(ms - zi.getRawOffset());
+ }
+ } else {
+ // 1) 2:30am during starting-DST transition is
+ // intrepreted as 3:30am DT
+ // 2) 5:00pm during DST is intrepreted as 5:00pm DT
+ // 3) 1:30am during ending-DST transition is interpreted
+ // as 1:30am DT/0:30am ST (before transition)
+ if (zi instanceof ZoneInfo) {
+ zoneOffset = ((ZoneInfo)zi).getOffsetsByWall(ms, offsets);
+ } else {
+ zoneOffset = zi.getOffset(ms - zi.getRawOffset());
+ }
+ }
+ }
+ ms -= zoneOffset;
+ getCalendarDate(ms, date);
+ return ms;
+ }
+
+ protected long getTimeOfDay(CalendarDate date) {
+ long fraction = date.getTimeOfDay();
+ if (fraction != CalendarDate.TIME_UNDEFINED) {
+ return fraction;
+ }
+ fraction = getTimeOfDayValue(date);
+ date.setTimeOfDay(fraction);
+ return fraction;
+ }
+
+ public long getTimeOfDayValue(CalendarDate date) {
+ long fraction = date.getHours();
+ fraction *= 60;
+ fraction += date.getMinutes();
+ fraction *= 60;
+ fraction += date.getSeconds();
+ fraction *= 1000;
+ fraction += date.getMillis();
+ return fraction;
+ }
+
+ public CalendarDate setTimeOfDay(CalendarDate cdate, int fraction) {
+ if (fraction < 0) {
+ throw new IllegalArgumentException();
+ }
+ boolean normalizedState = cdate.isNormalized();
+ int time = fraction;
+ int hours = time / HOUR_IN_MILLIS;
+ time %= HOUR_IN_MILLIS;
+ int minutes = time / MINUTE_IN_MILLIS;
+ time %= MINUTE_IN_MILLIS;
+ int seconds = time / SECOND_IN_MILLIS;
+ time %= SECOND_IN_MILLIS;
+ cdate.setHours(hours);
+ cdate.setMinutes(minutes);
+ cdate.setSeconds(seconds);
+ cdate.setMillis(time);
+ cdate.setTimeOfDay(fraction);
+ if (hours < 24 && normalizedState) {
+ // If this time of day setting doesn't affect the date,
+ // then restore the normalized state.
+ cdate.setNormalized(normalizedState);
+ }
+ return cdate;
+ }
+
+ /**
+ * Returns 7 in this default implementation.
+ *
+ * @return 7
+ */
+ public int getWeekLength() {
+ return 7;
+ }
+
+ protected abstract boolean isLeapYear(CalendarDate date);
+
+ public CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, CalendarDate date) {
+ CalendarDate ndate = (CalendarDate) date.clone();
+ normalize(ndate);
+ long fd = getFixedDate(ndate);
+ long nfd;
+ if (nth > 0) {
+ nfd = 7 * nth + getDayOfWeekDateBefore(fd, dayOfWeek);
+ } else {
+ nfd = 7 * nth + getDayOfWeekDateAfter(fd, dayOfWeek);
+ }
+ getCalendarDateFromFixedDate(ndate, nfd);
+ return ndate;
+ }
+
+ /**
+ * Returns a date of the given day of week before the given fixed
+ * date.
+ *
+ * @param fixedDate the fixed date
+ * @param dayOfWeek the day of week
+ * @return the calculated date
+ */
+ static long getDayOfWeekDateBefore(long fixedDate, int dayOfWeek) {
+ return getDayOfWeekDateOnOrBefore(fixedDate - 1, dayOfWeek);
+ }
+
+ /**
+ * Returns a date of the given day of week that is closest to and
+ * after the given fixed date.
+ *
+ * @param fixedDate the fixed date
+ * @param dayOfWeek the day of week
+ * @return the calculated date
+ */
+ static long getDayOfWeekDateAfter(long fixedDate, int dayOfWeek) {
+ return getDayOfWeekDateOnOrBefore(fixedDate + 7, dayOfWeek);
+ }
+
+ /**
+ * Returns a date of the given day of week on or before the given fixed
+ * date.
+ *
+ * @param fixedDate the fixed date
+ * @param dayOfWeek the day of week
+ * @return the calculated date
+ */
+ // public for java.util.GregorianCalendar
+ public static long getDayOfWeekDateOnOrBefore(long fixedDate, int dayOfWeek) {
+ long fd = fixedDate - (dayOfWeek - 1);
+ if (fd >= 0) {
+ return fixedDate - (fd % 7);
+ }
+ return fixedDate - CalendarUtils.mod(fd, 7);
+ }
+
+ /**
+ * Returns the fixed date calculated with the specified calendar
+ * date. If the specified date is not normalized, its date fields
+ * are normalized.
+ *
+ * @param date a <code>CalendarDate</code> with which the fixed
+ * date is calculated
+ * @return the calculated fixed date
+ * @see AbstractCalendar.html#fixed_date
+ */
+ protected abstract long getFixedDate(CalendarDate date);
+
+ /**
+ * Calculates calendar fields from the specified fixed date. This
+ * method stores the calculated calendar field values in the specified
+ * <code>CalendarDate</code>.
+ *
+ * @param date a <code>CalendarDate</code> to stored the
+ * calculated calendar fields.
+ * @param fixedDate a fixed date to calculate calendar fields
+ * @see AbstractCalendar.html#fixed_date
+ */
+ protected abstract void getCalendarDateFromFixedDate(CalendarDate date,
+ long fixedDate);
+
+ public boolean validateTime(CalendarDate date) {
+ int t = date.getHours();
+ if (t < 0 || t >= 24) {
+ return false;
+ }
+ t = date.getMinutes();
+ if (t < 0 || t >= 60) {
+ return false;
+ }
+ t = date.getSeconds();
+ // TODO: Leap second support.
+ if (t < 0 || t >= 60) {
+ return false;
+ }
+ t = date.getMillis();
+ if (t < 0 || t >= 1000) {
+ return false;
+ }
+ return true;
+ }
+
+
+ int normalizeTime(CalendarDate date) {
+ long fraction = getTimeOfDay(date);
+ long days = 0;
+
+ if (fraction >= DAY_IN_MILLIS) {
+ days = fraction / DAY_IN_MILLIS;
+ fraction %= DAY_IN_MILLIS;
+ } else if (fraction < 0) {
+ days = CalendarUtils.floorDivide(fraction, DAY_IN_MILLIS);
+ if (days != 0) {
+ fraction -= DAY_IN_MILLIS * days; // mod(fraction, DAY_IN_MILLIS)
+ }
+ }
+ if (days != 0) {
+ date.setTimeOfDay(fraction);
+ }
+ date.setMillis((int)(fraction % 1000));
+ fraction /= 1000;
+ date.setSeconds((int)(fraction % 60));
+ fraction /= 60;
+ date.setMinutes((int)(fraction % 60));
+ date.setHours((int)(fraction / 60));
+ return (int)days;
+ }
+}
Added: trunk/core/src/openjdk/sun/sun/util/calendar/BaseCalendar.java
===================================================================
--- trunk/core/src/openjdk/sun/sun/util/calendar/BaseCalendar.java (rev 0)
+++ trunk/core/src/openjdk/sun/sun/util/calendar/BaseCalendar.java 2007-06-23 05:02:03 UTC (rev 3292)
@@ -0,0 +1,538 @@
+/*
+ * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.util.calendar;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * The <code>BaseCalendar</code> provides basic calendar calculation
+ * functions to support the Julian, Gregorian, and Gregorian-based
+ * calendar systems.
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.5
+ */
+
+public abstract class BaseCalendar extends AbstractCalendar {
+
+ public static final int JANUARY = 1;
+ public static final int FEBRUARY = 2;
+ public static final int MARCH = 3;
+ public static final int APRIL = 4;
+ public static final int MAY = 5;
+ public static final int JUNE = 6;
+ public static final int JULY = 7;
+ public static final int AUGUST = 8;
+ public static final int SEPTEMBER = 9;
+ public static final int OCTOBER = 10;
+ public static final int NOVEMBER = 11;
+ public static final int DECEMBER = 12;
+
+ // day of week constants
+ public static final int SUNDAY = 1;
+ public static final int MONDAY = 2;
+ public static final int TUESDAY = 3;
+ public static final int WEDNESDAY = 4;
+ public static final int THURSDAY = 5;
+ public static final int FRIDAY = 6;
+ public static final int SATURDAY = 7;
+
+ // The base Gregorian year of FIXED_DATES[]
+ private static final int BASE_YEAR = 1970;
+
+ // Pre-calculated fixed dates of January 1 from BASE_YEAR
+ // (Gregorian). This table covers all the years that can be
+ // supported by the POSIX time_t (32-bit) after the Epoch. Note
+ // that the data type is int[].
+ private static final int[] FIXED_DATES = {
+ 719163, // 1970
+ 719528, // 1971
+ 719893, // 1972
+ 720259, // 1973
+ 720624, // 1974
+ 720989, // 1975
+ 721354, // 1976
+ 721720, // 1977
+ 722085, // 1978
+ 722450, // 1979
+ 722815, // 1980
+ 723181, // 1981
+ 723546, // 1982
+ 723911, // 1983
+ 724276, // 1984
+ 724642, // 1985
+ 725007, // 1986
+ 725372, // 1987
+ 725737, // 1988
+ 726103, // 1989
+ 726468, // 1990
+ 726833, // 1991
+ 727198, // 1992
+ 727564, // 1993
+ 727929, // 1994
+ 728294, // 1995
+ 728659, // 1996
+ 729025, // 1997
+ 729390, // 1998
+ 729755, // 1999
+ 730120, // 2000
+ 730486, // 2001
+ 730851, // 2002
+ 731216, // 2003
+ 731581, // 2004
+ 731947, // 2005
+ 732312, // 2006
+ 732677, // 2007
+ 733042, // 2008
+ 733408, // 2009
+ 733773, // 2010
+ 734138, // 2011
+ 734503, // 2012
+ 734869, // 2013
+ 735234, // 2014
+ 735599, // 2015
+ 735964, // 2016
+ 736330, // 2017
+ 736695, // 2018
+ 737060, // 2019
+ 737425, // 2020
+ 737791, // 2021
+ 738156, // 2022
+ 738521, // 2023
+ 738886, // 2024
+ 739252, // 2025
+ 739617, // 2026
+ 739982, // 2027
+ 740347, // 2028
+ 740713, // 2029
+ 741078, // 2030
+ 741443, // 2031
+ 741808, // 2032
+ 742174, // 2033
+ 742539, // 2034
+ 742904, // 2035
+ 743269, // 2036
+ 743635, // 2037
+ 744000, // 2038
+ 744365, // 2039
+ };
+
+ public abstract static class Date extends CalendarDate {
+ protected Date() {
+ super();
+ }
+ protected Date(TimeZone zone) {
+ super(zone);
+ }
+
+ public Date setNormalizedDate(int normalizedYear, int month, int dayOfMonth) {
+ setNormalizedYear(normalizedYear);
+ setMonth(month).setDayOfMonth(dayOfMonth);
+ return this;
+ }
+
+ public abstract int getNormalizedYear();
+
+ public abstract void setNormalizedYear(int normalizedYear);
+
+ // Cache for the fixed date of January 1 and year length of the
+ // cachedYear. A simple benchmark showed 7% performance
+ // improvement with >90% cache hit. The initial values are for Gregorian.
+ int cachedYear = 2004;
+ long cachedFixedDateJan1 = 731581L;
+ long cachedFixedDateNextJan1 = cachedFixedDateJan1 + 366;
+
+ protected final boolean hit(int year) {
+ return year == cachedYear;
+ }
+
+ protected final boolean hit(long fixedDate) {
+ return (fixedDate >= cachedFixedDateJan1 &&
+ fixedDate < cachedFixedDateNextJan1);
+ }
+ protected int getCachedYear() {
+ return cachedYear;
+ }
+
+ protected long getCachedJan1() {
+ return cachedFixedDateJan1;
+ }
+
+ protected void setCache(int year, long jan1, int len) {
+ cachedYear = year;
+ cachedFixedDateJan1 = jan1;
+ cachedFixedDateNextJan1 = jan1 + len;
+ }
+ }
+
+ public boolean validate(CalendarDate date) {
+ Date bdate = (Date) date;
+ if (bdate.isNormalized()) {
+ return true;
+ }
+ int month = bdate.getMonth();
+ if (month < JANUARY || month > DECEMBER) {
+ return false;
+ }
+ int d = bdate.getDayOfMonth();
+ if (d <= 0 || d > getMonthLength(bdate.getNormalizedYear(), month)) {
+ return false;
+ }
+ int dow = bdate.getDayOfWeek();
+ if (dow != bdate.FIELD_UNDEFINED && dow != getDayOfWeek(bdate)) {
+ return false;
+ }
+
+ if (!validateTime(date)) {
+ return false;
+ }
+
+ bdate.setNormalized(true);
+ return true;
+ }
+
+ public boolean normalize(CalendarDate date) {
+ if (date.isNormalized()) {
+ return true;
+ }
+
+ Date bdate = (Date) date;
+ TimeZone zi = bdate.getZone();
+
+ // If the date has a time zone, then we need to recalculate
+ // the calendar fields. Let getTime() do it.
+ if (zi != null) {
+ getTime(date);
+ return true;
+ }
+
+ int days = normalizeTime(bdate);
+ normalizeMonth(bdate);
+ long d = (long)bdate.getDayOfMonth() + days;
+ int m = bdate.getMonth();
+ int y = bdate.getNormalizedYear();
+ int ml = getMonthLength(y, m);
+
+ if (!(d > 0 && d <= ml)) {
+ if (d <= 0 && d > -28) {
+ ml = getMonthLength(y, --m);
+ d += ml;
+ bdate.setDayOfMonth((int) d);
+ if (m == 0) {
+ m = DECEMBER;
+ bdate.setNormalizedYear(y - 1);
+ }
+ bdate.setMonth(m);
+ } else if (d > ml && d < (ml + 28)) {
+ d -= ml;
+ ++m;
+ bdate.setDayOfMonth((int)d);
+ if (m > DECEMBER) {
+ bdate.setNormalizedYear(y + 1);
+ m = JANUARY;
+ }
+ bdate.setMonth(m);
+ } else {
+ long fixedDate = d + getFixedDate(y, m, 1, bdate) - 1L;
+ getCalendarDateFromFixedDate(bdate, fixedDate);
+ }
+ } else {
+ bdate.setDayOfWeek(getDayOfWeek(bdate));
+ }
+ date.setLeapYear(isLeapYear(bdate.getNormalizedYear()));
+ date.setZoneOffset(0);
+ date.setDaylightSaving(0);
+ bdate.setNormalized(true);
+ return true;
+ }
+
+ void normalizeMonth(CalendarDate date) {
+ Date bdate = (Date) date;
+ int year = bdate.getNormalizedYear();
+ long month = bdate.getMonth();
+ if (month <= 0) {
+ long xm = 1L - month;
+ year -= (int)((xm / 12) + 1);
+ month = 13 - (xm % 12);
+ bdate.setNormalizedYear(year);
+ bdate.setMonth((int) month);
+ } else if (month > DECEMBER) {
+ year += (int)((month - 1) / 12);
+ month = ((month - 1)) % 12 + 1;
+ bdate.setNormalizedYear(year);
+ bdate.setMonth((int) month);
+ }
+ }
+
+ /**
+ * Returns 366 if the specified date is in a leap year, or 365
+ * otherwise This method does not perform the normalization with
+ * the specified <code>CalendarDate</code>. The
+ * <code>CalendarDate</code> must be normalized to get a correct
+ * value.
+ *
+ * @param a <code>CalendarDate</code>
+ * @return a year length in days
+ * @throws ClassCastException if the specified date is not a
+ * {@link BaseCalendar.Date}
+ */
+ public int getYearLength(CalendarDate date) {
+ return isLeapYear(((Date)date).getNormalizedYear()) ? 366 : 365;
+ }
+
+ public int getYearLengthInMonths(CalendarDate date) {
+ return 12;
+ }
+
+ static final int[] DAYS_IN_MONTH
+ // 12 1 2 3 4 5 6 7 8 9 10 11 12
+ = { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+ static final int[] ACCUMULATED_DAYS_IN_MONTH
+ // 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1
+ = { -30, 0, 31, 59, 90,120,151,181,212,243, 273, 304, 334};
+
+ static final int[] ACCUMULATED_DAYS_IN_MONTH_LEAP
+ // 12/1 1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 10/1 11/1 12/1
+ = { -30, 0, 31, 59+1, 90+1,120+1,151+1,181+1,212+1,243+1, 273+1, 304+1, 334+1};
+
+ public int getMonthLength(CalendarDate date) {
+ Date gdate = (Date) date;
+ int month = gdate.getMonth();
+ if (month < JANUARY || month > DECEMBER) {
+ throw new IllegalArgumentException("Illegal month value: " + month);
+ }
+ return getMonthLength(gdate.getNormalizedYear(), month);
+ }
+
+ // accepts 0 (December in the previous year) to 12.
+ private final int getMonthLength(int year, int month) {
+ int days = DAYS_IN_MONTH[month];
+ if (month == FEBRUARY && isLeapYear(year)) {
+ days++;
+ }
+ return days;
+ }
+
+ public long getDayOfYear(CalendarDate date) {
+ return getDayOfYear(((Date)date).getNormalizedYear(),
+ date.getMonth(),
+ date.getDayOfMonth());
+ }
+
+ final long getDayOfYear(int year, int month, int dayOfMonth) {
+ return (long) dayOfMonth
+ + (isLeapYear(year) ?
+ ACCUMULATED_DAYS_IN_MONTH_LEAP[month] : ACCUMULATED_DAYS_IN_MONTH[month]);
+ }
+
+ // protected
+ public long getFixedDate(CalendarDate date) {
+ if (!date.isNormalized()) {
+ normalizeMonth(date);
+ }
+ return getFixedDate(((Date)date).getNormalizedYear(),
+ date.getMonth(),
+ date.getDayOfMonth(),
+ (BaseCalendar.Date) date);
+ }
+
+ // public for java.util.GregorianCalendar
+ public long getFixedDate(int year, int month, int dayOfMonth, BaseCalendar.Date cache) {
+ boolean isJan1 = month == JANUARY && dayOfMonth == 1;
+
+ // Look up the one year cache
+ if (cache != null && cache.hit(year)) {
+ if (isJan1) {
+ return cache.getCachedJan1();
+ }
+ return cache.getCachedJan1() + getDayOfYear(year, month, dayOfMonth) - 1;
+ }
+
+ // Look up the pre-calculated fixed date table
+ int n = year - BASE_YEAR;
+ if (n >= 0 && n < FIXED_DATES.length) {
+ long jan1 = FIXED_DATES[n];
+ if (cache != null) {
+ cache.setCache(year, jan1, isLeapYear(year) ? 366 : 365);
+ }
+ return isJan1 ? jan1 : jan1 + getDayOfYear(year, month, dayOfMonth) - 1;
+ }
+
+ long prevyear = (long)year - 1;
+ long days = dayOfMonth;
+
+ if (prevyear >= 0) {
+ days += (365 * prevyear)
+ + (prevyear / 4)
+ - (prevyear / 100)
+ + (prevyear / 400)
+ + ((367 * month - 362) / 12);
+ } else {
+ days += (365 * prevyear)
+ + CalendarUtils.floorDivide(prevyear, 4)
+ - CalendarUtils.floorDivide(prevyear, 100)
+ + CalendarUtils.floorDivide(prevyear, 400)
+ + CalendarUtils.floorDivide((367 * month - 362), 12);
+ }
+
+ if (month > FEBRUARY) {
+ days -= isLeapYear(year) ? 1 : 2;
+ }
+
+ // If it's January 1, update the cache.
+ if (cache != null && isJan1) {
+ cache.setCache(year, days, isLeapYear(year) ? 366 : 365);
+ }
+
+ return days;
+ }
+
+ /**
+ * Calculates calendar fields and store them in the specified
+ * <code>CalendarDate</code>.
+ */
+ // should be 'protected'
+ public void getCalendarDateFromFixedDate(CalendarDate date,
+ long fixedDate) {
+ Date gdate = (Date) date;
+ int year;
+ long jan1;
+ boolean isLeap;
+ if (gdate.hit(fixedDate)) {
+ year = gdate.getCachedYear();
+ jan1 = gdate.getCachedJan1();
+ isLeap = isLeapYear(year);
+ } else {
+ // Looking up FIXED_DATES[] here didn't improve performance
+ // much. So we calculate year and jan1. getFixedDate()
+ // will look up FIXED_DATES[] actually.
+ year = getGregorianYearFromFixedDate(fixedDate);
+ jan1 = getFixedDate(year, JANUARY, 1, null);
+ isLeap = isLeapYear(year);
+ // Update the cache data
+ gdate.setCache (year, jan1, isLeap ? 366 : 365);
+ }
+
+ int priorDays = (int)(fixedDate - jan1);
+ long mar1 = jan1 + 31 + 28;
+ if (isLeap) {
+ ++mar1;
+ }
+ if (fixedDate >= mar1) {
+ priorDays += isLeap ? 1 : 2;
+ }
+ int month = 12 * priorDays + 373;
+ if (month > 0) {
+ month /= 367;
+ } else {
+ month = CalendarUtils.floorDivide(month, 367);
+ }
+ long month1 = jan1 + ACCUMULATED_DAYS_IN_MONTH[month];
+ if (isLeap && month >= MARCH) {
+ ++month1;
+ }
+ int dayOfMonth = (int)(fixedDate - month1) + 1;
+ int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate);
+ assert dayOfWeek > 0 : "negative day of week " + dayOfWeek;
+ gdate.setNormalizedYear(year);
+ gdate.setMonth(month);
+ gdate.setDayOfMonth(dayOfMonth);
+ gdate.setDayOfWeek(dayOfWeek);
+ gdate.setLeapYear(isLeap);
+ gdate.setNormalized(true);
+ }
+
+ /**
+ * Returns the day of week of the given Gregorian date.
+ */
+ public int getDayOfWeek(CalendarDate date) {
+ long fixedDate = getFixedDate(date);
+ return getDayOfWeekFromFixedDate(fixedDate);
+ }
+
+ public static final int getDayOfWeekFromFixedDate(long fixedDate) {
+ // The fixed day 1 (January 1, 1 Gregorian) is Monday.
+ if (fixedDate >= 0) {
+ return (int)(fixedDate % 7) + SUNDAY;
+ }
+ return (int)CalendarUtils.mod(fixedDate, 7) + SUNDAY;
+ }
+
+ public int getYearFromFixedDate(long fixedDate) {
+ return getGregorianYearFromFixedDate(fixedDate);
+ }
+
+ /**
+ * Returns the Gregorian year number of the given fixed date.
+ */
+ final int getGregorianYearFromFixedDate(long fixedDate) {
+ long d0;
+ int d1, d2, d3, d4;
+ int n400, n100, n4, n1;
+ int year;
+
+ if (fixedDate > 0) {
+ d0 = fixedDate - 1;
+ n400 = (int)(d0 / 146097);
+ d1 = (int)(d0 % 146097);
+ n100 = d1 / 36524;
+ d2 = d1 % 36524;
+ n4 = d2 / 1461;
+ d3 = d2 % 1461;
+ n1 = d3 / 365;
+ d4 = (d3 % 365) + 1;
+ } else {
+ d0 = fixedDate - 1;
+ n400 = (int)CalendarUtils.floorDivide(d0, 146097L);
+ d1 = (int)CalendarUtils.mod(d0, 146097L);
+ n100 = CalendarUtils.floorDivide(d1, 36524);
+ d2 = CalendarUtils.mod(d1, 36524);
+ n4 = CalendarUtils.floorDivide(d2, 1461);
+ d3 = CalendarUtils.mod(d2, 1461);
+ n1 = CalendarUtils.floorDivide(d3, 365);
+ d4 = CalendarUtils.mod(d3, 365) + 1;
+ }
+ year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
+ if (!(n100 == 4 || n1 == 4)) {
+ ++year;
+ }
+ return year;
+ }
+
+ /**
+ * @return true if the specified year is a Gregorian leap year, or
+ * false otherwise.
+ * @see BaseCalendar#isGregorianLeapYear
+ */
+ protected boolean isLeapYear(CalendarDate date) {
+ return isLeapYear(((Date)date).getNormalizedYear());
+ }
+
+ boolean isLeapYear(int normalizedYear) {
+ return CalendarUtils.isGregorianLeapYear(normalizedYear);
+ }
+}
Added: trunk/core/src/openjdk/sun/sun/util/calendar/CalendarDate.java
===================================================================
--- trunk/core/src/openjdk/sun/sun/util/calendar/CalendarDate.java (rev 0)
+++ trunk/core/src/openjdk/sun/sun/util/calendar/CalendarDate.java 2007-06-23 05:02:03 UTC (rev 3292)
@@ -0,0 +1,505 @@
+/*
+ * Copyright 2000-2003 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.util.calendar;
+
+import java.lang.Cloneable;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * The <code>CalendarDate</code> class represents a specific instant
+ * in time by calendar date and time fields that are multiple cycles
+ * in different time unites. The semantics of each calendar field is
+ * given by a concrete calendar system rather than this
+ * <code>CalendarDate</code> class that holds calendar field values
+ * without interpreting them. Therefore, this class can be used to
+ * represent an amount of time, such as 2 years and 3 months.
+ *
+ * <p>A <code>CalendarDate</code> instance can be created by calling
+ * the <code>newCalendarDate</code> or <code>getCalendarDate</code>
+ * methods in <code>CalendarSystem</code>. A
+ * <code>CalendarSystem</code> instance is obtained by calling one of
+ * the factory methods in <code>CalendarSystem</code>. Manipulations
+ * of calendar dates must be handled by the calendar system by which
+ * <code>CalendarDate</code> instances have been created.
+ *
+ * <p>Some calendar fields can be modified through method calls. Any
+ * modification of a calendar field brings the state of a
+ * <code>CalendarDate</code> to <I>not normalized</I>. The
+ * normalization must be performed to make all the calendar fields
+ * consistent with a calendar system.
+ *
+ * <p>The <code>protected</code> methods are intended to be used for
+ * implementing a concrete calendar system, not for general use as an
+ * API.
+ *
+ * @see CalendarSystem
+ * @author Masayoshi Okutsu
+ * @since 1.5
+ */
+public abstract class CalendarDate implements Cloneable {
+ public static final int FIELD_UNDEFINED = Integer.MIN_VALUE;
+ public static final long TIME_UNDEFINED = Long.MIN_VALUE;
+
+ private Era era;
+ private int year;
+ private int month;
+ private int dayOfMonth;
+ private int dayOfWeek = FIELD_UNDEFINED;
+ private boolean leapYear;
+
+ private int hours;
+ private int minutes;
+ private int seconds;
+ private int millis; // fractional part of the second
+ private long fraction; // time of day value in millisecond
+
+ private boolean normalized;
+
+ private TimeZone zoneinfo;
+ private int zoneOffset;
+ private int daylightSaving;
+ private boolean forceStandardTime;
+
+ private Locale locale;
+
+ protected CalendarDate() {
+ this(TimeZone.getDefault());
+ }
+
+ protected CalendarDate(TimeZone zone) {
+ zoneinfo = zone;
+ }
+
+ public Era getEra() {
+ return era;
+ }
+
+ /**
+ * Sets the era of the date to the specified era. The default
+ * implementation of this method accepts any Era value, including
+ * <code>null</code>.
+ *
+ * @exception NullPointerException if the calendar system for this
+ * <code>CalendarDate</code> requires eras and the specified era
+ * is null.
+ * @exception IllegalArgumentException if the specified
+ * <code>era</code> is unknown to the calendar
+ * system for this <code>CalendarDate</code>.
+ */
+ public CalendarDate setEra(Era era) {
+ if (this.era == era) {
+ return this;
+ }
+ this.era = era;
+ normalized = false;
+ return this;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public CalendarDate setYear(int year) {
+ if (this.year != year) {
+ this.year = year;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addYear(int n) {
+ if (n != 0) {
+ year += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ /**
+ * Returns whether the year represented by this
+ * <code>CalendarDate</code> is a leap year. If leap years are
+ * not applicable to the calendar system, this method always
+ * returns <code>false</code>.
+ *
+ * <p>If this <code>CalendarDate</code> hasn't been normalized,
+ * <code>false</code> is returned. The normalization must be
+ * performed to retrieve the correct leap year information.
+ *
+ * @return <code>true</code> if this <code>CalendarDate</code> is
+ * normalized and the year of this <code>CalendarDate</code> is a
+ * leap year, or <code>false</code> otherwise.
+ * @see BaseCalendar#isGregorianLeapYear
+ */
+ public boolean isLeapYear() {
+ return leapYear;
+ }
+
+ void setLeapYear(boolean leapYear) {
+ this.leapYear = leapYear;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public CalendarDate setMonth(int month) {
+ if (this.month != month) {
+ this.month = month;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addMonth(int n) {
+ if (n != 0) {
+ month += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public int getDayOfMonth() {
+ return dayOfMonth;
+ }
+
+ public CalendarDate setDayOfMonth(int date) {
+ if (dayOfMonth != date) {
+ dayOfMonth = date;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addDayOfMonth(int n) {
+ if (n != 0) {
+ dayOfMonth += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ /**
+ * Returns the day of week value. If this CalendarDate is not
+ * normalized, {@link #FIELD_UNDEFINED} is returned.
+ *
+ * @return day of week or {@link #FIELD_UNDEFINED}
+ */
+ public int getDayOfWeek() {
+ if (!isNormalized()) {
+ dayOfWeek = FIELD_UNDEFINED;
+ }
+ return dayOfWeek;
+ }
+
+ public int getHours() {
+ return hours;
+ }
+
+ public CalendarDate setHours(int hours) {
+ if (this.hours != hours) {
+ this.hours = hours;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addHours(int n) {
+ if (n != 0) {
+ hours += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public int getMinutes() {
+ return minutes;
+ }
+
+ public CalendarDate setMinutes(int minutes) {
+ if (this.minutes != minutes) {
+ this.minutes = minutes;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addMinutes(int n) {
+ if (n != 0) {
+ minutes += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public int getSeconds() {
+ return seconds;
+ }
+
+ public CalendarDate setSeconds(int seconds) {
+ if (this.seconds != seconds) {
+ this.seconds = seconds;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addSeconds(int n) {
+ if (n != 0) {
+ seconds += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public int getMillis() {
+ return millis;
+ }
+
+ public CalendarDate setMillis(int millis) {
+ if (this.millis != millis) {
+ this.millis = millis;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public CalendarDate addMillis(int n) {
+ if (n != 0) {
+ millis += n;
+ normalized = false;
+ }
+ return this;
+ }
+
+ public long getTimeOfDay() {
+ if (!isNormalized()) {
+ return fraction = TIME_UNDEFINED;
+ }
+ return fraction;
+ }
+
+ public CalendarDate setDate(int year, int month, int dayOfMonth) {
+ setYear(year);
+ setMonth(month);
+ setDayOfMonth(dayOfMonth);
+ return this;
+ }
+
+ public CalendarDate addDate(int year, int month, int dayOfMonth) {
+ addYear(year);
+ addMonth(month);
+ addDayOfMonth(dayOfMonth);
+ return this;
+ }
+
+ public CalendarDate setTimeOfDay(int hours, int minutes, int seconds, int millis) {
+ setHours(hours);
+ setMinutes(minutes);
+ setSeconds(seconds);
+ setMillis(millis);
+ return this;
+ }
+
+ public CalendarDate addTimeOfDay(int hours, int minutes, int seconds, int millis) {
+ addHours(hours);
+ addMinutes(minutes);
+ addSeconds(seconds);
+ addMillis(millis);
+ return this;
+ }
+
+ protected void setTimeOfDay(long fraction) {
+ this.fraction = fraction;
+ }
+
+ public boolean isNormalized() {
+ return normalized;
+ }
+
+
+ public boolean isStandardTime() {
+ return forceStandardTime;
+ }
+
+ public void setStandardTime(boolean standardTime) {
+ forceStandardTime = standardTime;
+ }
+
+ public boolean isDaylightTime() {
+ if (isStandardTime()) {
+ return false;
+ }
+ return daylightSaving != 0;
+ }
+
+ protected void setLocale(Locale loc) {
+ locale = loc;
+ }
+
+ public TimeZone getZone() {
+ return zoneinfo;
+ }
+
+ public CalendarDate setZone(TimeZone zoneinfo) {
+ this.zoneinfo = zoneinfo;
+ return this;
+ }
+
+ /**
+ * Returns whether the specified date is the same date of this
+ * <code>CalendarDate</code>. The time of the day fields are
+ * ignored for the comparison.
+ */
+ public boolean isSameDate(CalendarDate date) {
+ return getDayOfWeek() == date.getDayOfWeek()
+ && getMonth() == date.getMonth()
+ && getYear() == date.getYear()
+ && getEra() == date.getEra();
+ }
+
+ public boolean equals(Object obj) {
+ if (!(obj instanceof CalendarDate)) {
+ return false;
+ }
+ CalendarDate that = (CalendarDate) obj;
+ if (isNormalized() != that.isNormalized()) {
+ return false;
+ }
+ boolean hasZone = zoneinfo != null;
+ boolean thatHasZone = that.zoneinfo != null;
+ if (hasZone != thatHasZone) {
+ return false;
+ }
+ if (hasZone && !zoneinfo.equals(that.zoneinfo)) {
+ return false;
+ }
+ return (getEra() == that.getEra()
+ && year == that.year
+ && month == that.month
+ && dayOfMonth == that.dayOfMonth
+ && hours == that.hours
+ && minutes == that.minutes
+ && seconds == that.seconds
+ && millis == that.millis
+ && zoneOffset == that.zoneOffset);
+ }
+
+ public int hashCode() {
+ // a pseudo (local standard) time stamp value in milliseconds
+ // from the Epoch, assuming Gregorian calendar fields.
+ long hash = ((((((long)year - 1970) * 12) + (month - 1)) * 30) + dayOfMonth) * 24;
+ hash = ((((((hash + hours) * 60) + minutes) * 60) + seconds) * 1000) + millis;
+ hash -= zoneOffset;
+ int normalized = isNormalized() ? 1 : 0;
+ int era = 0;
+ Era e = getEra();
+ if (e != null) {
+ era = e.hashCode();
+ }
+ int zone = zoneinfo != null ? zoneinfo.hashCode() : 0;
+ return (int) hash * (int)(hash >> 32) ^ era ^ normalized ^ zone;
+ }
+
+ /**
+ * Returns a copy of this <code>CalendarDate</code>. The
+ * <code>TimeZone</code> object, if any, is not cloned.
+ *
+ * @return a copy of this <code>CalendarDate</code>
+ */
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ // this shouldn't happen
+ throw new InternalError();
+ }
+ }
+
+ /**
+ * Converts calendar date values to a <code>String</code> in the
+ * following format.
+ * <pre>
+ * yyyy-MM-dd'T'HH:mm:ss.SSSz
+ * </pre>
+ *
+ * @see java.text.SimpleDateFormat
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ CalendarUtils.sprintf0d(sb, year, 4).append('-');
+ CalendarUtils.sprintf0d(sb, month, 2).append('-');
+ CalendarUtils.sprintf0d(sb, dayOfMonth, 2).append('T');
+ CalendarUtils.sprintf0d(sb, hours, 2).append(':');
+ CalendarUtils.sprintf0d(sb, minutes, 2).append(':');
+ CalendarUtils.sprintf0d(sb, seconds, 2).append('.');
+ CalendarUtils.sprintf0d(sb, millis, 3);
+ if (zoneOffset == 0) {
+ sb.append('Z');
+ } else if (zoneOffset != FIELD_UNDEFINED) {
+ int offset;
+ char sign;
+ if (zoneOffset > 0) {
+ offset = zoneOffset;
+ sign = '+';
+ } else {
+ offset = -zoneOffset;
+ sign = '-';
+ }
+ offset /= 60000;
+ sb.append(sign);
+ CalendarUtils.sprintf0d(sb, offset / 60, 2);
+ CalendarUtils.sprintf0d(sb, offset % 60, 2);
+ } else {
+ sb.append(" local time");
+ }
+ return sb.toString();
+ }
+
+ protected void setDayOfWeek(int dayOfWeek) {
+ this.dayOfWeek = dayOfWeek;
+ }
+
+ protected void setNormalized(boolean normalized) {
+ this.normalized = normalized;
+ }
+
+ public int getZoneOffset() {
+ return zoneOffset;
+ }
+
+ protected void setZoneOffset(int offset) {
+ zoneOffset = offset;
+ }
+
+ public int getDaylightSaving() {
+ return daylightSaving;
+ }
+
+ protected void setDaylightSaving(int daylightSaving) {
+ this.daylightSaving = daylightSaving;
+ }
+}
Added: trunk/core/src/openjdk/sun/sun/util/calendar/CalendarSystem.java
===================================================================
--- trunk/core/src/openjdk/sun/sun/util/calendar/CalendarSystem.java (rev 0)
+++ trunk/core/src/openjdk/sun/sun/util/calendar/CalendarSystem.java 2007-06-23 05:02:03 UTC (rev 3292)
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.util.calendar;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * <code>CalendarSystem</code> is an abstract class that defines the
+ * programming interface to deal with calendar date and time.
+ *
+ * <p><code>CalendarSystem</code> instances are singletons. For
+ * example, there exists only one Gregorian calendar instance in the
+ * Java runtime environment. A singleton instance can be obtained
+ * calling one of the static factory methods.
+ *
+ * <h4>CalendarDate</h4>
+ *
+ * <p>For the methods in a <code>CalendarSystem</code> that manipulate
+ * a <code>CalendarDate</code>, <code>CalendarDate</code>s that have
+ * been created by the <code>CalendarSystem</code> must be
+ * specified. Otherwise, the methods throw an exception. This is
+ * because, for example, a Chinese calendar date can't be understood
+ * by the Hebrew calendar system.
+ *
+ * <h4>Calendar names</h4>
+ *
+ * Each calendar system has a unique name to be identified. The Java
+ * runtime in this release supports the following calendar systems.
+ *
+ * <pre>
+ * Name Calendar System
+ * ---------------------------------------
+ * gregorian Gregorian Calendar
+ * julian Julian Calendar
+ * japanese Japanese Imperial Calendar
+ * </pre>
+ *
+ * @see CalendarDate
+ * @author Masayoshi Okutsu
+ * @since 1.5
+ */
+
+public abstract class CalendarSystem {
+
+ /////////////////////// Calendar Factory Methods /////////////////////////
+
+ private volatile static boolean initialized = false;
+
+ // Map of calendar names and calendar class names
+ private static ConcurrentMap<String, String> names;
+
+ // Map of calendar names and CalendarSystem instances
+ private static ConcurrentMap<String,CalendarSystem> calendars;
+
+ private static final String PACKAGE_NAME = "sun.util.calendar.";
+
+ private static final String[] namePairs = {
+ "gregorian", "Gregorian",
+ "japanese", "LocalGregorianCalendar",
+ "julian", "JulianCalendar",
+ /*
+ "hebrew", "HebrewCalendar",
+ "iso8601", "ISOCalendar",
+ "taiwanese", "LocalGregorianCalendar",
+ "thaibuddhist", "LocalGregorianCalendar",
+ */
+ };
+
+ private static void initNames() {
+ ConcurrentMap<String,String> nameMap = new ConcurrentHashMap<String,String>();
+
+ // Associate a calendar name with its class name and the
+ // calendar class name with its date class name.
+ StringBuilder clName = new StringBuilder();
+ for (int i = 0; i < namePairs.length; i += 2) {
+ clName.setLength(0);
+ String cl = clName.append(PACKAGE_NAME).append(namePairs[i+1]).toString();
+ nameMap.put(namePairs[i], cl);
+ }
+ synchronized (CalendarSystem.class) {
+ if (!initialized) {
+ names = nameMap;
+ calendars = new ConcurrentHashMap<String,CalendarSystem>();
+ initialized = true;
+ }
+ }
+ }
+
+ private final static Gregorian GREGORIAN_INSTANCE = new Gregorian();
+
+ /**
+ * Returns the singleton instance of the <code>Gregorian</code>
+ * calendar system.
+ *
+ * @return the <code>Gregorian</code> instance
+ */
+ public static Gregorian getGregorianCalendar() {
+ return GREGORIAN_INSTANCE;
+ }
+
+ /**
+ * Returns a <code>CalendarSystem</code> specified by the calendar
+ * name. The calendar name has to be one of the supported calendar
+ * names.
+ *
+ * @param calendarName the calendar name
+ * @return the <code>CalendarSystem</code> specified by
+ * <code>calendarName</code>, or null if there is no
+ * <code>CalendarSystem</code> associated with the given calendar name.
+ */
+ public static CalendarSystem forName(String calendarName) {
+ if ("gregorian".equals(calendarName)) {
+ return GREGORIAN_INSTANCE;
+ }
+
+ if (!initialized) {
+ initNames();
+ }
+
+ CalendarSystem cal = calendars.get(calendarName);
+ if (cal != null) {
+ return cal;
+ }
+
+ String className = names.get(calendarName);
+ if (className == null) {
+ return null; // Unknown calendar name
+ }
+
+ if (className.endsWith("LocalGregorianCalendar")) {
+ // Create the specific kind of local Gregorian calendar system
+ cal = LocalGregorianCalendar.getLocalGregorianCalendar(calendarName);
+ } else {
+ try {
+ Class cl = Class.forName(className);
+ cal = (CalendarSystem) cl.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException("internal error", e);
+ }
+ }
+ if (cal == null) {
+ return null;
+ }
+ CalendarSystem cs = calendars.putIfAbsent(calendarName, cal);
+ return (cs == null) ? cal : cs;
+ }
+
+ //////////////////////////////// Calendar API //////////////////////////////////
+
+ /**
+ * Returns the name of this calendar system.
+ */
+ public abstract String getName();
+
+ public abstract CalendarDate getCalendarDate();
+
+ /**
+ * Calculates calendar fields from the specified number of
+ * milliseconds since the Epoch, January 1, 1970 00:00:00 UTC
+ * (Gregorian). This method doesn't check overflow or underflow
+ * when adjusting the millisecond value (representing UTC) with
+ * the time zone offsets (i.e., the GMT offset and amount of
+ * daylight saving).
+ *
+ * @param millis the offset value in milliseconds from January 1,
+ * 1970 00:00:00 UTC (Gregorian).
+ * @return a <code>CalendarDate</code> instance that contains the
+ * calculated calendar field values.
+ */
+ public abstract CalendarDate getCalendarDate(long millis);
+
+ public abstract CalendarDate getCalendarDate(long millis, CalendarDate date);
+
+ public abstract CalendarDate getCalendarDate(long millis, TimeZone zone);
+
+ /**
+ * Constructs a <code>CalendarDate</code> that is specific to this
+ * calendar system. All calendar fields have their initial
+ * values. The {@link TimeZone#getDefault() default time zone} is
+ * set to the instance.
+ *
+ * @return a <code>CalendarDate</code> instance that contains the initial
+ * calendar field values.
+ */
+ public abstract CalendarDate newCalendarDate();
+
+ public abstract CalendarDate newCalendarDate(TimeZone zone);
+
+ /**
+ * Returns the number of milliseconds since the Epoch, January 1,
+ * 1970 00:00:00 UTC (Gregorian), represented by the specified
+ * <code>CalendarDate</code>.
+ *
+ * @param date the <code>CalendarDate</code> from which the time
+ * value is calculated
+ * @return the number of milliseconds since the Epoch.
+ */
+ public abstract long getTime(CalendarDate date);
+
+ /**
+ * Returns the length in days of the specified year by
+ * <code>date</code>. This method does not perform the
+ * normalization with the specified <code>CalendarDate</code>. The
+ * <code>CalendarDate</code> must be normalized to get a correct
+ * value.
+ */
+ public abstract int getYearLength(CalendarDate date);
+
+ /**
+ * Returns the number of months of the specified year. This method
+ * does not perform the normalization with the specified
+ * <code>CalendarDate</code>. The <code>CalendarDate</code> must
+ * be normalized to get a correct value.
+ */
+ public abstract int getYearLengthInMonths(CalendarDate date);
+
+ /**
+ * Returns the length in days of the month specified by the calendar
+ * date. This method does not perform the normalization with the
+ * specified calendar date. The <code>CalendarDate</code> must
+ * be normalized to get a correct value.
+ *
+ * @param date the date from which the month value is obtained
+ * @return the number of days in the month
+ * @exception IllegalArgumentException if the specified calendar date
+ * doesn't have a valid month value in this calendar system.
+ */
+ public abstract int getMonthLength(CalendarDate date); // no setter
+
+ /**
+ * Returns the length in days of a week in this calendar
+ * system. If this calendar system has multiple radix weeks, this
+ * method returns only one of them.
+ */
+ public abstract int getWeekLength();
+
+ /**
+ * Returns the <code>Era</code> designated by the era name that
+ * has to be known to this calendar system. If no Era is
+ * applicable to this calendar system, null is returned.
+ *
+ * @param eraName the name of the era
+ * @return the <code>Era</code> designated by
+ * <code>eraName</code>, or <code>null</code> if no Era is
+ * applicable to this calendar system or the specified era name is
+ * not known to this calendar system.
+ */
+ public abstract Era getEra(String eraName);
+
+ /**
+ * Returns valid <code>Era</code>s of this calendar system. The
+ * return value is sorted in the descendant order. (i.e., the first
+ * element of the returned array is the oldest era.) If no era is
+ * applicable to this calendar system, <code>null</code> is returned.
+ *
+ * @return an array of valid <code>Era</code>s, or
+ * <code>null</code> if no era is applicable to this calendar
+ * system.
+ */
+ public abstract Era[] getEras();
+
+ /**
+ * @throws IllegalArgumentException if the specified era name is
+ * unknown to this calendar system.
+ * @see Era
+ */
+ public abstract void setEra(CalendarDate date, String eraName);
+
+ /**
+ * Returns a <code>CalendarDate</code> of the n-th day of week
+ * which is on, after or before the specified date. For example, the
+ * first Sunday in April 2002 (Gregorian) can be obtained as
+ * below:
+ *
+ * <pre><code>
+ * Gregorian cal = CalendarSystem.getGregorianCalendar();
+ * CalendarDate date = cal.newCalendarDate();
+ * date.setDate(2004, cal.APRIL, 1);
+ * CalendarDate firstSun = cal.getNthDayOfWeek(1, cal.SUNDAY, date);
+ * // firstSun represents April 4, 2004.
+ * </code></pre>
+ *
+ * This method returns a new <code>CalendarDate</code> instance
+ * and doesn't modify the original date.
+ *
+ * @param nth specifies the n-th one. A positive number specifies
+ * <em>on or after</em> the <code>date</code>. A non-positive number
+ * specifies <em>on or before</em> the <code>date</code>.
+ * @param dayOfWeek the day of week
+ * @param date the date
+ * @return the date of the nth <code>dayOfWeek</code> after
+ * or before the specified <code>CalendarDate</code>
+ */
+ public abstract CalendarDate getNthDayOfWeek(int nth, int dayOfWeek,
+ CalendarDate date);
+
+ public abstract CalendarDate setTimeOfDay(CalendarDate date, int timeOfDay);
+
+ /**
+ * Checks whether the calendar fields specified by <code>date</code>
+ * represents a valid date and time in this calendar system. If the
+ * given date is valid, <code>date</code> is marked as <em>normalized</em>.
+ *
+ * @param date the <code>CalendarDate</code> to be validated
+ * @return <code>true</code> if all the calendar fields are consistent,
+ * otherwise, <code>false</code> is returned.
+ * @exception NullPointerException if the specified
+ * <code>date</code> is <code>null</code>
+ */
+ public abstract boolean validate(CalendarDate date);
+
+ /**
+ * Normalizes calendar fields in the specified
+ * <code>date</code>. Also all {@link CalendarDate#FIELD_UNDEFINED
+ * undefined} fields are set to correct values. The actual
+ * normalization process is calendar system dependent.
+ *
+ * @param date the calendar date to be validated
+ * @return <code>true</code> if all fields have been normalized;
+ * <code>false</code> otherwise.
+ * @exception NullPointerException if the specified
+ * <code>date</code> is <code>null</code>
+ */
+ public abstract boolean normalize(CalendarDate date);
+}
Added: trunk/core/src/openjdk/sun/sun/util/calendar/CalendarUtils.java
===================================================================
--- trunk/core/src/openjdk/sun/sun/util/calendar/CalendarUtils.java (rev 0)
+++ trunk/core/src/openjdk/sun/sun/util/calendar/CalendarUtils.java 2007-06-23 05:02:03 UTC (rev 3292)
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.util.calendar;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CalendarUtils {
+
+ /**
+ * Returns whether the specified year is a leap year in the Gregorian
+ * calendar system.
+ *
+ * @param gregorianYear a Gregorian calendar year
+ * @return true if the given year is a leap year in the Gregorian
+ * calendar system.
+ * @see CalendarDate#isLeapYear
+ */
+ public static final boolean isGregorianLeapYear(int gregorianYear) {
+ return (((gregorianYear % 4) == 0)
+ && (((gregorianYear % 100) != 0) || ((gregorianYear % 400) == 0)));
+ }
+
+ /**
+ * Returns whether the specified year is a leap year in the Julian
+ * calendar system. The year number must be a normalized one
+ * (e.g., 45 B.C.E. is 1-45).
+ *
+ * @param normalizedJulianYear a normalized Julian calendar year
+ * @return true if the given year is a leap year in the Julian
+ * calendar system.
+ * @see CalendarDate#isLeapYear
+ */
+ public static final boolean isJulianLeapYear(int normalizedJulianYear) {
+ return (normalizedJulianYear % 4) == 0;
+ }
+
+ /**
+ * Divides two integers and returns the floor of the quotient.
+ * For example, <code>floorDivide(-1, 4)</code> returns -1 while
+ * -1/4 is 0.
+ *
+ * @param n the numerator
+ * @param d a divisor that must be greater than 0
+ * @return the floor of the quotient
+ */
+ public static final long floorDivide(long n, long d) {
+ return ((n >= 0) ?
+ (n / d) : (((n + 1L) / d) - 1L));
+ }
+
+ /**
+ * Divides two integers and returns the floor of the quotient.
+ * For example, <code>floorDivide(-1, 4)</code> returns -1 while
+ * -1/4 is 0.
+ *
+ * @param n the numerator
+ * @param d a divisor that must be greater than 0
+ * @return the floor of the quotient
+ */
+ public static final int floorDivide(int n, int d) {
+ return...
[truncated message content] |