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