|
|
|
@ -42,6 +42,7 @@ import com.google.j2objc.annotations.J2ObjCIncompatible; |
|
|
|
|
import com.google.protobuf.Duration; |
|
|
|
|
import com.google.protobuf.Timestamp; |
|
|
|
|
import java.io.Serializable; |
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
import java.text.ParseException; |
|
|
|
|
import java.text.SimpleDateFormat; |
|
|
|
|
import java.util.Comparator; |
|
|
|
@ -49,6 +50,7 @@ import java.util.Date; |
|
|
|
|
import java.util.GregorianCalendar; |
|
|
|
|
import java.util.Locale; |
|
|
|
|
import java.util.TimeZone; |
|
|
|
|
import javax.annotation.Nullable; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Utilities to help create/manipulate {@code protobuf/timestamp.proto}. All operations throw an |
|
|
|
@ -117,8 +119,8 @@ public final class Timestamps { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns a {@link Comparator} for {@link Timestamp Timestamps} which sorts in increasing |
|
|
|
|
* chronological order. Nulls and invalid {@link Timestamp Timestamps} are not allowed (see |
|
|
|
|
* {@link #isValid}). The returned comparator is serializable. |
|
|
|
|
* chronological order. Nulls and invalid {@link Timestamp Timestamps} are not allowed (see {@link |
|
|
|
|
* #isValid}). The returned comparator is serializable. |
|
|
|
|
*/ |
|
|
|
|
public static Comparator<Timestamp> comparator() { |
|
|
|
|
return TimestampComparator.INSTANCE; |
|
|
|
@ -281,7 +283,8 @@ public final class Timestamps { |
|
|
|
|
try { |
|
|
|
|
return normalizedTimestamp(seconds, nanos); |
|
|
|
|
} catch (IllegalArgumentException e) { |
|
|
|
|
ParseException ex = new ParseException( |
|
|
|
|
ParseException ex = |
|
|
|
|
new ParseException( |
|
|
|
|
"Failed to parse timestamp " + value + " Timestamp is out of range.", 0); |
|
|
|
|
ex.initCause(e); |
|
|
|
|
throw ex; |
|
|
|
@ -307,6 +310,39 @@ public final class Timestamps { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// the following 3 constants contain references to java.time.Instant methods (if that class is
|
|
|
|
|
// available at runtime); otherwise, they are null.
|
|
|
|
|
@Nullable private static final Method INSTANT_NOW = instantMethod("now"); |
|
|
|
|
|
|
|
|
|
@Nullable private static final Method INSTANT_GET_EPOCH_SECOND = instantMethod("getEpochSecond"); |
|
|
|
|
|
|
|
|
|
@Nullable private static final Method INSTANT_GET_NANO = instantMethod("getNano"); |
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
private static Method instantMethod(String methodName) { |
|
|
|
|
try { |
|
|
|
|
return Class.forName("java.time.Instant").getMethod(methodName); |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Create a Timestamp using the best-available system clock. */ |
|
|
|
|
public static Timestamp now() { |
|
|
|
|
if (INSTANT_NOW != null) { |
|
|
|
|
try { |
|
|
|
|
Object now = INSTANT_NOW.invoke(null); |
|
|
|
|
long epochSecond = (long) INSTANT_GET_EPOCH_SECOND.invoke(now); |
|
|
|
|
int nanoAdjustment = (int) INSTANT_GET_NANO.invoke(now); |
|
|
|
|
return normalizedTimestamp(epochSecond, nanoAdjustment); |
|
|
|
|
} catch (Throwable fallThrough) { |
|
|
|
|
throw new AssertionError(fallThrough); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// otherwise, fall back on millisecond precision
|
|
|
|
|
return fromMillis(System.currentTimeMillis()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** Create a Timestamp from the number of seconds elapsed from the epoch. */ |
|
|
|
|
@SuppressWarnings("GoodTime") // this is a legacy conversion API
|
|
|
|
|
public static Timestamp fromSeconds(long seconds) { |
|
|
|
@ -333,7 +369,7 @@ public final class Timestamps { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Create a Timestamp from a java.util.Date. If the java.util.Date is a java.sql.Timestamp, |
|
|
|
|
* Create a Timestamp from a {@link Date}. If the {@link Date} is a {@link java.sql.Timestamp}, |
|
|
|
|
* full nanonsecond precision is retained. |
|
|
|
|
* |
|
|
|
|
* @throws IllegalArgumentException if the year is before 1 CE or after 9999 CE |
|
|
|
@ -344,7 +380,10 @@ public final class Timestamps { |
|
|
|
|
if (date instanceof java.sql.Timestamp) { |
|
|
|
|
java.sql.Timestamp sqlTimestamp = (java.sql.Timestamp) date; |
|
|
|
|
long time = sqlTimestamp.getTime(); |
|
|
|
|
long integralSeconds = (time < 0 && time % 1000 != 0) ? time / 1000L - 1 : time / 1000L ; // truncate the fractional seconds
|
|
|
|
|
long integralSeconds = |
|
|
|
|
(time < 0 && time % 1000 != 0) |
|
|
|
|
? time / 1000L - 1 |
|
|
|
|
: time / 1000L; // truncate the fractional seconds
|
|
|
|
|
return Timestamp.newBuilder() |
|
|
|
|
.setSeconds(integralSeconds) |
|
|
|
|
.setNanos(sqlTimestamp.getNanos()) |
|
|
|
|