feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,398 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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;
}
}

View File

@@ -0,0 +1,537 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
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 != Date.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 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);
}
}

View File

@@ -0,0 +1,505 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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(e);
}
}
/**
* 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;
}
}

View File

@@ -0,0 +1,395 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Properties;
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<>();
// 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<>();
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 InternalError(e);
}
}
if (cal == null) {
return null;
}
CalendarSystem cs = calendars.putIfAbsent(calendarName, cal);
return (cs == null) ? cal : cs;
}
/**
* Returns a {@link Properties} loaded from lib/calendars.properties.
*
* @return a {@link Properties} loaded from lib/calendars.properties
* @throws IOException if an error occurred when reading from the input stream
* @throws IllegalArgumentException if the input stream contains any malformed
* Unicode escape sequences
*/
public static Properties getCalendarProperties() throws IOException {
Properties calendarProps = null;
try {
String homeDir = AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("java.home"));
final String fname = homeDir + File.separator + "lib" + File.separator
+ "calendars.properties";
calendarProps = AccessController.doPrivileged(new PrivilegedExceptionAction<Properties>() {
@Override
public Properties run() throws IOException {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream(fname)) {
props.load(fis);
}
return props;
}
});
} catch (PrivilegedActionException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
} else if (cause instanceof IllegalArgumentException) {
throw (IllegalArgumentException) cause;
}
// Should not happen
throw new InternalError(cause);
}
return calendarProps;
}
//////////////////////////////// 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);
}

View File

@@ -0,0 +1,193 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.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 ((n >= 0) ?
(n / d) : (((n + 1) / d) - 1));
}
/**
* Divides two integers and returns the floor of the quotient and
* the modulus remainder. For example,
* <code>floorDivide(-1,4)</code> returns <code>-1</code> with
* <code>3</code> as its remainder, while <code>-1/4</code> is
* <code>0</code> and <code>-1%4</code> is <code>-1</code>.
*
* @param n the numerator
* @param d a divisor which must be > 0
* @param r an array of at least one element in which the value
* <code>mod(n, d)</code> is returned.
* @return the floor of the quotient.
*/
public static final int floorDivide(int n, int d, int[] r) {
if (n >= 0) {
r[0] = n % d;
return n / d;
}
int q = ((n + 1) / d) - 1;
r[0] = n - (q * d);
return q;
}
/**
* Divides two integers and returns the floor of the quotient and
* the modulus remainder. For example,
* <code>floorDivide(-1,4)</code> returns <code>-1</code> with
* <code>3</code> as its remainder, while <code>-1/4</code> is
* <code>0</code> and <code>-1%4</code> is <code>-1</code>.
*
* @param n the numerator
* @param d a divisor which must be > 0
* @param r an array of at least one element in which the value
* <code>mod(n, d)</code> is returned.
* @return the floor of the quotient.
*/
public static final int floorDivide(long n, int d, int[] r) {
if (n >= 0) {
r[0] = (int)(n % d);
return (int)(n / d);
}
int q = (int)(((n + 1) / d) - 1);
r[0] = (int)(n - (q * d));
return q;
}
public static final long mod(long x, long y) {
return (x - y * floorDivide(x, y));
}
public static final int mod(int x, int y) {
return (x - y * floorDivide(x, y));
}
public static final int amod(int x, int y) {
int z = mod(x, y);
return (z == 0) ? y : z;
}
public static final long amod(long x, long y) {
long z = mod(x, y);
return (z == 0) ? y : z;
}
/**
* Mimics sprintf(buf, "%0*d", decaimal, width).
*/
public static final StringBuilder sprintf0d(StringBuilder sb, int value, int width) {
long d = value;
if (d < 0) {
sb.append('-');
d = -d;
--width;
}
int n = 10;
for (int i = 2; i < width; i++) {
n *= 10;
}
for (int i = 1; i < width && d < n; i++) {
sb.append('0');
n /= 10;
}
sb.append(d);
return sb;
}
public static final StringBuffer sprintf0d(StringBuffer sb, int value, int width) {
long d = value;
if (d < 0) {
sb.append('-');
d = -d;
--width;
}
int n = 10;
for (int i = 2; i < width; i++) {
n *= 10;
}
for (int i = 1; i < width && d < n; i++) {
sb.append('0');
n /= 10;
}
sb.append(d);
return sb;
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.Locale;
import java.util.TimeZone;
/**
* The class <code>Era</code> represents a calendar era that defines a
* period of time in which the same year numbering is used. For
* example, Gregorian year 2004 is <I>Heisei</I> 16 in the Japanese
* calendar system. An era starts at any point of time (Gregorian) that is
* represented by <code>CalendarDate</code>.
*
* <p><code>Era</code>s that are applicable to a particular calendar
* system can be obtained by calling {@link CalendarSystem#getEras}
* one of which can be used to specify a date in
* <code>CalendarDate</code>.
*
* <p>The following era names are defined in this release.
* <pre>{@code
* Calendar system Era name Since (in Gregorian)
* -----------------------------------------------------------------------
* Japanese calendar Meiji 1868-01-01T00:00:00 local time
* Taisho 1912-07-30T00:00:00 local time
* Showa 1926-12-25T00:00:00 local time
* Heisei 1989-01-08T00:00:00 local time
* Reiwa 2019-05-01T00:00:00 local time
* -----------------------------------------------------------------------
* }</pre>
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public final class Era {
private final String name;
private final String abbr;
private final long since;
private final CalendarDate sinceDate;
private final boolean localTime;
/**
* Constructs an <code>Era</code> instance.
*
* @param name the era name (e.g., "BeforeCommonEra" for the Julian calendar system)
* @param abbr the abbreviation of the era name (e.g., "B.C.E." for "BeforeCommonEra")
* @param since the time (millisecond offset from January 1, 1970
* (Gregorian) UTC or local time) when the era starts, inclusive.
* @param localTime <code>true</code> if <code>since</code>
* specifies a local time; <code>false</code> if
* <code>since</code> specifies UTC
*/
public Era(String name, String abbr, long since, boolean localTime) {
this.name = name;
this.abbr = abbr;
this.since = since;
this.localTime = localTime;
Gregorian gcal = CalendarSystem.getGregorianCalendar();
BaseCalendar.Date d = (BaseCalendar.Date) gcal.newCalendarDate(null);
gcal.getCalendarDate(since, d);
sinceDate = new ImmutableGregorianDate(d);
}
public String getName() {
return name;
}
public String getDisplayName(Locale locale) {
return name;
}
public String getAbbreviation() {
return abbr;
}
public String getDiaplayAbbreviation(Locale locale) {
return abbr;
}
public long getSince(TimeZone zone) {
if (zone == null || !localTime) {
return since;
}
int offset = zone.getOffset(since);
return since - offset;
}
public CalendarDate getSinceDate() {
return sinceDate;
}
public boolean isLocalTime() {
return localTime;
}
public boolean equals(Object o) {
if (!(o instanceof Era)) {
return false;
}
Era that = (Era) o;
return name.equals(that.name)
&& abbr.equals(that.abbr)
&& since == that.since
&& localTime == that.localTime;
}
private int hash = 0;
public int hashCode() {
if (hash == 0) {
hash = name.hashCode() ^ abbr.hashCode() ^ (int)since ^ (int)(since >> 32)
^ (localTime ? 1 : 0);
}
return hash;
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
sb.append(getName()).append(" (");
sb.append(getAbbreviation()).append(')');
sb.append(" since ").append(getSinceDate());
if (localTime) {
sb.setLength(sb.length() - 1); // remove 'Z'
sb.append(" local time");
}
sb.append(']');
return sb.toString();
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.TimeZone;
/**
* Gregorian calendar implementation.
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public class Gregorian extends BaseCalendar {
static class Date extends BaseCalendar.Date {
protected Date() {
super();
}
protected Date(TimeZone zone) {
super(zone);
}
public int getNormalizedYear() {
return getYear();
}
public void setNormalizedYear(int normalizedYear) {
setYear(normalizedYear);
}
}
Gregorian() {
}
public String getName() {
return "gregorian";
}
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
public Date getCalendarDate(long millis, CalendarDate date) {
return (Date) super.getCalendarDate(millis, date);
}
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
public Date newCalendarDate() {
return new Date();
}
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
}

View File

@@ -0,0 +1,258 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.Locale;
import java.util.TimeZone;
class ImmutableGregorianDate extends BaseCalendar.Date {
private final BaseCalendar.Date date;
ImmutableGregorianDate(BaseCalendar.Date date) {
if (date == null) {
throw new NullPointerException();
}
this.date = date;
}
public Era getEra() {
return date.getEra();
}
public CalendarDate setEra(Era era) {
unsupported(); return this;
}
public int getYear() {
return date.getYear();
}
public CalendarDate setYear(int year) {
unsupported(); return this;
}
public CalendarDate addYear(int n) {
unsupported(); return this;
}
public boolean isLeapYear() {
return date.isLeapYear();
}
void setLeapYear(boolean leapYear) {
unsupported();
}
public int getMonth() {
return date.getMonth();
}
public CalendarDate setMonth(int month) {
unsupported(); return this;
}
public CalendarDate addMonth(int n) {
unsupported(); return this;
}
public int getDayOfMonth() {
return date.getDayOfMonth();
}
public CalendarDate setDayOfMonth(int date) {
unsupported(); return this;
}
public CalendarDate addDayOfMonth(int n) {
unsupported(); return this;
}
public int getDayOfWeek() {
return date.getDayOfWeek();
}
public int getHours() {
return date.getHours();
}
public CalendarDate setHours(int hours) {
unsupported(); return this;
}
public CalendarDate addHours(int n) {
unsupported(); return this;
}
public int getMinutes() {
return date.getMinutes();
}
public CalendarDate setMinutes(int minutes) {
unsupported(); return this;
}
public CalendarDate addMinutes(int n) {
unsupported(); return this;
}
public int getSeconds() {
return date.getSeconds();
}
public CalendarDate setSeconds(int seconds) {
unsupported(); return this;
}
public CalendarDate addSeconds(int n) {
unsupported(); return this;
}
public int getMillis() {
return date.getMillis();
}
public CalendarDate setMillis(int millis) {
unsupported(); return this;
}
public CalendarDate addMillis(int n) {
unsupported(); return this;
}
public long getTimeOfDay() {
return date.getTimeOfDay();
}
public CalendarDate setDate(int year, int month, int dayOfMonth) {
unsupported(); return this;
}
public CalendarDate addDate(int year, int month, int dayOfMonth) {
unsupported(); return this;
}
public CalendarDate setTimeOfDay(int hours, int minutes, int seconds, int millis) {
unsupported(); return this;
}
public CalendarDate addTimeOfDay(int hours, int minutes, int seconds, int millis) {
unsupported(); return this;
}
protected void setTimeOfDay(long fraction) {
unsupported();
}
public boolean isNormalized() {
return date.isNormalized();
}
public boolean isStandardTime() {
return date.isStandardTime();
}
public void setStandardTime(boolean standardTime) {
unsupported();
}
public boolean isDaylightTime() {
return date.isDaylightTime();
}
protected void setLocale(Locale loc) {
unsupported();
}
public TimeZone getZone() {
return date.getZone();
}
public CalendarDate setZone(TimeZone zoneinfo) {
unsupported(); return this;
}
public boolean isSameDate(CalendarDate date) {
return date.isSameDate(date);
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ImmutableGregorianDate)) {
return false;
}
return date.equals(((ImmutableGregorianDate) obj).date);
}
public int hashCode() {
return date.hashCode();
}
public Object clone() {
return super.clone();
}
public String toString() {
return date.toString();
}
protected void setDayOfWeek(int dayOfWeek) {
unsupported();
}
protected void setNormalized(boolean normalized) {
unsupported();
}
public int getZoneOffset() {
return date.getZoneOffset();
}
protected void setZoneOffset(int offset) {
unsupported();
}
public int getDaylightSaving() {
return date.getDaylightSaving();
}
protected void setDaylightSaving(int daylightSaving) {
unsupported();
}
public int getNormalizedYear() {
return date.getNormalizedYear();
}
public void setNormalizedYear(int normalizedYear) {
unsupported();
}
private void unsupported() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright (c) 2003, 2005, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.util.TimeZone;
/**
* Julian calendar implementation.
*
* @author Masayoshi Okutsu
* @since 1.5
*/
public class JulianCalendar extends BaseCalendar {
private static final int BCE = 0;
private static final int CE = 1;
private static final Era[] eras = {
new Era("BeforeCommonEra", "B.C.E.", Long.MIN_VALUE, false),
new Era("CommonEra", "C.E.", -62135709175808L, true)
};
private static final int JULIAN_EPOCH = -1;
private static class Date extends BaseCalendar.Date {
protected Date() {
super();
setCache(1, -1L, 365); // January 1, 1 CE (Julian)
}
protected Date(TimeZone zone) {
super(zone);
setCache(1, -1L, 365); // January 1, 1 CE (Julian)
}
public Date setEra(Era era) {
if (era == null) {
throw new NullPointerException();
}
if (era != eras[0] || era != eras[1]) {
throw new IllegalArgumentException("unknown era: " + era);
}
super.setEra(era);
return this;
}
protected void setKnownEra(Era era) {
super.setEra(era);
}
public int getNormalizedYear() {
if (getEra() == eras[BCE]) {
return 1 - getYear();
}
return getYear();
}
// Use the year numbering ..., -2, -1, 0, 1, 2, ... for
// normalized years. This differs from "Calendrical
// Calculations" in which the numbering is ..., -2, -1, 1, 2,
// ...
public void setNormalizedYear(int year) {
if (year <= 0) {
setYear(1 - year);
setKnownEra(eras[BCE]);
} else {
setYear(year);
setKnownEra(eras[CE]);
}
}
public String toString() {
String time = super.toString();
time = time.substring(time.indexOf('T'));
StringBuffer sb = new StringBuffer();
Era era = getEra();
if (era != null) {
String n = era.getAbbreviation();
if (n != null) {
sb.append(n).append(' ');
}
}
sb.append(getYear()).append('-');
CalendarUtils.sprintf0d(sb, getMonth(), 2).append('-');
CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
sb.append(time);
return sb.toString();
}
}
JulianCalendar() {
setEras(eras);
}
public String getName() {
return "julian";
}
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
public Date getCalendarDate(long millis, CalendarDate date) {
return (Date) super.getCalendarDate(millis, date);
}
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
public Date newCalendarDate() {
return new Date();
}
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
/**
* @param jyear normalized Julian year
*/
public long getFixedDate(int jyear, int month, int dayOfMonth, BaseCalendar.Date cache) {
boolean isJan1 = month == JANUARY && dayOfMonth == 1;
// Look up the one year cache
if (cache != null && cache.hit(jyear)) {
if (isJan1) {
return cache.getCachedJan1();
}
return cache.getCachedJan1() + getDayOfYear(jyear, month, dayOfMonth) - 1;
}
long y = jyear;
long days = JULIAN_EPOCH - 1 + (365 * (y - 1)) + dayOfMonth;
if (y > 0) {
// CE years
days += (y - 1) / 4;
} else {
// BCE years
days += CalendarUtils.floorDivide(y - 1, 4);
}
if (month > 0) {
days += ((367 * (long) month) - 362) / 12;
} else {
days += CalendarUtils.floorDivide((367 * (long) month) - 362, 12);
}
if (month > FEBRUARY) {
days -= CalendarUtils.isJulianLeapYear(jyear) ? 1 : 2;
}
// If it's January 1, update the cache.
if (cache != null && isJan1) {
cache.setCache(jyear, days, CalendarUtils.isJulianLeapYear(jyear) ? 366 : 365);
}
return days;
}
public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
Date jdate = (Date) date;
long fd = 4 * (fixedDate - JULIAN_EPOCH) + 1464;
int year;
if (fd >= 0) {
year = (int)(fd / 1461);
} else {
year = (int) CalendarUtils.floorDivide(fd, 1461);
}
int priorDays = (int)(fixedDate - getFixedDate(year, JANUARY, 1, jdate));
boolean isLeap = CalendarUtils.isJulianLeapYear(year);
if (fixedDate >= getFixedDate(year, MARCH, 1, jdate)) {
priorDays += isLeap ? 1 : 2;
}
int month = 12 * priorDays + 373;
if (month > 0) {
month /= 367;
} else {
month = CalendarUtils.floorDivide(month, 367);
}
int dayOfMonth = (int)(fixedDate - getFixedDate(year, month, 1, jdate)) + 1;
int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate);
assert dayOfWeek > 0 : "negative day of week " + dayOfWeek;
jdate.setNormalizedYear(year);
jdate.setMonth(month);
jdate.setDayOfMonth(dayOfMonth);
jdate.setDayOfWeek(dayOfWeek);
jdate.setLeapYear(isLeap);
jdate.setNormalized(true);
}
/**
* Returns the normalized Julian year number of the given fixed date.
*/
public int getYearFromFixedDate(long fixedDate) {
int year = (int) CalendarUtils.floorDivide(4 * (fixedDate - JULIAN_EPOCH) + 1464, 1461);
return year;
}
public int getDayOfWeek(CalendarDate date) {
// TODO: should replace this with a faster calculation, such
// as cache table lookup
long fixedDate = getFixedDate(date);
return getDayOfWeekFromFixedDate(fixedDate);
}
boolean isLeapYear(int jyear) {
return CalendarUtils.isJulianLeapYear(jyear);
}
}

View File

@@ -0,0 +1,389 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TimeZone;
/**
*
* @author Masayoshi Okutsu
* @since 1.6
*/
public class LocalGregorianCalendar extends BaseCalendar {
private String name;
private Era[] eras;
public static class Date extends BaseCalendar.Date {
protected Date() {
super();
}
protected Date(TimeZone zone) {
super(zone);
}
private int gregorianYear = FIELD_UNDEFINED;
@Override
public Date setEra(Era era) {
if (getEra() != era) {
super.setEra(era);
gregorianYear = FIELD_UNDEFINED;
}
return this;
}
@Override
public Date addYear(int localYear) {
super.addYear(localYear);
gregorianYear += localYear;
return this;
}
@Override
public Date setYear(int localYear) {
if (getYear() != localYear) {
super.setYear(localYear);
gregorianYear = FIELD_UNDEFINED;
}
return this;
}
@Override
public int getNormalizedYear() {
return gregorianYear;
}
@Override
public void setNormalizedYear(int normalizedYear) {
this.gregorianYear = normalizedYear;
}
void setLocalEra(Era era) {
super.setEra(era);
}
void setLocalYear(int year) {
super.setYear(year);
}
@Override
public String toString() {
String time = super.toString();
time = time.substring(time.indexOf('T'));
StringBuffer sb = new StringBuffer();
Era era = getEra();
if (era != null) {
String abbr = era.getAbbreviation();
if (abbr != null) {
sb.append(abbr);
}
}
sb.append(getYear()).append('.');
CalendarUtils.sprintf0d(sb, getMonth(), 2).append('.');
CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
sb.append(time);
return sb.toString();
}
}
static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
Properties calendarProps;
try {
calendarProps = CalendarSystem.getCalendarProperties();
} catch (IOException | IllegalArgumentException e) {
throw new InternalError(e);
}
// Parse calendar.*.eras
String props = calendarProps.getProperty("calendar." + name + ".eras");
if (props == null) {
return null;
}
List<Era> eras = new ArrayList<>();
StringTokenizer eraTokens = new StringTokenizer(props, ";");
while (eraTokens.hasMoreTokens()) {
String items = eraTokens.nextToken().trim();
StringTokenizer itemTokens = new StringTokenizer(items, ",");
String eraName = null;
boolean localTime = true;
long since = 0;
String abbr = null;
while (itemTokens.hasMoreTokens()) {
String item = itemTokens.nextToken();
int index = item.indexOf('=');
// it must be in the key=value form.
if (index == -1) {
return null;
}
String key = item.substring(0, index);
String value = item.substring(index + 1);
if ("name".equals(key)) {
eraName = value;
} else if ("since".equals(key)) {
if (value.endsWith("u")) {
localTime = false;
since = Long.parseLong(value.substring(0, value.length() - 1));
} else {
since = Long.parseLong(value);
}
} else if ("abbr".equals(key)) {
abbr = value;
} else {
throw new RuntimeException("Unknown key word: " + key);
}
}
Era era = new Era(eraName, abbr, since, localTime);
eras.add(era);
}
Era[] eraArray = new Era[eras.size()];
eras.toArray(eraArray);
return new LocalGregorianCalendar(name, eraArray);
}
private LocalGregorianCalendar(String name, Era[] eras) {
this.name = name;
this.eras = eras;
setEras(eras);
}
@Override
public String getName() {
return name;
}
@Override
public Date getCalendarDate() {
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
}
@Override
public Date getCalendarDate(long millis) {
return getCalendarDate(millis, newCalendarDate());
}
@Override
public Date getCalendarDate(long millis, TimeZone zone) {
return getCalendarDate(millis, newCalendarDate(zone));
}
@Override
public Date getCalendarDate(long millis, CalendarDate date) {
Date ldate = (Date) super.getCalendarDate(millis, date);
return adjustYear(ldate, millis, ldate.getZoneOffset());
}
private Date adjustYear(Date ldate, long millis, int zoneOffset) {
int i;
for (i = eras.length - 1; i >= 0; --i) {
Era era = eras[i];
long since = era.getSince(null);
if (era.isLocalTime()) {
since -= zoneOffset;
}
if (millis >= since) {
ldate.setLocalEra(era);
int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
ldate.setLocalYear(y);
break;
}
}
if (i < 0) {
ldate.setLocalEra(null);
ldate.setLocalYear(ldate.getNormalizedYear());
}
ldate.setNormalized(true);
return ldate;
}
@Override
public Date newCalendarDate() {
return new Date();
}
@Override
public Date newCalendarDate(TimeZone zone) {
return new Date(zone);
}
@Override
public boolean validate(CalendarDate date) {
Date ldate = (Date) date;
Era era = ldate.getEra();
if (era != null) {
if (!validateEra(era)) {
return false;
}
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
Date tmp = newCalendarDate(date.getZone());
tmp.setEra(era).setDate(date.getYear(), date.getMonth(), date.getDayOfMonth());
normalize(tmp);
if (tmp.getEra() != era) {
return false;
}
} else {
if (date.getYear() >= eras[0].getSinceDate().getYear()) {
return false;
}
ldate.setNormalizedYear(ldate.getYear());
}
return super.validate(ldate);
}
private boolean validateEra(Era era) {
// Validate the era
for (int i = 0; i < eras.length; i++) {
if (era == eras[i]) {
return true;
}
}
return false;
}
@Override
public boolean normalize(CalendarDate date) {
if (date.isNormalized()) {
return true;
}
normalizeYear(date);
Date ldate = (Date) date;
// Normalize it as a Gregorian date and get its millisecond value
super.normalize(ldate);
boolean hasMillis = false;
long millis = 0;
int year = ldate.getNormalizedYear();
int i;
Era era = null;
for (i = eras.length - 1; i >= 0; --i) {
era = eras[i];
if (era.isLocalTime()) {
CalendarDate sinceDate = era.getSinceDate();
int sinceYear = sinceDate.getYear();
if (year > sinceYear) {
break;
}
if (year == sinceYear) {
int month = ldate.getMonth();
int sinceMonth = sinceDate.getMonth();
if (month > sinceMonth) {
break;
}
if (month == sinceMonth) {
int day = ldate.getDayOfMonth();
int sinceDay = sinceDate.getDayOfMonth();
if (day > sinceDay) {
break;
}
if (day == sinceDay) {
long timeOfDay = ldate.getTimeOfDay();
long sinceTimeOfDay = sinceDate.getTimeOfDay();
if (timeOfDay >= sinceTimeOfDay) {
break;
}
--i;
break;
}
}
}
} else {
if (!hasMillis) {
millis = super.getTime(date);
hasMillis = true;
}
long since = era.getSince(date.getZone());
if (millis >= since) {
break;
}
}
}
if (i >= 0) {
ldate.setLocalEra(era);
int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
ldate.setLocalYear(y);
} else {
// Set Gregorian year with no era
ldate.setEra(null);
ldate.setLocalYear(year);
ldate.setNormalizedYear(year);
}
ldate.setNormalized(true);
return true;
}
@Override
void normalizeMonth(CalendarDate date) {
normalizeYear(date);
super.normalizeMonth(date);
}
void normalizeYear(CalendarDate date) {
Date ldate = (Date) date;
// Set the supposed-to-be-correct Gregorian year first
// e.g., Showa 90 becomes 2015 (1926 + 90 - 1).
Era era = ldate.getEra();
if (era == null || !validateEra(era)) {
ldate.setNormalizedYear(ldate.getYear());
} else {
ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
}
}
/**
* Returns whether the specified Gregorian year is a leap year.
* @see #isLeapYear(Era, int)
*/
@Override
public boolean isLeapYear(int gregorianYear) {
return CalendarUtils.isGregorianLeapYear(gregorianYear);
}
public boolean isLeapYear(Era era, int year) {
if (era == null) {
return isLeapYear(year);
}
int gyear = era.getSinceDate().getYear() + year - 1;
return isLeapYear(gyear);
}
@Override
public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
Date ldate = (Date) date;
super.getCalendarDateFromFixedDate(ldate, fixedDate);
adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);
}
}

View File

@@ -0,0 +1,737 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.util.calendar;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.ref.SoftReference;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
/**
* <code>ZoneInfo</code> is an implementation subclass of {@link
* java.util.TimeZone TimeZone} that represents GMT offsets and
* daylight saving time transitions of a time zone.
* <p>
* The daylight saving time transitions are described in the {@link
* #transitions transitions} table consisting of a chronological
* sequence of transitions of GMT offset and/or daylight saving time
* changes. Since all transitions are represented in UTC, in theory,
* <code>ZoneInfo</code> can be used with any calendar systems except
* for the {@link #getOffset(int,int,int,int,int,int) getOffset}
* method that takes Gregorian calendar date fields.
* <p>
* This table covers transitions from 1900 until 2037 (as of version
* 1.4), Before 1900, it assumes that there was no daylight saving
* time and the <code>getOffset</code> methods always return the
* {@link #getRawOffset} value. No Local Mean Time is supported. If a
* specified date is beyond the transition table and this time zone is
* supposed to observe daylight saving time in 2037, it delegates
* operations to a {@link java.util.SimpleTimeZone SimpleTimeZone}
* object created using the daylight saving time schedule as of 2037.
* <p>
* The date items, transitions, GMT offset(s), etc. are read from a database
* file. See {@link ZoneInfoFile} for details.
* @see java.util.SimpleTimeZone
* @since 1.4
*/
public class ZoneInfo extends TimeZone {
private static final int UTC_TIME = 0;
private static final int STANDARD_TIME = 1;
private static final int WALL_TIME = 2;
private static final long OFFSET_MASK = 0x0fL;
private static final long DST_MASK = 0xf0L;
private static final int DST_NSHIFT = 4;
// this bit field is reserved for abbreviation support
private static final long ABBR_MASK = 0xf00L;
private static final int TRANSITION_NSHIFT = 12;
private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar();
/**
* The raw GMT offset in milliseconds between this zone and GMT.
* Negative offsets are to the west of Greenwich. To obtain local
* <em>standard</em> time, add the offset to GMT time.
* @serial
*/
private int rawOffset;
/**
* Difference in milliseconds from the original GMT offset in case
* the raw offset value has been modified by calling {@link
* #setRawOffset}. The initial value is 0.
* @serial
*/
private int rawOffsetDiff = 0;
/**
* A CRC32 value of all pairs of transition time (in milliseconds
* in <code>long</code>) in local time and its GMT offset (in
* seconds in <code>int</code>) in the chronological order. Byte
* values of each <code>long</code> and <code>int</code> are taken
* in the big endian order (i.e., MSB to LSB).
* @serial
*/
private int checksum;
/**
* The amount of time in milliseconds saved during daylight saving
* time. If <code>useDaylight</code> is false, this value is 0.
* @serial
*/
private int dstSavings;
/**
* This array describes transitions of GMT offsets of this time
* zone, including both raw offset changes and daylight saving
* time changes.
* A long integer consists of four bit fields.
* <ul>
* <li>The most significant 52-bit field represents transition
* time in milliseconds from Gregorian January 1 1970, 00:00:00
* GMT.</li>
* <li>The next 4-bit field is reserved and must be 0.</li>
* <li>The next 4-bit field is an index value to {@link #offsets
* offsets[]} for the amount of daylight saving at the
* transition. If this value is zero, it means that no daylight
* saving, not the index value zero.</li>
* <li>The least significant 4-bit field is an index value to
* {@link #offsets offsets[]} for <em>total</em> GMT offset at the
* transition.</li>
* </ul>
* If this time zone doesn't observe daylight saving time and has
* never changed any GMT offsets in the past, this value is null.
* @serial
*/
private long[] transitions;
/**
* This array holds all unique offset values in
* milliseconds. Index values to this array are stored in the
* transitions array elements.
* @serial
*/
private int[] offsets;
/**
* SimpleTimeZone parameter values. It has to have either 8 for
* {@link java.util.SimpleTimeZone#SimpleTimeZone(int, String,
* int, int , int , int , int , int , int , int , int) the
* 11-argument SimpleTimeZone constructor} or 10 for {@link
* java.util.SimpleTimeZone#SimpleTimeZone(int, String, int, int,
* int , int , int , int , int , int , int, int, int) the
* 13-argument SimpleTimeZone constructor} parameters.
* @serial
*/
private int[] simpleTimeZoneParams;
/**
* True if the raw GMT offset value would change after the time
* zone data has been generated; false, otherwise. The default
* value is false.
* @serial
*/
private boolean willGMTOffsetChange = false;
/**
* True if the object has been modified after its instantiation.
*/
transient private boolean dirty = false;
private static final long serialVersionUID = 2653134537216586139L;
/**
* A constructor.
*/
public ZoneInfo() {
}
/**
* A Constructor for CustomID.
*/
public ZoneInfo(String ID, int rawOffset) {
this(ID, rawOffset, 0, 0, null, null, null, false);
}
/**
* Constructs a ZoneInfo instance.
*
* @param ID time zone name
* @param rawOffset GMT offset in milliseconds
* @param dstSavings daylight saving value in milliseconds or 0
* (zero) if this time zone doesn't observe Daylight Saving Time.
* @param checksum CRC32 value with all transitions table entry
* values
* @param transitions transition table
* @param offsets offset value table
* @param simpleTimeZoneParams parameter values for constructing
* SimpleTimeZone
* @param willGMTOffsetChange the value of willGMTOffsetChange
*/
ZoneInfo(String ID,
int rawOffset,
int dstSavings,
int checksum,
long[] transitions,
int[] offsets,
int[] simpleTimeZoneParams,
boolean willGMTOffsetChange) {
setID(ID);
this.rawOffset = rawOffset;
this.dstSavings = dstSavings;
this.checksum = checksum;
this.transitions = transitions;
this.offsets = offsets;
this.simpleTimeZoneParams = simpleTimeZoneParams;
this.willGMTOffsetChange = willGMTOffsetChange;
}
/**
* Returns the difference in milliseconds between local time and UTC
* of given time, taking into account both the raw offset and the
* effect of daylight savings.
*
* @param date the milliseconds in UTC
* @return the milliseconds to add to UTC to get local wall time
*/
public int getOffset(long date) {
return getOffsets(date, null, UTC_TIME);
}
public int getOffsets(long utc, int[] offsets) {
return getOffsets(utc, offsets, UTC_TIME);
}
public int getOffsetsByStandard(long standard, int[] offsets) {
return getOffsets(standard, offsets, STANDARD_TIME);
}
public int getOffsetsByWall(long wall, int[] offsets) {
return getOffsets(wall, offsets, WALL_TIME);
}
private int getOffsets(long date, int[] offsets, int type) {
// if dst is never observed, there is no transition.
if (transitions == null) {
int offset = getLastRawOffset();
if (offsets != null) {
offsets[0] = offset;
offsets[1] = 0;
}
return offset;
}
date -= rawOffsetDiff;
int index = getTransitionIndex(date, type);
// prior to the transition table, returns the raw offset.
// FIXME: should support LMT.
if (index < 0) {
int offset = getLastRawOffset();
if (offsets != null) {
offsets[0] = offset;
offsets[1] = 0;
}
return offset;
}
if (index < transitions.length) {
long val = transitions[index];
int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff;
if (offsets != null) {
int dst = (int)((val >>> DST_NSHIFT) & 0xfL);
int save = (dst == 0) ? 0 : this.offsets[dst];
offsets[0] = offset - save;
offsets[1] = save;
}
return offset;
}
// beyond the transitions, delegate to SimpleTimeZone if there
// is a rule; otherwise, return rawOffset.
SimpleTimeZone tz = getLastRule();
if (tz != null) {
int rawoffset = tz.getRawOffset();
long msec = date;
if (type != UTC_TIME) {
msec -= rawOffset;
}
int dstoffset = tz.getOffset(msec) - rawOffset;
// Check if it's in a standard-to-daylight transition.
if (dstoffset > 0 && tz.getOffset(msec - dstoffset) == rawoffset && type == WALL_TIME) {
dstoffset = 0;
}
if (offsets != null) {
offsets[0] = rawoffset;
offsets[1] = dstoffset;
}
return rawoffset + dstoffset;
}
int offset = getLastRawOffset();
if (offsets != null) {
offsets[0] = offset;
offsets[1] = 0;
}
return offset;
}
private int getTransitionIndex(long date, int type) {
int low = 0;
int high = transitions.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
long val = transitions[mid];
long midVal = val >> TRANSITION_NSHIFT; // sign extended
if (type != UTC_TIME) {
midVal += offsets[(int)(val & OFFSET_MASK)]; // wall time
}
if (type == STANDARD_TIME) {
int dstIndex = (int)((val >>> DST_NSHIFT) & 0xfL);
if (dstIndex != 0) {
midVal -= offsets[dstIndex]; // make it standard time
}
}
if (midVal < date) {
low = mid + 1;
} else if (midVal > date) {
high = mid - 1;
} else {
return mid;
}
}
// if beyond the transitions, returns that index.
if (low >= transitions.length) {
return low;
}
return low - 1;
}
/**
* Returns the difference in milliseconds between local time and
* UTC, taking into account both the raw offset and the effect of
* daylight savings, for the specified date and time. This method
* assumes that the start and end month are distinct. This method
* assumes a Gregorian calendar for calculations.
* <p>
* <em>Note: In general, clients should use
* {@link Calendar#ZONE_OFFSET Calendar.get(ZONE_OFFSET)} +
* {@link Calendar#DST_OFFSET Calendar.get(DST_OFFSET)}
* instead of calling this method.</em>
*
* @param era The era of the given date. The value must be either
* GregorianCalendar.AD or GregorianCalendar.BC.
* @param year The year in the given date.
* @param month The month in the given date. Month is 0-based. e.g.,
* 0 for January.
* @param day The day-in-month of the given date.
* @param dayOfWeek The day-of-week of the given date.
* @param millis The milliseconds in day in <em>standard</em> local time.
* @return The milliseconds to add to UTC to get local time.
*/
public int getOffset(int era, int year, int month, int day,
int dayOfWeek, int milliseconds) {
if (milliseconds < 0 || milliseconds >= AbstractCalendar.DAY_IN_MILLIS) {
throw new IllegalArgumentException();
}
if (era == java.util.GregorianCalendar.BC) { // BC
year = 1 - year;
} else if (era != java.util.GregorianCalendar.AD) {
throw new IllegalArgumentException();
}
CalendarDate date = gcal.newCalendarDate(null);
date.setDate(year, month + 1, day);
if (gcal.validate(date) == false) {
throw new IllegalArgumentException();
}
// bug-for-bug compatible argument checking
if (dayOfWeek < java.util.GregorianCalendar.SUNDAY
|| dayOfWeek > java.util.GregorianCalendar.SATURDAY) {
throw new IllegalArgumentException();
}
if (transitions == null) {
return getLastRawOffset();
}
long dateInMillis = gcal.getTime(date) + milliseconds;
dateInMillis -= (long) rawOffset; // make it UTC
return getOffsets(dateInMillis, null, UTC_TIME);
}
/**
* Sets the base time zone offset from GMT. This operation
* modifies all the transitions of this ZoneInfo object, including
* historical ones, if applicable.
*
* @param offsetMillis the base time zone offset to GMT.
* @see getRawOffset
*/
public synchronized void setRawOffset(int offsetMillis) {
if (offsetMillis == rawOffset + rawOffsetDiff) {
return;
}
rawOffsetDiff = offsetMillis - rawOffset;
if (lastRule != null) {
lastRule.setRawOffset(offsetMillis);
}
dirty = true;
}
/**
* Returns the GMT offset of the current date. This GMT offset
* value is not modified during Daylight Saving Time.
*
* @return the GMT offset value in milliseconds to add to UTC time
* to get local standard time
*/
public int getRawOffset() {
if (!willGMTOffsetChange) {
return rawOffset + rawOffsetDiff;
}
int[] offsets = new int[2];
getOffsets(System.currentTimeMillis(), offsets, UTC_TIME);
return offsets[0];
}
public boolean isDirty() {
return dirty;
}
private int getLastRawOffset() {
return rawOffset + rawOffsetDiff;
}
/**
* Queries if this time zone uses Daylight Saving Time in the last known rule.
*/
public boolean useDaylightTime() {
return (simpleTimeZoneParams != null);
}
@Override
public boolean observesDaylightTime() {
if (simpleTimeZoneParams != null) {
return true;
}
if (transitions == null) {
return false;
}
// Look up the transition table to see if it's in DST right
// now or if there's any standard-to-daylight transition at
// any future.
long utc = System.currentTimeMillis() - rawOffsetDiff;
int index = getTransitionIndex(utc, UTC_TIME);
// before transitions in the transition table
if (index < 0) {
return false;
}
// the time is in the table range.
for (int i = index; i < transitions.length; i++) {
if ((transitions[i] & DST_MASK) != 0) {
return true;
}
}
// No further DST is observed.
return false;
}
/**
* Queries if the specified date is in Daylight Saving Time.
*/
public boolean inDaylightTime(Date date) {
if (date == null) {
throw new NullPointerException();
}
if (transitions == null) {
return false;
}
long utc = date.getTime() - rawOffsetDiff;
int index = getTransitionIndex(utc, UTC_TIME);
// before transitions in the transition table
if (index < 0) {
return false;
}
// the time is in the table range.
if (index < transitions.length) {
return (transitions[index] & DST_MASK) != 0;
}
// beyond the transition table
SimpleTimeZone tz = getLastRule();
if (tz != null) {
return tz.inDaylightTime(date);
}
return false;
}
/**
* Returns the amount of time in milliseconds that the clock is advanced
* during daylight saving time is in effect in its last daylight saving time rule.
*
* @return the number of milliseconds the time is advanced with respect to
* standard time when daylight saving time is in effect.
*/
public int getDSTSavings() {
return dstSavings;
}
// /**
// * @return the last year in the transition table or -1 if this
// * time zone doesn't observe any daylight saving time.
// */
// public int getMaxTransitionYear() {
// if (transitions == null) {
// return -1;
// }
// long val = transitions[transitions.length - 1];
// int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff;
// val = (val >> TRANSITION_NSHIFT) + offset;
// CalendarDate lastDate = Gregorian.getCalendarDate(val);
// return lastDate.getYear();
// }
/**
* Returns a string representation of this time zone.
* @return the string
*/
public String toString() {
return getClass().getName() +
"[id=\"" + getID() + "\"" +
",offset=" + getLastRawOffset() +
",dstSavings=" + dstSavings +
",useDaylight=" + useDaylightTime() +
",transitions=" + ((transitions != null) ? transitions.length : 0) +
",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) +
"]";
}
/**
* Gets all available IDs supported in the Java run-time.
*
* @return an array of time zone IDs.
*/
public static String[] getAvailableIDs() {
return ZoneInfoFile.getZoneIds();
}
/**
* Gets all available IDs that have the same value as the
* specified raw GMT offset.
*
* @param rawOffset the GMT offset in milliseconds. This
* value should not include any daylight saving time.
*
* @return an array of time zone IDs.
*/
public static String[] getAvailableIDs(int rawOffset) {
return ZoneInfoFile.getZoneIds(rawOffset);
}
/**
* Gets the ZoneInfo for the given ID.
*
* @param ID the ID for a ZoneInfo. See TimeZone for detail.
*
* @return the specified ZoneInfo object, or null if there is no
* time zone of the ID.
*/
public static TimeZone getTimeZone(String ID) {
return ZoneInfoFile.getZoneInfo(ID);
}
private transient SimpleTimeZone lastRule;
/**
* Returns a SimpleTimeZone object representing the last GMT
* offset and DST schedule or null if this time zone doesn't
* observe DST.
*/
private synchronized SimpleTimeZone getLastRule() {
if (lastRule == null) {
lastRule = getLastRuleInstance();
}
return lastRule;
}
/**
* Returns a SimpleTimeZone object that represents the last
* known daylight saving time rules.
*
* @return a SimpleTimeZone object or null if this time zone
* doesn't observe DST.
*/
public SimpleTimeZone getLastRuleInstance() {
if (simpleTimeZoneParams == null) {
return null;
}
if (simpleTimeZoneParams.length == 10) {
return new SimpleTimeZone(getLastRawOffset(), getID(),
simpleTimeZoneParams[0],
simpleTimeZoneParams[1],
simpleTimeZoneParams[2],
simpleTimeZoneParams[3],
simpleTimeZoneParams[4],
simpleTimeZoneParams[5],
simpleTimeZoneParams[6],
simpleTimeZoneParams[7],
simpleTimeZoneParams[8],
simpleTimeZoneParams[9],
dstSavings);
}
return new SimpleTimeZone(getLastRawOffset(), getID(),
simpleTimeZoneParams[0],
simpleTimeZoneParams[1],
simpleTimeZoneParams[2],
simpleTimeZoneParams[3],
simpleTimeZoneParams[4],
simpleTimeZoneParams[5],
simpleTimeZoneParams[6],
simpleTimeZoneParams[7],
dstSavings);
}
/**
* Returns a copy of this <code>ZoneInfo</code>.
*/
public Object clone() {
ZoneInfo zi = (ZoneInfo) super.clone();
zi.lastRule = null;
return zi;
}
/**
* Returns a hash code value calculated from the GMT offset and
* transitions.
* @return a hash code of this time zone
*/
public int hashCode() {
return getLastRawOffset() ^ checksum;
}
/**
* Compares the equity of two ZoneInfo objects.
*
* @param obj the object to be compared with
* @return true if given object is same as this ZoneInfo object,
* false otherwise.
*/
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ZoneInfo)) {
return false;
}
ZoneInfo that = (ZoneInfo) obj;
return (getID().equals(that.getID())
&& (getLastRawOffset() == that.getLastRawOffset())
&& (checksum == that.checksum));
}
/**
* Returns true if this zone has the same raw GMT offset value and
* transition table as another zone info. If the specified
* TimeZone object is not a ZoneInfo instance, this method returns
* true if the specified TimeZone object has the same raw GMT
* offset value with no daylight saving time.
*
* @param other the ZoneInfo object to be compared with
* @return true if the given <code>TimeZone</code> has the same
* GMT offset and transition information; false, otherwise.
*/
public boolean hasSameRules(TimeZone other) {
if (this == other) {
return true;
}
if (other == null) {
return false;
}
if (!(other instanceof ZoneInfo)) {
if (getRawOffset() != other.getRawOffset()) {
return false;
}
// if both have the same raw offset and neither observes
// DST, they have the same rule.
if ((transitions == null)
&& (useDaylightTime() == false)
&& (other.useDaylightTime() == false)) {
return true;
}
return false;
}
if (getLastRawOffset() != ((ZoneInfo)other).getLastRawOffset()) {
return false;
}
return (checksum == ((ZoneInfo)other).checksum);
}
/**
* Returns a Map from alias time zone IDs to their standard
* time zone IDs.
*
* @return the Map that holds the mappings from alias time zone IDs
* to their standard time zone IDs, or null if
* <code>ZoneInfoMappings</code> file is not available.
*/
public static Map<String, String> getAliasTable() {
return ZoneInfoFile.getAliasMap();
}
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
// We don't know how this object from 1.4.x or earlier has
// been mutated. So it should always be marked as `dirty'.
dirty = true;
}
}

File diff suppressed because it is too large Load Diff