8143413: add toEpochSecond methods for efficient access
Reviewed-by: rriggs, scolebourne
--- a/jdk/src/java.base/share/classes/java/time/LocalDate.java Fri Dec 18 17:42:06 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java Wed Dec 23 13:19:58 2015 -0500
@@ -147,6 +147,10 @@
* This could be used by an application as a "far future" date.
*/
public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31);
+ /**
+ * The epoch year {@code LocalDate}, '1970-01-01'.
+ */
+ public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
/**
* Serialization version.
@@ -1864,6 +1868,29 @@
return total - DAYS_0000_TO_1970;
}
+ /**
+ * Converts this {@code LocalDate} to the number of seconds since the epoch
+ * of 1970-01-01T00:00:00Z.
+ * <p>
+ * This combines this local date with the specified time and
+ * offset to calculate the epoch-second value, which is the
+ * number of elapsed seconds from 1970-01-01T00:00:00Z.
+ * Instants on the time-line after the epoch are positive, earlier
+ * are negative.
+ *
+ * @param time the local time, not null
+ * @param offset the zone offset, not null
+ * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
+ * @since 9
+ */
+ public long toEpochSecond(LocalTime time, ZoneOffset offset) {
+ Objects.requireNonNull(time, "time");
+ Objects.requireNonNull(offset, "offset");
+ long secs = toEpochDay() * SECONDS_PER_DAY + time.toSecondOfDay();
+ secs -= offset.getTotalSeconds();
+ return secs;
+ }
+
//-----------------------------------------------------------------------
/**
* Compares this date to another date.
--- a/jdk/src/java.base/share/classes/java/time/LocalTime.java Fri Dec 18 17:42:06 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/time/LocalTime.java Wed Dec 23 13:19:58 2015 -0500
@@ -1490,6 +1490,30 @@
return total;
}
+ /**
+ * Converts this {@code LocalTime} to the number of seconds since the epoch
+ * of 1970-01-01T00:00:00Z.
+ * <p>
+ * This combines this local time with the specified date and
+ * offset to calculate the epoch-second value, which is the
+ * number of elapsed seconds from 1970-01-01T00:00:00Z.
+ * Instants on the time-line after the epoch are positive, earlier
+ * are negative.
+ *
+ * @param date the local date, not null
+ * @param offset the zone offset, not null
+ * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
+ * @since 9
+ */
+ public long toEpochSecond(LocalDate date, ZoneOffset offset) {
+ Objects.requireNonNull(date, "date");
+ Objects.requireNonNull(offset, "offset");
+ long epochDay = date.toEpochDay();
+ long secs = epochDay * 86400 + toSecondOfDay();
+ secs -= offset.getTotalSeconds();
+ return secs;
+ }
+
//-----------------------------------------------------------------------
/**
* Compares this time to another time.
--- a/jdk/src/java.base/share/classes/java/time/OffsetTime.java Fri Dec 18 17:42:06 2015 +0100
+++ b/jdk/src/java.base/share/classes/java/time/OffsetTime.java Wed Dec 23 13:19:58 2015 -0500
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -1232,6 +1232,28 @@
return nod - offsetNanos;
}
+ /**
+ * Converts this {@code OffsetTime} to the number of seconds since the epoch
+ * of 1970-01-01T00:00:00Z.
+ * <p>
+ * This combines this offset time with the specified date to calculate the
+ * epoch-second value, which is the number of elapsed seconds from
+ * 1970-01-01T00:00:00Z.
+ * Instants on the time-line after the epoch are positive, earlier
+ * are negative.
+ *
+ * @param date the localdate, not null
+ * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative
+ * @since 9
+ */
+ public long toEpochSecond(LocalDate date) {
+ Objects.requireNonNull(date, "date");
+ long epochDay = date.toEpochDay();
+ long secs = epochDay * 86400 + time.toSecondOfDay();
+ secs -= offset.getTotalSeconds();
+ return secs;
+ }
+
//-----------------------------------------------------------------------
/**
* Compares this {@code OffsetTime} to another time.
--- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java Fri Dec 18 17:42:06 2015 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java Wed Dec 23 13:19:58 2015 -0500
@@ -2157,6 +2157,31 @@
}
//-----------------------------------------------------------------------
+ // toEpochSecond
+ //-----------------------------------------------------------------------
+ @DataProvider(name="epochSecond")
+ Object[][] provider_toEpochSecond() {
+ return new Object[][] {
+ {LocalDate.of(1858, 11, 17).toEpochSecond(LocalTime.MIDNIGHT, OFFSET_PONE), -3506720400L},
+ {LocalDate.of(1, 1, 1).toEpochSecond(LocalTime.NOON, OFFSET_PONE), -62135557200L},
+ {LocalDate.of(1995, 9, 27).toEpochSecond(LocalTime.of(5, 30), OFFSET_PTWO), 812172600L},
+ {LocalDate.of(1970, 1, 1).toEpochSecond(LocalTime.MIDNIGHT, OFFSET_MTWO), 7200L},
+ {LocalDate.of(-1, 12, 31).toEpochSecond(LocalTime.NOON, OFFSET_PONE), -62167266000L},
+ {LocalDate.of(1, 1, 1).toEpochSecond(LocalTime.MIDNIGHT, OFFSET_PONE),
+ Instant.ofEpochSecond(-62135600400L).getEpochSecond()},
+ {LocalDate.of(1995, 9, 27).toEpochSecond(LocalTime.NOON, OFFSET_PTWO),
+ Instant.ofEpochSecond(812196000L).getEpochSecond()},
+ {LocalDate.of(1995, 9, 27).toEpochSecond(LocalTime.of(5, 30), OFFSET_MTWO),
+ LocalDateTime.of(1995, 9, 27, 5, 30).toEpochSecond(OFFSET_MTWO)},
+ };
+ }
+
+ @Test(dataProvider="epochSecond")
+ public void test_toEpochSecond(long actual, long expected) {
+ assertEquals(actual, expected);
+ }
+
+ //-----------------------------------------------------------------------
// compareTo()
//-----------------------------------------------------------------------
@Test
--- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java Fri Dec 18 17:42:06 2015 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java Wed Dec 23 13:19:58 2015 -0500
@@ -2433,6 +2433,32 @@
}
}
+ //-----------------------------------------------------------------------
+ // toEpochSecond()
+ //--------------------------------------------------------------------------
+ @DataProvider(name="epochSecond")
+ Object[][] provider__toEpochSecond() {
+ return new Object[][] {
+ {LocalTime.of(0, 0).toEpochSecond(LocalDate.of(1970, 1, 1), OFFSET_PTWO), -7200L},
+ {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1965, 12, 31), OFFSET_PTWO), -126282600L},
+ {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1995, 5, 3), OFFSET_MTWO), 799507800L},
+ {LocalTime.of(0, 0).toEpochSecond(LocalDate.of(1970, 1, 1), OFFSET_PTWO),
+ Instant.ofEpochSecond(-7200).getEpochSecond()},
+ {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1969, 12, 31), OFFSET_MTWO),
+ Instant.ofEpochSecond(-37800L).getEpochSecond()},
+ {LocalTime.of(11, 30).toEpochSecond(LocalDate.of(1970, 1, 1), OFFSET_PTWO),
+ LocalDateTime.of(1970, 1, 1, 11, 30).toEpochSecond(OFFSET_PTWO)},
+ };
+ }
+
+ @Test(dataProvider="epochSecond")
+ public void test_toEpochSecond(long actual, long expected) {
+ assertEquals(actual, expected);
+ }
+
+ //-----------------------------------------------------------------------
+ // toSecondOfDay_fromNanoOfDay_symmetry()
+ //-----------------------------------------------------------------------
@Test
public void test_toSecondOfDay_fromNanoOfDay_symmetry() {
LocalTime t = LocalTime.of(0, 0);
--- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java Fri Dec 18 17:42:06 2015 +0100
+++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java Wed Dec 23 13:19:58 2015 -0500
@@ -134,6 +134,7 @@
private static final ZoneId ZONE_GAZA = ZoneId.of("Asia/Gaza");
private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1);
private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2);
+ private static final ZoneOffset OFFSET_MTWO = ZoneOffset.ofHours(-2);
private static final LocalDate DATE = LocalDate.of(2008, 12, 3);
private OffsetTime TEST_11_30_59_500_PONE;
@@ -1149,6 +1150,29 @@
}
//-----------------------------------------------------------------------
+ // toEpochSecond()
+ //-----------------------------------------------------------------------
+ @DataProvider(name="epochSecond")
+ Object[][] provider_toEpochSecond() {
+ return new Object[][] {
+ {OffsetTime.of(0, 0, 0, 0, OFFSET_PTWO).toEpochSecond(LocalDate.of(1970, 1, 1)), -7200L},
+ {OffsetTime.of(11, 30, 0, 0, OFFSET_MTWO).toEpochSecond(LocalDate.of(1995, 9, 27)), 812208600L},
+ {OffsetTime.of(0, 0, 0, 0, OFFSET_PONE).toEpochSecond(LocalDate.of(1970, 1, 1)),
+ Instant.ofEpochSecond(-3600).getEpochSecond()},
+ {OffsetTime.of(11, 30, 0, 0, OFFSET_PTWO).toEpochSecond(LocalDate.of(1965, 12, 31)),
+ Instant.ofEpochSecond(-126282600L).getEpochSecond()},
+ {OffsetTime.of(11, 30, 0, 0, OFFSET_MTWO).toEpochSecond(LocalDate.of(1970, 1, 1)),
+ OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(11, 30), OFFSET_MTWO)
+ .toEpochSecond()},
+ };
+ }
+
+ @Test(dataProvider="epochSecond")
+ public void test_toEpochSecond(long actual, long expected) {
+ assertEquals(actual, expected);
+ }
+
+ //-----------------------------------------------------------------------
// compareTo()
//-----------------------------------------------------------------------
@Test