Skip to content

Commit 30a9a62

Browse files
authored
Added support for java.time API (#4627)
1 parent 486a581 commit 30a9a62

40 files changed

Lines changed: 3565 additions & 12 deletions
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package java.time;
2+
3+
public abstract class Clock {
4+
public abstract ZoneId getZone();
5+
6+
public abstract Instant instant();
7+
8+
public long millis() {
9+
return instant().toEpochMilli();
10+
}
11+
12+
public static Clock systemUTC() {
13+
return new SystemClock(ZoneOffset.UTC);
14+
}
15+
16+
public static Clock systemDefaultZone() {
17+
return new SystemClock(ZoneId.systemDefault());
18+
}
19+
20+
public static Clock fixed(Instant fixedInstant, ZoneId zone) {
21+
return new FixedClock(fixedInstant, zone);
22+
}
23+
24+
private static final class SystemClock extends Clock {
25+
private final ZoneId zone;
26+
27+
private SystemClock(ZoneId zone) {
28+
this.zone = zone;
29+
}
30+
31+
public ZoneId getZone() {
32+
return zone;
33+
}
34+
35+
public Instant instant() {
36+
return Instant.now();
37+
}
38+
}
39+
40+
private static final class FixedClock extends Clock {
41+
private final Instant instant;
42+
private final ZoneId zone;
43+
44+
private FixedClock(Instant instant, ZoneId zone) {
45+
this.instant = instant;
46+
this.zone = zone;
47+
}
48+
49+
public ZoneId getZone() {
50+
return zone;
51+
}
52+
53+
public Instant instant() {
54+
return instant;
55+
}
56+
}
57+
}
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package java.time;
2+
3+
import java.text.ParseException;
4+
import java.text.SimpleDateFormat;
5+
import java.util.Calendar;
6+
import java.util.Date;
7+
import java.util.Locale;
8+
import java.util.TimeZone;
9+
10+
public final class DateTimeSupport {
11+
static final long MILLIS_PER_SECOND = 1000L;
12+
static final long MILLIS_PER_DAY = 86400000L;
13+
static final long SECONDS_PER_DAY = 86400L;
14+
static final long NANOS_PER_SECOND = 1000000000L;
15+
static final long NANOS_PER_MILLI = 1000000L;
16+
static final long NANOS_PER_DAY = 86400000000000L;
17+
18+
private static final long DAYS_0000_TO_1970 = 719528L;
19+
20+
private DateTimeSupport() {
21+
}
22+
23+
public static int floorDiv(int x, int y) {
24+
int r = x / y;
25+
if ((x ^ y) < 0 && (r * y != x)) {
26+
r--;
27+
}
28+
return r;
29+
}
30+
31+
public static long floorDiv(long x, long y) {
32+
long r = x / y;
33+
if ((x ^ y) < 0 && (r * y != x)) {
34+
r--;
35+
}
36+
return r;
37+
}
38+
39+
public static int floorMod(int x, int y) {
40+
return x - floorDiv(x, y) * y;
41+
}
42+
43+
public static long floorMod(long x, long y) {
44+
return x - floorDiv(x, y) * y;
45+
}
46+
47+
public static boolean isLeapYear(int year) {
48+
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
49+
}
50+
51+
public static int lengthOfMonth(int year, int month) {
52+
switch (month) {
53+
case 2:
54+
return isLeapYear(year) ? 29 : 28;
55+
case 4:
56+
case 6:
57+
case 9:
58+
case 11:
59+
return 30;
60+
default:
61+
return 31;
62+
}
63+
}
64+
65+
public static long toEpochDay(int year, int month, int dayOfMonth) {
66+
long y = year;
67+
long m = month;
68+
long total = 365L * y;
69+
if (y >= 0) {
70+
total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
71+
} else {
72+
total -= y / -4 - y / -100 + y / -400;
73+
}
74+
total += ((367 * m - 362) / 12);
75+
total += dayOfMonth - 1;
76+
if (m > 2) {
77+
total--;
78+
if (!isLeapYear(year)) {
79+
total--;
80+
}
81+
}
82+
return total - DAYS_0000_TO_1970;
83+
}
84+
85+
public static int[] epochDayToDate(long epochDay) {
86+
long zeroDay = epochDay + DAYS_0000_TO_1970;
87+
zeroDay -= 60;
88+
long adjust = 0;
89+
if (zeroDay < 0) {
90+
long adjustCycles = (zeroDay + 1) / 146097 - 1;
91+
adjust = adjustCycles * 400;
92+
zeroDay += -adjustCycles * 146097;
93+
}
94+
long yearEst = (400 * zeroDay + 591) / 146097;
95+
long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
96+
if (doyEst < 0) {
97+
yearEst--;
98+
doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
99+
}
100+
yearEst += adjust;
101+
int marchDoy0 = (int) doyEst;
102+
int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
103+
int month = (marchMonth0 + 2) % 12 + 1;
104+
int day = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
105+
yearEst += marchMonth0 / 10;
106+
return new int[] { (int) yearEst, month, day };
107+
}
108+
109+
public static void checkDate(int year, int month, int day) {
110+
if (month < 1 || month > 12) {
111+
throw new IllegalArgumentException("Invalid month: " + month);
112+
}
113+
int maxDay = lengthOfMonth(year, month);
114+
if (day < 1 || day > maxDay) {
115+
throw new IllegalArgumentException("Invalid day: " + day);
116+
}
117+
}
118+
119+
public static void checkTime(int hour, int minute, int second, int nano) {
120+
if (hour < 0 || hour > 23) {
121+
throw new IllegalArgumentException("Invalid hour: " + hour);
122+
}
123+
if (minute < 0 || minute > 59) {
124+
throw new IllegalArgumentException("Invalid minute: " + minute);
125+
}
126+
if (second < 0 || second > 59) {
127+
throw new IllegalArgumentException("Invalid second: " + second);
128+
}
129+
if (nano < 0 || nano >= NANOS_PER_SECOND) {
130+
throw new IllegalArgumentException("Invalid nano: " + nano);
131+
}
132+
}
133+
134+
public static long toEpochSecond(LocalDate date, LocalTime time, ZoneOffset offset) {
135+
long days = date.toEpochDay();
136+
long secs = days * SECONDS_PER_DAY + time.toSecondOfDay();
137+
return secs - offset.getTotalSeconds();
138+
}
139+
140+
public static int millisOfSecond(int nano) {
141+
return nano / 1000000;
142+
}
143+
144+
public static Calendar newCalendar(TimeZone tz) {
145+
Calendar out = Calendar.getInstance(tz);
146+
return out;
147+
}
148+
149+
public static LocalDateTime localDateTimeFromInstant(Instant instant, ZoneId zone) {
150+
ZoneOffset offset = offsetFromInstant(instant, zone);
151+
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
152+
long epochDay = floorDiv(localSecond, SECONDS_PER_DAY);
153+
int secondOfDay = (int) floorMod(localSecond, SECONDS_PER_DAY);
154+
LocalDate date = LocalDate.ofEpochDay(epochDay);
155+
LocalTime time = LocalTime.ofNanoOfDay(secondOfDay * NANOS_PER_SECOND + instant.getNano());
156+
return LocalDateTime.of(date, time);
157+
}
158+
159+
public static ZoneOffset offsetFromInstant(Instant instant, ZoneId zone) {
160+
TimeZone tz = zone.toTimeZone();
161+
Calendar cal = newCalendar(TimeZone.getTimeZone("GMT"));
162+
cal.setTime(new Date(instant.toEpochMilli()));
163+
int offsetMillis = tz.getOffset(
164+
1,
165+
cal.get(Calendar.YEAR),
166+
cal.get(Calendar.MONTH),
167+
cal.get(Calendar.DAY_OF_MONTH),
168+
cal.get(Calendar.DAY_OF_WEEK),
169+
((cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE)) * 60 + cal.get(Calendar.SECOND)) * 1000
170+
+ cal.get(Calendar.MILLISECOND));
171+
return ZoneOffset.ofTotalSeconds(offsetMillis / 1000);
172+
}
173+
174+
public static SimpleDateFormat newFormat(String pattern, ZoneId zone, Locale locale) {
175+
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
176+
return sdf;
177+
}
178+
179+
public static String formatPattern(String pattern, TemporalCarrier carrier, Locale locale) {
180+
ZoneId zone = carrier.getZoneForFormatting();
181+
SimpleDateFormat sdf = newFormat(pattern, zone, locale);
182+
TimeZone original = TimeZone.getDefault();
183+
try {
184+
if (zone != null) {
185+
TimeZone.setDefault(zone.toTimeZone());
186+
}
187+
return sdf.format(new Date(carrier.toInstant().toEpochMilli()));
188+
} finally {
189+
TimeZone.setDefault(original);
190+
}
191+
}
192+
193+
public static ParsedPatternResult parsePattern(String text, String pattern, ZoneId defaultZone, Locale locale) {
194+
TimeZone original = TimeZone.getDefault();
195+
try {
196+
if (defaultZone != null) {
197+
TimeZone.setDefault(defaultZone.toTimeZone());
198+
}
199+
SimpleDateFormat sdf = newFormat(pattern, defaultZone, locale);
200+
Date date = sdf.parse(text);
201+
Instant instant = Instant.ofEpochMilli(date.getTime());
202+
ZoneId zone = defaultZone == null ? ZoneOffset.UTC : defaultZone;
203+
return new ParsedPatternResult(instant, zone);
204+
} catch (ParseException err) {
205+
throw new java.time.format.DateTimeParseException(err.getMessage(), text, 0);
206+
} finally {
207+
TimeZone.setDefault(original);
208+
}
209+
}
210+
211+
public interface TemporalCarrier {
212+
Instant toInstant();
213+
ZoneId getZoneForFormatting();
214+
}
215+
216+
public static final class ParsedPatternResult {
217+
public final Instant instant;
218+
public final ZoneId zone;
219+
220+
ParsedPatternResult(Instant instant, ZoneId zone) {
221+
this.instant = instant;
222+
this.zone = zone;
223+
}
224+
}
225+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package java.time;
2+
3+
public final class Duration implements Comparable<Duration> {
4+
private final long seconds;
5+
private final int nanos;
6+
7+
private Duration(long seconds, int nanos) {
8+
this.seconds = seconds;
9+
this.nanos = nanos;
10+
}
11+
12+
public static Duration ofDays(long days) {
13+
return ofSeconds(days * 86400L);
14+
}
15+
16+
public static Duration ofHours(long hours) {
17+
return ofSeconds(hours * 3600L);
18+
}
19+
20+
public static Duration ofMinutes(long minutes) {
21+
return ofSeconds(minutes * 60L);
22+
}
23+
24+
public static Duration ofSeconds(long seconds) {
25+
return new Duration(seconds, 0);
26+
}
27+
28+
public static Duration ofSeconds(long seconds, long nanoAdjustment) {
29+
long secs = seconds + DateTimeSupport.floorDiv(nanoAdjustment, DateTimeSupport.NANOS_PER_SECOND);
30+
int nanos = (int) DateTimeSupport.floorMod(nanoAdjustment, DateTimeSupport.NANOS_PER_SECOND);
31+
return new Duration(secs, nanos);
32+
}
33+
34+
public static Duration ofMillis(long millis) {
35+
return ofSeconds(DateTimeSupport.floorDiv(millis, 1000L), DateTimeSupport.floorMod(millis, 1000L) * 1000000L);
36+
}
37+
38+
public long getSeconds() {
39+
return seconds;
40+
}
41+
42+
public int getNano() {
43+
return nanos;
44+
}
45+
46+
public long toMillis() {
47+
return seconds * 1000L + nanos / 1000000L;
48+
}
49+
50+
public Duration plus(Duration other) {
51+
return ofSeconds(seconds + other.seconds, nanos + other.nanos);
52+
}
53+
54+
public Duration minus(Duration other) {
55+
return ofSeconds(seconds - other.seconds, nanos - other.nanos);
56+
}
57+
58+
public int compareTo(Duration other) {
59+
if (seconds != other.seconds) {
60+
return seconds < other.seconds ? -1 : 1;
61+
}
62+
return nanos < other.nanos ? -1 : nanos > other.nanos ? 1 : 0;
63+
}
64+
65+
public boolean equals(Object obj) {
66+
return obj instanceof Duration && compareTo((Duration) obj) == 0;
67+
}
68+
69+
public int hashCode() {
70+
return (int) (seconds ^ (seconds >>> 32)) + nanos * 31;
71+
}
72+
73+
public String toString() {
74+
StringBuffer sb = new StringBuffer("PT");
75+
long absSeconds = Math.abs(seconds);
76+
if (seconds < 0 && absSeconds > 0) {
77+
sb.append('-');
78+
}
79+
sb.append(absSeconds);
80+
if (nanos != 0) {
81+
sb.append('.');
82+
String frac = String.valueOf(1000000000L + nanos).substring(1);
83+
while (frac.endsWith("0")) {
84+
frac = frac.substring(0, frac.length() - 1);
85+
}
86+
sb.append(frac);
87+
}
88+
sb.append('S');
89+
return sb.toString();
90+
}
91+
}

0 commit comments

Comments
 (0)