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/AbstractCalendar.java
41159 views
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>AbstractCalendar</code> class provides a framework for
33
* implementing a concrete calendar system.
34
*
35
* <p><a name="fixed_date"></a><B>Fixed Date</B><br>
36
*
37
* For implementing a concrete calendar system, each calendar must
38
* have the common date numbering, starting from midnight the onset of
39
* Monday, January 1, 1 (Gregorian). It is called a <I>fixed date</I>
40
* in this class. January 1, 1 (Gregorian) is fixed date 1. (See
41
* Nachum Dershowitz and Edward M. Reingold, <I>CALENDRICAL
42
* CALCULATION The Millennium Edition</I>, Section 1.2 for details.)
43
*
44
* @author Masayoshi Okutsu
45
* @since 1.5
46
*/
47
48
public abstract class AbstractCalendar extends CalendarSystem {
49
50
// The constants assume no leap seconds support.
51
static final int SECOND_IN_MILLIS = 1000;
52
static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
53
static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
54
static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
55
56
// The number of days between January 1, 1 and January 1, 1970 (Gregorian)
57
static final int EPOCH_OFFSET = 719163;
58
59
private Era[] eras;
60
61
protected AbstractCalendar() {
62
}
63
64
public Era getEra(String eraName) {
65
if (eras != null) {
66
for (Era era : eras) {
67
if (era.getName().equals(eraName)) {
68
return era;
69
}
70
}
71
}
72
return null;
73
}
74
75
public Era[] getEras() {
76
Era[] e = null;
77
if (eras != null) {
78
e = new Era[eras.length];
79
System.arraycopy(eras, 0, e, 0, eras.length);
80
}
81
return e;
82
}
83
84
public void setEra(CalendarDate date, String eraName) {
85
if (eras == null) {
86
return; // should report an error???
87
}
88
for (int i = 0; i < eras.length; i++) {
89
Era e = eras[i];
90
if (e != null && e.getName().equals(eraName)) {
91
date.setEra(e);
92
return;
93
}
94
}
95
throw new IllegalArgumentException("unknown era name: " + eraName);
96
}
97
98
protected void setEras(Era[] eras) {
99
this.eras = eras;
100
}
101
102
public CalendarDate getCalendarDate() {
103
return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
104
}
105
106
public CalendarDate getCalendarDate(long millis) {
107
return getCalendarDate(millis, newCalendarDate());
108
}
109
110
public CalendarDate getCalendarDate(long millis, TimeZone zone) {
111
CalendarDate date = newCalendarDate(zone);
112
return getCalendarDate(millis, date);
113
}
114
115
public CalendarDate getCalendarDate(long millis, CalendarDate date) {
116
int ms = 0; // time of day
117
int zoneOffset = 0;
118
int saving = 0;
119
long days = 0; // fixed date
120
121
// adjust to local time if `date' has time zone.
122
TimeZone zi = date.getZone();
123
if (zi != null) {
124
int[] offsets = new int[2];
125
if (zi instanceof ZoneInfo) {
126
zoneOffset = ((ZoneInfo)zi).getOffsets(millis, offsets);
127
} else {
128
zoneOffset = zi.getOffset(millis);
129
offsets[0] = zi.getRawOffset();
130
offsets[1] = zoneOffset - offsets[0];
131
}
132
133
// We need to calculate the given millis and time zone
134
// offset separately for java.util.GregorianCalendar
135
// compatibility. (i.e., millis + zoneOffset could cause
136
// overflow or underflow, which must be avoided.) Usually
137
// days should be 0 and ms is in the range of -13:00 to
138
// +14:00. However, we need to deal with extreme cases.
139
days = zoneOffset / DAY_IN_MILLIS;
140
ms = zoneOffset % DAY_IN_MILLIS;
141
saving = offsets[1];
142
}
143
date.setZoneOffset(zoneOffset);
144
date.setDaylightSaving(saving);
145
146
days += millis / DAY_IN_MILLIS;
147
ms += (int) (millis % DAY_IN_MILLIS);
148
if (ms >= DAY_IN_MILLIS) {
149
// at most ms is (DAY_IN_MILLIS - 1) * 2.
150
ms -= DAY_IN_MILLIS;
151
++days;
152
} else {
153
// at most ms is (1 - DAY_IN_MILLIS) * 2. Adding one
154
// DAY_IN_MILLIS results in still negative.
155
while (ms < 0) {
156
ms += DAY_IN_MILLIS;
157
--days;
158
}
159
}
160
161
// convert to fixed date (offset from Jan. 1, 1 (Gregorian))
162
days += EPOCH_OFFSET;
163
164
// calculate date fields from the fixed date
165
getCalendarDateFromFixedDate(date, days);
166
167
// calculate time fields from the time of day
168
setTimeOfDay(date, ms);
169
date.setLeapYear(isLeapYear(date));
170
date.setNormalized(true);
171
return date;
172
}
173
174
public long getTime(CalendarDate date) {
175
long gd = getFixedDate(date);
176
long ms = (gd - EPOCH_OFFSET) * DAY_IN_MILLIS + getTimeOfDay(date);
177
int zoneOffset = 0;
178
TimeZone zi = date.getZone();
179
if (zi != null) {
180
if (date.isNormalized()) {
181
return ms - date.getZoneOffset();
182
}
183
// adjust time zone and daylight saving
184
int[] offsets = new int[2];
185
if (date.isStandardTime()) {
186
// 1) 2:30am during starting-DST transition is
187
// intrepreted as 2:30am ST
188
// 2) 5:00pm during DST is still interpreted as 5:00pm ST
189
// 3) 1:30am during ending-DST transition is interpreted
190
// as 1:30am ST (after transition)
191
if (zi instanceof ZoneInfo) {
192
((ZoneInfo)zi).getOffsetsByStandard(ms, offsets);
193
zoneOffset = offsets[0];
194
} else {
195
zoneOffset = zi.getOffset(ms - zi.getRawOffset());
196
}
197
} else {
198
// 1) 2:30am during starting-DST transition is
199
// intrepreted as 3:30am DT
200
// 2) 5:00pm during DST is intrepreted as 5:00pm DT
201
// 3) 1:30am during ending-DST transition is interpreted
202
// as 1:30am DT/0:30am ST (before transition)
203
if (zi instanceof ZoneInfo) {
204
zoneOffset = ((ZoneInfo)zi).getOffsetsByWall(ms, offsets);
205
} else {
206
zoneOffset = zi.getOffset(ms - zi.getRawOffset());
207
}
208
}
209
}
210
ms -= zoneOffset;
211
getCalendarDate(ms, date);
212
return ms;
213
}
214
215
protected long getTimeOfDay(CalendarDate date) {
216
long fraction = date.getTimeOfDay();
217
if (fraction != CalendarDate.TIME_UNDEFINED) {
218
return fraction;
219
}
220
fraction = getTimeOfDayValue(date);
221
date.setTimeOfDay(fraction);
222
return fraction;
223
}
224
225
public long getTimeOfDayValue(CalendarDate date) {
226
long fraction = date.getHours();
227
fraction *= 60;
228
fraction += date.getMinutes();
229
fraction *= 60;
230
fraction += date.getSeconds();
231
fraction *= 1000;
232
fraction += date.getMillis();
233
return fraction;
234
}
235
236
public CalendarDate setTimeOfDay(CalendarDate cdate, int fraction) {
237
if (fraction < 0) {
238
throw new IllegalArgumentException();
239
}
240
boolean normalizedState = cdate.isNormalized();
241
int time = fraction;
242
int hours = time / HOUR_IN_MILLIS;
243
time %= HOUR_IN_MILLIS;
244
int minutes = time / MINUTE_IN_MILLIS;
245
time %= MINUTE_IN_MILLIS;
246
int seconds = time / SECOND_IN_MILLIS;
247
time %= SECOND_IN_MILLIS;
248
cdate.setHours(hours);
249
cdate.setMinutes(minutes);
250
cdate.setSeconds(seconds);
251
cdate.setMillis(time);
252
cdate.setTimeOfDay(fraction);
253
if (hours < 24 && normalizedState) {
254
// If this time of day setting doesn't affect the date,
255
// then restore the normalized state.
256
cdate.setNormalized(normalizedState);
257
}
258
return cdate;
259
}
260
261
/**
262
* Returns 7 in this default implementation.
263
*
264
* @return 7
265
*/
266
public int getWeekLength() {
267
return 7;
268
}
269
270
protected abstract boolean isLeapYear(CalendarDate date);
271
272
public CalendarDate getNthDayOfWeek(int nth, int dayOfWeek, CalendarDate date) {
273
CalendarDate ndate = (CalendarDate) date.clone();
274
normalize(ndate);
275
long fd = getFixedDate(ndate);
276
long nfd;
277
if (nth > 0) {
278
nfd = 7 * nth + getDayOfWeekDateBefore(fd, dayOfWeek);
279
} else {
280
nfd = 7 * nth + getDayOfWeekDateAfter(fd, dayOfWeek);
281
}
282
getCalendarDateFromFixedDate(ndate, nfd);
283
return ndate;
284
}
285
286
/**
287
* Returns a date of the given day of week before the given fixed
288
* date.
289
*
290
* @param fixedDate the fixed date
291
* @param dayOfWeek the day of week
292
* @return the calculated date
293
*/
294
static long getDayOfWeekDateBefore(long fixedDate, int dayOfWeek) {
295
return getDayOfWeekDateOnOrBefore(fixedDate - 1, dayOfWeek);
296
}
297
298
/**
299
* Returns a date of the given day of week that is closest to and
300
* after the given fixed date.
301
*
302
* @param fixedDate the fixed date
303
* @param dayOfWeek the day of week
304
* @return the calculated date
305
*/
306
static long getDayOfWeekDateAfter(long fixedDate, int dayOfWeek) {
307
return getDayOfWeekDateOnOrBefore(fixedDate + 7, dayOfWeek);
308
}
309
310
/**
311
* Returns a date of the given day of week on or before the given fixed
312
* date.
313
*
314
* @param fixedDate the fixed date
315
* @param dayOfWeek the day of week
316
* @return the calculated date
317
*/
318
// public for java.util.GregorianCalendar
319
public static long getDayOfWeekDateOnOrBefore(long fixedDate, int dayOfWeek) {
320
long fd = fixedDate - (dayOfWeek - 1);
321
if (fd >= 0) {
322
return fixedDate - (fd % 7);
323
}
324
return fixedDate - CalendarUtils.mod(fd, 7);
325
}
326
327
/**
328
* Returns the fixed date calculated with the specified calendar
329
* date. If the specified date is not normalized, its date fields
330
* are normalized.
331
*
332
* @param date a <code>CalendarDate</code> with which the fixed
333
* date is calculated
334
* @return the calculated fixed date
335
* @see AbstractCalendar.html#fixed_date
336
*/
337
protected abstract long getFixedDate(CalendarDate date);
338
339
/**
340
* Calculates calendar fields from the specified fixed date. This
341
* method stores the calculated calendar field values in the specified
342
* <code>CalendarDate</code>.
343
*
344
* @param date a <code>CalendarDate</code> to stored the
345
* calculated calendar fields.
346
* @param fixedDate a fixed date to calculate calendar fields
347
* @see AbstractCalendar.html#fixed_date
348
*/
349
protected abstract void getCalendarDateFromFixedDate(CalendarDate date,
350
long fixedDate);
351
352
public boolean validateTime(CalendarDate date) {
353
int t = date.getHours();
354
if (t < 0 || t >= 24) {
355
return false;
356
}
357
t = date.getMinutes();
358
if (t < 0 || t >= 60) {
359
return false;
360
}
361
t = date.getSeconds();
362
// TODO: Leap second support.
363
if (t < 0 || t >= 60) {
364
return false;
365
}
366
t = date.getMillis();
367
if (t < 0 || t >= 1000) {
368
return false;
369
}
370
return true;
371
}
372
373
374
int normalizeTime(CalendarDate date) {
375
long fraction = getTimeOfDay(date);
376
long days = 0;
377
378
if (fraction >= DAY_IN_MILLIS) {
379
days = fraction / DAY_IN_MILLIS;
380
fraction %= DAY_IN_MILLIS;
381
} else if (fraction < 0) {
382
days = CalendarUtils.floorDivide(fraction, DAY_IN_MILLIS);
383
if (days != 0) {
384
fraction -= DAY_IN_MILLIS * days; // mod(fraction, DAY_IN_MILLIS)
385
}
386
}
387
if (days != 0) {
388
date.setTimeOfDay(fraction);
389
}
390
date.setMillis((int)(fraction % 1000));
391
fraction /= 1000;
392
date.setSeconds((int)(fraction % 60));
393
fraction /= 60;
394
date.setMinutes((int)(fraction % 60));
395
date.setHours((int)(fraction / 60));
396
return (int)days;
397
}
398
}
399
400