We need to convert Google Proto buffer time stamp to a normal date. In that circumstance is there any way to convert Google Proto buffer timestamp to a Java LocalDate
directly?
To convert LocalDateTime to LocalDate instance, use toLocalDate() method. It returns a LocalDate with the same year, month and day as in the original localdatetime object. LocalDateTime localDateTime = LocalDateTime. now(); LocalDate localDate = localDateTime.
The easiest way to convert LocalDate to Date is to use valueOf() method from java.
As a moment in UTC, convert to java.time.Instant
. Then apply a time zone to get a ZonedDateTime
. Extract the date-only portion as a LocalDate
.
One-liner:
Instant
.ofEpochSecond( ts.getSeconds() , ts.getNanos() )
.atZone( ZoneId.of( "America/Montreal" ) )
.toLocalDate()
First step is to convert the Timestamp
object’s count of seconds and fractional second (nanoseconds) to the java.time classes. Specifically, java.time.Instant
. Just like Timestamp
, an Instant
represents a moment in UTC with a resolution of nanoseconds.
Instant instant = Instant.ofEpochSecond( ts.getSeconds() , ts.getNanos() ) ;
Determining a date requires a time zone. For any given moment, the date varies around the globe by zone.
Apply a ZoneId
to our Instant
to get a ZonedDateTime
. Same moment, same point on the timeline, different wall-clock time.
ZoneId z = ZoneId( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Extract the date-only portion as a LocalDate
. A LocalDate
has no time-of-day and no time zone.
LocalDate ld = zdt.toLocalDate() ;
Caution: Do not use LocalDateTime
class for this purpose, as unfortunately shown in another Answer. That class purposely lacks any concept of time zone or offset-from-UTC. As such it cannot represent a moment, is not a point on the timeline. See class documentation.
Best to entirely avoid the terribly troublesome legacy date-time classes including Date
, Calendar
, SimpleDateFormat
. But if you must interoperate with old code not yet updated to java.time you can convert back-and-forth. Call new conversion methods added to the old classes.
GregorianCalendar gc = GregorianCalendar.from( zdt ) ;
To represent a date-only value as a GregorianCalendar
we must specify a time-of-day and a time zone. You’ll likely want to use the first moment of the day as the time-of-day component. Never assume the first moment is 00:00:00. Anomalies such as Daylight Saving Time mean the first moment might be another time such as 01:00:00. Let java.time determine first moment.
ZonedDateTime firstMomentOfDay = ld.atZone( z ) ;
GregorianCalendar gc = GregorianCalendar.from( firstMomentOfDay ) ;
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
First some heads up: Protobuf's TimeStamp
has a higher resolution (Seconds and fractions of seconds) than Java's LocalDate
(Days) so you will be loosing some information by converting from TimeStamp
to a LocalDate
See this excerpt of TimeStamp's JavaDoc:
A Timestamp represents a point in time independent of any time zone or calendar, represented as seconds and fractions of seconds at nanosecond resolution in UTC Epoch time.
This very same JavaDoc tells us, the value is a representation based on Epoch time, that means we can use Java's LocalDateTime#ofEpochSeconds to convert without loss (because LocalDateTime
also stores time) and from there on strip the time to get a LocalDate
.
By using a LocalDateTime
(em: Local) we can make sure we use the same TimeZone offset as the TimeStamp
Class does, which is UTC (thats again from the JavaDoc):
final Timestamp ts1 = Timestamp.newBuilder().setSeconds((60 * 60 * 24) - 1).build();
final Timestamp ts2 = Timestamp.newBuilder().setSeconds((60 * 60 * 24)).build();
final LocalDate ld1 = LocalDateTime.ofEpochSecond(ts1.getSeconds(), ts1.getNanos(), ZoneOffset.UTC).toLocalDate();
final LocalDate ld2 = LocalDateTime.ofEpochSecond(ts2.getSeconds(), ts2.getNanos(), ZoneOffset.UTC).toLocalDate();
System.out.println(ts1 + " = " + ld1);
System.out.println(ts2 + " = " + ld2);
Output
seconds: 86399 = 1970-01-01
seconds: 86400 = 1970-01-02
EDIT after asking for conversion to java.util.Date
Looking at possible constructors for Date
and their JavaDoc we find:
Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
And because GMT beeing the older Standard for zoned time representation and it is basically UTC +/- 0, this constructor fits our needs:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// making sure the Date objects use UTC as timezone
final Timestamp ts1 = Timestamp.newBuilder().setSeconds((60 * 60 * 24) - 1).build();
final Timestamp ts2 = Timestamp.newBuilder().setSeconds((60 * 60 * 24)).build();
final Date d1 = new Date(ts1.getSeconds() * 1000);
final Date d2 = new Date(ts2.getSeconds() * 1000);
System.out.println(ts1 + " = " + d1);
System.out.println(ts2 + " = " + d2);
Output:
seconds: 86399 = Thu Jan 01 23:59:59 CET 1970
seconds: 86400 = Fri Jan 02 00:00:00 CET 1970
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With