Timestamps.java
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf.util;
32 
33 import static com.google.common.math.IntMath.checkedAdd;
34 import static com.google.common.math.IntMath.checkedSubtract;
35 import static com.google.common.math.LongMath.checkedAdd;
36 import static com.google.common.math.LongMath.checkedMultiply;
37 import static com.google.common.math.LongMath.checkedSubtract;
38 
39 import com.google.errorprone.annotations.CanIgnoreReturnValue;
41 import com.google.protobuf.Timestamp;
42 import java.text.ParseException;
43 import java.text.SimpleDateFormat;
44 import java.util.Comparator;
45 import java.util.Date;
46 import java.util.GregorianCalendar;
47 import java.util.Locale;
48 import java.util.TimeZone;
49 
54 public final class Timestamps {
55 
56  // Timestamp for "0001-01-01T00:00:00Z"
57  static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
58 
59  // Timestamp for "9999-12-31T23:59:59Z"
60  static final long TIMESTAMP_SECONDS_MAX = 253402300799L;
61 
62  static final long NANOS_PER_SECOND = 1000000000;
63  static final long NANOS_PER_MILLISECOND = 1000000;
64  static final long NANOS_PER_MICROSECOND = 1000;
65  static final long MILLIS_PER_SECOND = 1000;
66  static final long MICROS_PER_SECOND = 1000000;
67 
69  public static final Timestamp MIN_VALUE =
70  Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MIN).setNanos(0).build();
71 
75  public static final Timestamp MAX_VALUE =
76  Timestamp.newBuilder().setSeconds(TIMESTAMP_SECONDS_MAX).setNanos(999999999).build();
77 
81  public static final Timestamp EPOCH = Timestamp.newBuilder().setSeconds(0).setNanos(0).build();
82 
83  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
84  new ThreadLocal<SimpleDateFormat>() {
85  @Override
86  protected SimpleDateFormat initialValue() {
87  return createTimestampFormat();
88  }
89  };
90 
91  private static SimpleDateFormat createTimestampFormat() {
92  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
93  GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
94  // We use Proleptic Gregorian Calendar (i.e., Gregorian calendar extends
95  // backwards to year one) for timestamp formating.
96  calendar.setGregorianChange(new Date(Long.MIN_VALUE));
97  sdf.setCalendar(calendar);
98  return sdf;
99  }
100 
101  private Timestamps() {}
102 
103  private static final Comparator<Timestamp> COMPARATOR =
104  new Comparator<Timestamp>() {
105  @Override
106  public int compare(Timestamp t1, Timestamp t2) {
107  checkValid(t1);
108  checkValid(t2);
109  int secDiff = Long.compare(t1.getSeconds(), t2.getSeconds());
110  return (secDiff != 0) ? secDiff : Integer.compare(t1.getNanos(), t2.getNanos());
111  }
112  };
113 
119  public static Comparator<Timestamp> comparator() {
120  return COMPARATOR;
121  }
122 
130  public static int compare(Timestamp x, Timestamp y) {
131  return COMPARATOR.compare(x, y);
132  }
133 
142  public static boolean isValid(Timestamp timestamp) {
143  return isValid(timestamp.getSeconds(), timestamp.getNanos());
144  }
145 
155  @SuppressWarnings("GoodTime") // this is a legacy conversion API
156  public static boolean isValid(long seconds, int nanos) {
157  if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
158  return false;
159  }
160  if (nanos < 0 || nanos >= NANOS_PER_SECOND) {
161  return false;
162  }
163  return true;
164  }
165 
167  @CanIgnoreReturnValue
168  public static Timestamp checkValid(Timestamp timestamp) {
169  long seconds = timestamp.getSeconds();
170  int nanos = timestamp.getNanos();
171  if (!isValid(seconds, nanos)) {
172  throw new IllegalArgumentException(
173  String.format(
174  "Timestamp is not valid. See proto definition for valid values. "
175  + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]. "
176  + "Nanos (%s) must be in range [0, +999,999,999].",
177  seconds, nanos));
178  }
179  return timestamp;
180  }
181 
188  public static Timestamp checkValid(Timestamp.Builder timestampBuilder) {
189  return checkValid(timestampBuilder.build());
190  }
191 
203  public static String toString(Timestamp timestamp) {
204  checkValid(timestamp);
205 
206  long seconds = timestamp.getSeconds();
207  int nanos = timestamp.getNanos();
208 
209  StringBuilder result = new StringBuilder();
210  // Format the seconds part.
211  Date date = new Date(seconds * MILLIS_PER_SECOND);
212  result.append(timestampFormat.get().format(date));
213  // Format the nanos part.
214  if (nanos != 0) {
215  result.append(".");
216  result.append(formatNanos(nanos));
217  }
218  result.append("Z");
219  return result.toString();
220  }
221 
232  public static Timestamp parse(String value) throws ParseException {
233  int dayOffset = value.indexOf('T');
234  if (dayOffset == -1) {
235  throw new ParseException("Failed to parse timestamp: invalid timestamp \"" + value + "\"", 0);
236  }
237  int timezoneOffsetPosition = value.indexOf('Z', dayOffset);
238  if (timezoneOffsetPosition == -1) {
239  timezoneOffsetPosition = value.indexOf('+', dayOffset);
240  }
241  if (timezoneOffsetPosition == -1) {
242  timezoneOffsetPosition = value.indexOf('-', dayOffset);
243  }
244  if (timezoneOffsetPosition == -1) {
245  throw new ParseException("Failed to parse timestamp: missing valid timezone offset.", 0);
246  }
247  // Parse seconds and nanos.
248  String timeValue = value.substring(0, timezoneOffsetPosition);
249  String secondValue = timeValue;
250  String nanoValue = "";
251  int pointPosition = timeValue.indexOf('.');
252  if (pointPosition != -1) {
253  secondValue = timeValue.substring(0, pointPosition);
254  nanoValue = timeValue.substring(pointPosition + 1);
255  }
256  Date date = timestampFormat.get().parse(secondValue);
257  long seconds = date.getTime() / MILLIS_PER_SECOND;
258  int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
259  // Parse timezone offsets.
260  if (value.charAt(timezoneOffsetPosition) == 'Z') {
261  if (value.length() != timezoneOffsetPosition + 1) {
262  throw new ParseException(
263  "Failed to parse timestamp: invalid trailing data \""
264  + value.substring(timezoneOffsetPosition)
265  + "\"",
266  0);
267  }
268  } else {
269  String offsetValue = value.substring(timezoneOffsetPosition + 1);
270  long offset = parseTimezoneOffset(offsetValue);
271  if (value.charAt(timezoneOffsetPosition) == '+') {
272  seconds -= offset;
273  } else {
274  seconds += offset;
275  }
276  }
277  try {
278  return normalizedTimestamp(seconds, nanos);
279  } catch (IllegalArgumentException e) {
280  throw new ParseException("Failed to parse timestamp: timestamp is out of range.", 0);
281  }
282  }
283 
285  @SuppressWarnings("GoodTime") // this is a legacy conversion API
286  public static Timestamp fromSeconds(long seconds) {
287  return normalizedTimestamp(seconds, 0);
288  }
289 
296  @SuppressWarnings("GoodTime") // this is a legacy conversion API
297  public static long toSeconds(Timestamp timestamp) {
298  return checkValid(timestamp).getSeconds();
299  }
300 
302  @SuppressWarnings("GoodTime") // this is a legacy conversion API
303  public static Timestamp fromMillis(long milliseconds) {
304  return normalizedTimestamp(
305  milliseconds / MILLIS_PER_SECOND,
306  (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
307  }
308 
315  @SuppressWarnings("GoodTime") // this is a legacy conversion API
316  public static long toMillis(Timestamp timestamp) {
317  checkValid(timestamp);
318  return checkedAdd(
319  checkedMultiply(timestamp.getSeconds(), MILLIS_PER_SECOND),
320  timestamp.getNanos() / NANOS_PER_MILLISECOND);
321  }
322 
324  @SuppressWarnings("GoodTime") // this is a legacy conversion API
325  public static Timestamp fromMicros(long microseconds) {
326  return normalizedTimestamp(
327  microseconds / MICROS_PER_SECOND,
328  (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
329  }
330 
337  @SuppressWarnings("GoodTime") // this is a legacy conversion API
338  public static long toMicros(Timestamp timestamp) {
339  checkValid(timestamp);
340  return checkedAdd(
341  checkedMultiply(timestamp.getSeconds(), MICROS_PER_SECOND),
342  timestamp.getNanos() / NANOS_PER_MICROSECOND);
343  }
344 
346  @SuppressWarnings("GoodTime") // this is a legacy conversion API
347  public static Timestamp fromNanos(long nanoseconds) {
348  return normalizedTimestamp(
349  nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
350  }
351 
353  @SuppressWarnings("GoodTime") // this is a legacy conversion API
354  public static long toNanos(Timestamp timestamp) {
355  checkValid(timestamp);
356  return checkedAdd(
357  checkedMultiply(timestamp.getSeconds(), NANOS_PER_SECOND), timestamp.getNanos());
358  }
359 
361  public static Duration between(Timestamp from, Timestamp to) {
362  checkValid(from);
363  checkValid(to);
364  return Durations.normalizedDuration(
365  checkedSubtract(to.getSeconds(), from.getSeconds()),
366  checkedSubtract(to.getNanos(), from.getNanos()));
367  }
368 
371  checkValid(start);
373  return normalizedTimestamp(
374  checkedAdd(start.getSeconds(), length.getSeconds()),
375  checkedAdd(start.getNanos(), length.getNanos()));
376  }
377 
380  checkValid(start);
382  return normalizedTimestamp(
383  checkedSubtract(start.getSeconds(), length.getSeconds()),
384  checkedSubtract(start.getNanos(), length.getNanos()));
385  }
386 
387  static Timestamp normalizedTimestamp(long seconds, int nanos) {
388  if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
389  seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
390  nanos = (int) (nanos % NANOS_PER_SECOND);
391  }
392  if (nanos < 0) {
393  nanos =
394  (int)
395  (nanos + NANOS_PER_SECOND); // no overflow since nanos is negative (and we're adding)
396  seconds = checkedSubtract(seconds, 1);
397  }
398  Timestamp timestamp = Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
399  return checkValid(timestamp);
400  }
401 
402  private static long parseTimezoneOffset(String value) throws ParseException {
403  int pos = value.indexOf(':');
404  if (pos == -1) {
405  throw new ParseException("Invalid offset value: " + value, 0);
406  }
407  String hours = value.substring(0, pos);
408  String minutes = value.substring(pos + 1);
409  return (Long.parseLong(hours) * 60 + Long.parseLong(minutes)) * 60;
410  }
411 
412  static int parseNanos(String value) throws ParseException {
413  int result = 0;
414  for (int i = 0; i < 9; ++i) {
415  result = result * 10;
416  if (i < value.length()) {
417  if (value.charAt(i) < '0' || value.charAt(i) > '9') {
418  throw new ParseException("Invalid nanoseconds.", 0);
419  }
420  result += value.charAt(i) - '0';
421  }
422  }
423  return result;
424  }
425 
427  static String formatNanos(int nanos) {
428  // Determine whether to use 3, 6, or 9 digits for the nano part.
429  if (nanos % NANOS_PER_MILLISECOND == 0) {
430  return String.format(Locale.ENGLISH, "%1$03d", nanos / NANOS_PER_MILLISECOND);
431  } else if (nanos % NANOS_PER_MICROSECOND == 0) {
432  return String.format(Locale.ENGLISH, "%1$06d", nanos / NANOS_PER_MICROSECOND);
433  } else {
434  return String.format(Locale.ENGLISH, "%1$09d", nanos);
435  }
436  }
437 }
com.google.protobuf.util.Timestamps.timestampFormat
static final ThreadLocal< SimpleDateFormat > timestampFormat
Definition: Timestamps.java:83
com.google.protobuf.util.Timestamps.fromSeconds
static Timestamp fromSeconds(long seconds)
Definition: Timestamps.java:286
com.google.protobuf.util.Timestamps.toMicros
static long toMicros(Timestamp timestamp)
Definition: Timestamps.java:338
com.google.protobuf.util.Timestamps.fromNanos
static Timestamp fromNanos(long nanoseconds)
Definition: Timestamps.java:347
com.google.protobuf.util.Timestamps.MIN_VALUE
static final Timestamp MIN_VALUE
Definition: Timestamps.java:69
com.google.protobuf.util.Timestamps.toNanos
static long toNanos(Timestamp timestamp)
Definition: Timestamps.java:354
com.google.protobuf.util.Timestamps.fromMicros
static Timestamp fromMicros(long microseconds)
Definition: Timestamps.java:325
Timestamp
Definition: timestamp.pb.h:69
length
GLenum GLuint GLenum GLsizei length
Definition: glcorearb.h:2695
com.google.protobuf.util.Timestamps.createTimestampFormat
static SimpleDateFormat createTimestampFormat()
Definition: Timestamps.java:91
com.google.protobuf.util.Timestamps.fromMillis
static Timestamp fromMillis(long milliseconds)
Definition: Timestamps.java:303
com.google.protobuf.util.Timestamps.EPOCH
static final Timestamp EPOCH
Definition: Timestamps.java:81
com.google.protobuf
Definition: ProtoCaliperBenchmark.java:2
com.google.protobuf.util.Timestamps.add
static Timestamp add(Timestamp start, Duration length)
Definition: Timestamps.java:370
y
GLint y
Definition: glcorearb.h:2768
x
GLint GLenum GLint x
Definition: glcorearb.h:2834
com.google.protobuf.util.Timestamps.between
static Duration between(Timestamp from, Timestamp to)
Definition: Timestamps.java:361
com.google.protobuf.util.Durations
Definition: Durations.java:54
Timestamp
struct Timestamp Timestamp
Definition: php/ext/google/protobuf/protobuf.h:663
offset
GLintptr offset
Definition: glcorearb.h:2944
start
GLuint start
Definition: glcorearb.h:2858
com.google.protobuf.util.Timestamps.checkValid
static Timestamp checkValid(Timestamp timestamp)
Definition: Timestamps.java:168
com.google.protobuf.util.Timestamps.parseTimezoneOffset
static long parseTimezoneOffset(String value)
Definition: Timestamps.java:402
com.google.protobuf.util.Timestamps.parse
static Timestamp parse(String value)
Definition: Timestamps.java:232
com.google.protobuf.util.Timestamps.MAX_VALUE
static final Timestamp MAX_VALUE
Definition: Timestamps.java:75
com.google.protobuf.util.Timestamps.toString
static String toString(Timestamp timestamp)
Definition: Timestamps.java:203
com.google.protobuf.util.Timestamps.checkValid
static Timestamp checkValid(Timestamp.Builder timestampBuilder)
Definition: Timestamps.java:188
com.google.protobuf.util.Durations.checkValid
static Duration checkValid(Duration duration)
Definition: Durations.java:180
i
int i
Definition: gmock-matchers_test.cc:764
java
com.google.protobuf.util.Timestamps.toMillis
static long toMillis(Timestamp timestamp)
Definition: Timestamps.java:316
com.google.protobuf.util.Timestamps.compare
static int compare(Timestamp x, Timestamp y)
Definition: Timestamps.java:130
com.google.protobuf.util.Timestamps.COMPARATOR
static final Comparator< Timestamp > COMPARATOR
Definition: Timestamps.java:103
com.google.protobuf::Duration
Duration
struct Duration Duration
Definition: php/ext/google/protobuf/protobuf.h:631
com.google.protobuf.util.Timestamps
Definition: Timestamps.java:54
com.google
com
com.google.protobuf.util.Timestamps.comparator
static Comparator< Timestamp > comparator()
Definition: Timestamps.java:119
com.google.protobuf.util.Timestamps.subtract
static Timestamp subtract(Timestamp start, Duration length)
Definition: Timestamps.java:379
value
GLsizei const GLfloat * value
Definition: glcorearb.h:3093
com.google.protobuf.util.Timestamps.toSeconds
static long toSeconds(Timestamp timestamp)
Definition: Timestamps.java:297
com.google.protobuf.util.Timestamps.Timestamps
Timestamps()
Definition: Timestamps.java:101
com.google.protobuf.util.Timestamps.isValid
static boolean isValid(Timestamp timestamp)
Definition: Timestamps.java:142


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:07:00