History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/util/calendar/BaseCalendar.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/util/calendar/BaseCalendar.java+538−0
@@ -0,0 +1,538 @@
1+/*
2+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.util.calendar;
27+
28+import java.util.Locale;
29+import java.util.TimeZone;
30+
31+/**
32+ * The <code>BaseCalendar</code> provides basic calendar calculation
33+ * functions to support the Julian, Gregorian, and Gregorian-based
34+ * calendar systems.
35+ *
36+ * @author Masayoshi Okutsu
37+ * @since 1.5
38+ */
39+
40+public abstract class BaseCalendar extends AbstractCalendar {
41+
42+ public static final int JANUARY = 1;
43+ public static final int FEBRUARY = 2;
44+ public static final int MARCH = 3;
45+ public static final int APRIL = 4;
46+ public static final int MAY = 5;
47+ public static final int JUNE = 6;
48+ public static final int JULY = 7;
49+ public static final int AUGUST = 8;
50+ public static final int SEPTEMBER = 9;
51+ public static final int OCTOBER = 10;
52+ public static final int NOVEMBER = 11;
53+ public static final int DECEMBER = 12;
54+
55+ // day of week constants
56+ public static final int SUNDAY = 1;
57+ public static final int MONDAY = 2;
58+ public static final int TUESDAY = 3;
59+ public static final int WEDNESDAY = 4;
60+ public static final int THURSDAY = 5;
61+ public static final int FRIDAY = 6;
62+ public static final int SATURDAY = 7;
63+
64+ // The base Gregorian year of FIXED_DATES[]
65+ private static final int BASE_YEAR = 1970;
66+
67+ // Pre-calculated fixed dates of January 1 from BASE_YEAR
68+ // (Gregorian). This table covers all the years that can be
69+ // supported by the POSIX time_t (32-bit) after the Epoch. Note
70+ // that the data type is int[].
71+ private static final int[] FIXED_DATES = {
72+ 719163, // 1970
73+ 719528, // 1971
74+ 719893, // 1972
75+ 720259, // 1973
76+ 720624, // 1974
77+ 720989, // 1975
78+ 721354, // 1976
79+ 721720, // 1977
80+ 722085, // 1978
81+ 722450, // 1979
82+ 722815, // 1980
83+ 723181, // 1981
84+ 723546, // 1982
85+ 723911, // 1983
86+ 724276, // 1984
87+ 724642, // 1985
88+ 725007, // 1986
89+ 725372, // 1987
90+ 725737, // 1988
91+ 726103, // 1989
92+ 726468, // 1990
93+ 726833, // 1991
94+ 727198, // 1992
95+ 727564, // 1993
96+ 727929, // 1994
97+ 728294, // 1995
98+ 728659, // 1996
99+ 729025, // 1997
100+ 729390, // 1998
101+ 729755, // 1999
102+ 730120, // 2000
103+ 730486, // 2001
104+ 730851, // 2002
105+ 731216, // 2003
106+ 731581, // 2004
107+ 731947, // 2005
108+ 732312, // 2006
109+ 732677, // 2007
110+ 733042, // 2008
111+ 733408, // 2009
112+ 733773, // 2010
113+ 734138, // 2011
114+ 734503, // 2012
115+ 734869, // 2013
116+ 735234, // 2014
117+ 735599, // 2015
118+ 735964, // 2016
119+ 736330, // 2017
120+ 736695, // 2018
121+ 737060, // 2019
122+ 737425, // 2020
123+ 737791, // 2021
124+ 738156, // 2022
125+ 738521, // 2023
126+ 738886, // 2024
127+ 739252, // 2025
128+ 739617, // 2026
129+ 739982, // 2027
130+ 740347, // 2028
131+ 740713, // 2029
132+ 741078, // 2030
133+ 741443, // 2031
134+ 741808, // 2032
135+ 742174, // 2033
136+ 742539, // 2034
137+ 742904, // 2035
138+ 743269, // 2036
139+ 743635, // 2037
140+ 744000, // 2038
141+ 744365, // 2039
142+ };
143+
144+ public abstract static class Date extends CalendarDate {
145+ protected Date() {
146+ super();
147+ }
148+ protected Date(TimeZone zone) {
149+ super(zone);
150+ }
151+
152+ public Date setNormalizedDate(int normalizedYear, int month, int dayOfMonth) {
153+ setNormalizedYear(normalizedYear);
154+ setMonth(month).setDayOfMonth(dayOfMonth);
155+ return this;
156+ }
157+
158+ public abstract int getNormalizedYear();
159+
160+ public abstract void setNormalizedYear(int normalizedYear);
161+
162+ // Cache for the fixed date of January 1 and year length of the
163+ // cachedYear. A simple benchmark showed 7% performance
164+ // improvement with >90% cache hit. The initial values are for Gregorian.
165+ int cachedYear = 2004;
166+ long cachedFixedDateJan1 = 731581L;
167+ long cachedFixedDateNextJan1 = cachedFixedDateJan1 + 366;
168+
169+ protected final boolean hit(int year) {
170+ return year == cachedYear;
171+ }
172+
173+ protected final boolean hit(long fixedDate) {
174+ return (fixedDate >= cachedFixedDateJan1 &&
175+ fixedDate < cachedFixedDateNextJan1);
176+ }
177+ protected int getCachedYear() {
178+ return cachedYear;
179+ }
180+
181+ protected long getCachedJan1() {
182+ return cachedFixedDateJan1;
183+ }
184+
185+ protected void setCache(int year, long jan1, int len) {
186+ cachedYear = year;
187+ cachedFixedDateJan1 = jan1;
188+ cachedFixedDateNextJan1 = jan1 + len;
189+ }
190+ }
191+
192+ public boolean validate(CalendarDate date) {
193+ Date bdate = (Date) date;
194+ if (bdate.isNormalized()) {
195+ return true;
196+ }
197+ int month = bdate.getMonth();
198+ if (month < JANUARY || month > DECEMBER) {
199+ return false;
200+ }
201+ int d = bdate.getDayOfMonth();
202+ if (d <= 0 || d > getMonthLength(bdate.getNormalizedYear(), month)) {
203+ return false;
204+ }
205+ int dow = bdate.getDayOfWeek();
206+ if (dow != bdate.FIELD_UNDEFINED && dow != getDayOfWeek(bdate)) {
207+ return false;
208+ }
209+
210+ if (!validateTime(date)) {
211+ return false;
212+ }
213+
214+ bdate.setNormalized(true);
215+ return true;
216+ }
217+
218+ public boolean normalize(CalendarDate date) {
219+ if (date.isNormalized()) {
220+ return true;
221+ }
222+
223+ Date bdate = (Date) date;
224+ TimeZone zi = bdate.getZone();
225+
226+ // If the date has a time zone, then we need to recalculate
227+ // the calendar fields. Let getTime() do it.
228+ if (zi != null) {
229+ getTime(date);
230+ return true;
231+ }
232+
233+ int days = normalizeTime(bdate);
234+ normalizeMonth(bdate);
235+ long d = (long)bdate.getDayOfMonth() + days;
236+ int m = bdate.getMonth();
237+ int y = bdate.getNormalizedYear();
238+ int ml = getMonthLength(y, m);
239+
240+ if (!(d > 0 && d <= ml)) {
241+ if (d <= 0 && d > -28) {
242+ ml = getMonthLength(y, --m);
243+ d += ml;
244+ bdate.setDayOfMonth((int) d);
245+ if (m == 0) {
246+ m = DECEMBER;
247+ bdate.setNormalizedYear(y - 1);
248+ }
249+ bdate.setMonth(m);
250+ } else if (d > ml && d < (ml + 28)) {
251+ d -= ml;
252+ ++m;
253+ bdate.setDayOfMonth((int)d);
254+ if (m > DECEMBER) {
255+ bdate.setNormalizedYear(y + 1);
256+ m = JANUARY;
257+ }
258+ bdate.setMonth(m);
259+ } else {
260+ long fixedDate = d + getFixedDate(y, m, 1, bdate) - 1L;
261+ getCalendarDateFromFixedDate(bdate, fixedDate);
262+ }
263+ } else {
264+ bdate.setDayOfWeek(getDayOfWeek(bdate));
265+ }
266+ date.setLeapYear(isLeapYear(bdate.getNormalizedYear()));
267+ date.setZoneOffset(0);
268+ date.setDaylightSaving(0);
269+ bdate.setNormalized(true);
270+ return true;
271+ }
272+
273+ void normalizeMonth(CalendarDate date) {
274+ Date bdate = (Date) date;
275+ int year = bdate.getNormalizedYear();
276+ long month = bdate.getMonth();
277+ if (month <= 0) {
278+ long xm = 1L - month;
279+ year -= (int)((xm / 12) + 1);
280+ month = 13 - (xm % 12);
281+ bdate.setNormalizedYear(year);
282+ bdate.setMonth((int) month);
283+ } else if (month > DECEMBER) {
284+ year += (int)((month - 1) / 12);
285+ month = ((month - 1)) % 12 + 1;
286+ bdate.setNormalizedYear(year);
287+ bdate.setMonth((int) month);
288+ }
289+ }
290+
291+ /**
292+ * Returns 366 if the specified date is in a leap year, or 365
293+ * otherwise This method does not perform the normalization with
294+ * the specified <code>CalendarDate</code>. The
295+ * <code>CalendarDate</code> must be normalized to get a correct
296+ * value.
297+ *
298+ * @param a <code>CalendarDate</code>
299+ * @return a year length in days
300+ * @throws ClassCastException if the specified date is not a
301+ * {@link BaseCalendar.Date}
302+ */
303+ public int getYearLength(CalendarDate date) {
304+ return isLeapYear(((Date)date).getNormalizedYear()) ? 366 : 365;
305+ }
306+
307+ public int getYearLengthInMonths(CalendarDate date) {
308+ return 12;
309+ }
310+
311+ static final int[] DAYS_IN_MONTH
312+ // 12 1 2 3 4 5 6 7 8 9 10 11 12
313+ = { 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
314+ static final int[] ACCUMULATED_DAYS_IN_MONTH
315+ // 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
316+ = { -30, 0, 31, 59, 90,120,151,181,212,243, 273, 304, 334};
317+
318+ static final int[] ACCUMULATED_DAYS_IN_MONTH_LEAP
319+ // 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
320+ = { -30, 0, 31, 59+1, 90+1,120+1,151+1,181+1,212+1,243+1, 273+1, 304+1, 334+1};
321+
322+ public int getMonthLength(CalendarDate date) {
323+ Date gdate = (Date) date;
324+ int month = gdate.getMonth();
325+ if (month < JANUARY || month > DECEMBER) {
326+ throw new IllegalArgumentException("Illegal month value: " + month);
327+ }
328+ return getMonthLength(gdate.getNormalizedYear(), month);
329+ }
330+
331+ // accepts 0 (December in the previous year) to 12.
332+ private final int getMonthLength(int year, int month) {
333+ int days = DAYS_IN_MONTH[month];
334+ if (month == FEBRUARY && isLeapYear(year)) {
335+ days++;
336+ }
337+ return days;
338+ }
339+
340+ public long getDayOfYear(CalendarDate date) {
341+ return getDayOfYear(((Date)date).getNormalizedYear(),
342+ date.getMonth(),
343+ date.getDayOfMonth());
344+ }
345+
346+ final long getDayOfYear(int year, int month, int dayOfMonth) {
347+ return (long) dayOfMonth
348+ + (isLeapYear(year) ?
349+ ACCUMULATED_DAYS_IN_MONTH_LEAP[month] : ACCUMULATED_DAYS_IN_MONTH[month]);
350+ }
351+
352+ // protected
353+ public long getFixedDate(CalendarDate date) {
354+ if (!date.isNormalized()) {
355+ normalizeMonth(date);
356+ }
357+ return getFixedDate(((Date)date).getNormalizedYear(),
358+ date.getMonth(),
359+ date.getDayOfMonth(),
360+ (BaseCalendar.Date) date);
361+ }
362+
363+ // public for java.util.GregorianCalendar
364+ public long getFixedDate(int year, int month, int dayOfMonth, BaseCalendar.Date cache) {
365+ boolean isJan1 = month == JANUARY && dayOfMonth == 1;
366+
367+ // Look up the one year cache
368+ if (cache != null && cache.hit(year)) {
369+ if (isJan1) {
370+ return cache.getCachedJan1();
371+ }
372+ return cache.getCachedJan1() + getDayOfYear(year, month, dayOfMonth) - 1;
373+ }
374+
375+ // Look up the pre-calculated fixed date table
376+ int n = year - BASE_YEAR;
377+ if (n >= 0 && n < FIXED_DATES.length) {
378+ long jan1 = FIXED_DATES[n];
379+ if (cache != null) {
380+ cache.setCache(year, jan1, isLeapYear(year) ? 366 : 365);
381+ }
382+ return isJan1 ? jan1 : jan1 + getDayOfYear(year, month, dayOfMonth) - 1;
383+ }
384+
385+ long prevyear = (long)year - 1;
386+ long days = dayOfMonth;
387+
388+ if (prevyear >= 0) {
389+ days += (365 * prevyear)
390+ + (prevyear / 4)
391+ - (prevyear / 100)
392+ + (prevyear / 400)
393+ + ((367 * month - 362) / 12);
394+ } else {
395+ days += (365 * prevyear)
396+ + CalendarUtils.floorDivide(prevyear, 4)
397+ - CalendarUtils.floorDivide(prevyear, 100)
398+ + CalendarUtils.floorDivide(prevyear, 400)
399+ + CalendarUtils.floorDivide((367 * month - 362), 12);
400+ }
401+
402+ if (month > FEBRUARY) {
403+ days -= isLeapYear(year) ? 1 : 2;
404+ }
405+
406+ // If it's January 1, update the cache.
407+ if (cache != null && isJan1) {
408+ cache.setCache(year, days, isLeapYear(year) ? 366 : 365);
409+ }
410+
411+ return days;
412+ }
413+
414+ /**
415+ * Calculates calendar fields and store them in the specified
416+ * <code>CalendarDate</code>.
417+ */
418+ // should be 'protected'
419+ public void getCalendarDateFromFixedDate(CalendarDate date,
420+ long fixedDate) {
421+ Date gdate = (Date) date;
422+ int year;
423+ long jan1;
424+ boolean isLeap;
425+ if (gdate.hit(fixedDate)) {
426+ year = gdate.getCachedYear();
427+ jan1 = gdate.getCachedJan1();
428+ isLeap = isLeapYear(year);
429+ } else {
430+ // Looking up FIXED_DATES[] here didn't improve performance
431+ // much. So we calculate year and jan1. getFixedDate()
432+ // will look up FIXED_DATES[] actually.
433+ year = getGregorianYearFromFixedDate(fixedDate);
434+ jan1 = getFixedDate(year, JANUARY, 1, null);
435+ isLeap = isLeapYear(year);
436+ // Update the cache data
437+ gdate.setCache (year, jan1, isLeap ? 366 : 365);
438+ }
439+
440+ int priorDays = (int)(fixedDate - jan1);
441+ long mar1 = jan1 + 31 + 28;
442+ if (isLeap) {
443+ ++mar1;
444+ }
445+ if (fixedDate >= mar1) {
446+ priorDays += isLeap ? 1 : 2;
447+ }
448+ int month = 12 * priorDays + 373;
449+ if (month > 0) {
450+ month /= 367;
451+ } else {
452+ month = CalendarUtils.floorDivide(month, 367);
453+ }
454+ long month1 = jan1 + ACCUMULATED_DAYS_IN_MONTH[month];
455+ if (isLeap && month >= MARCH) {
456+ ++month1;
457+ }
458+ int dayOfMonth = (int)(fixedDate - month1) + 1;
459+ int dayOfWeek = getDayOfWeekFromFixedDate(fixedDate);
460+ assert dayOfWeek > 0 : "negative day of week " + dayOfWeek;
461+ gdate.setNormalizedYear(year);
462+ gdate.setMonth(month);
463+ gdate.setDayOfMonth(dayOfMonth);
464+ gdate.setDayOfWeek(dayOfWeek);
465+ gdate.setLeapYear(isLeap);
466+ gdate.setNormalized(true);
467+ }
468+
469+ /**
470+ * Returns the day of week of the given Gregorian date.
471+ */
472+ public int getDayOfWeek(CalendarDate date) {
473+ long fixedDate = getFixedDate(date);
474+ return getDayOfWeekFromFixedDate(fixedDate);
475+ }
476+
477+ public static final int getDayOfWeekFromFixedDate(long fixedDate) {
478+ // The fixed day 1 (January 1, 1 Gregorian) is Monday.
479+ if (fixedDate >= 0) {
480+ return (int)(fixedDate % 7) + SUNDAY;
481+ }
482+ return (int)CalendarUtils.mod(fixedDate, 7) + SUNDAY;
483+ }
484+
485+ public int getYearFromFixedDate(long fixedDate) {
486+ return getGregorianYearFromFixedDate(fixedDate);
487+ }
488+
489+ /**
490+ * Returns the Gregorian year number of the given fixed date.
491+ */
492+ final int getGregorianYearFromFixedDate(long fixedDate) {
493+ long d0;
494+ int d1, d2, d3, d4;
495+ int n400, n100, n4, n1;
496+ int year;
497+
498+ if (fixedDate > 0) {
499+ d0 = fixedDate - 1;
500+ n400 = (int)(d0 / 146097);
501+ d1 = (int)(d0 % 146097);
502+ n100 = d1 / 36524;
503+ d2 = d1 % 36524;
504+ n4 = d2 / 1461;
505+ d3 = d2 % 1461;
506+ n1 = d3 / 365;
507+ d4 = (d3 % 365) + 1;
508+ } else {
509+ d0 = fixedDate - 1;
510+ n400 = (int)CalendarUtils.floorDivide(d0, 146097L);
511+ d1 = (int)CalendarUtils.mod(d0, 146097L);
512+ n100 = CalendarUtils.floorDivide(d1, 36524);
513+ d2 = CalendarUtils.mod(d1, 36524);
514+ n4 = CalendarUtils.floorDivide(d2, 1461);
515+ d3 = CalendarUtils.mod(d2, 1461);
516+ n1 = CalendarUtils.floorDivide(d3, 365);
517+ d4 = CalendarUtils.mod(d3, 365) + 1;
518+ }
519+ year = 400 * n400 + 100 * n100 + 4 * n4 + n1;
520+ if (!(n100 == 4 || n1 == 4)) {
521+ ++year;
522+ }
523+ return year;
524+ }
525+
526+ /**
527+ * @return true if the specified year is a Gregorian leap year, or
528+ * false otherwise.
529+ * @see BaseCalendar#isGregorianLeapYear
530+ */
531+ protected boolean isLeapYear(CalendarDate date) {
532+ return isLeapYear(((Date)date).getNormalizedYear());
533+ }
534+
535+ boolean isLeapYear(int normalizedYear) {
536+ return CalendarUtils.isGregorianLeapYear(normalizedYear);
537+ }
538+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t