17

I have an instance of LocalDateTime, which I get from the repository layer, and I need to convert it to a Timestamp (Protocol Buffer) instance.

I have used to following approach for the conversion:

LocalDateTime localDateTime = LocalDateTime.now();//this can be any date

Instant instant = localDateTime.toInstant(ZoneOffset.UTC);

Timestamp timestamp = Timestamp.newBuilder()
                            .setSeconds(instant.getEpochSecond())
                            .setNanos(instant.getNano())
                            .build();

Is the ZoneOffset used here, to convert localDateTime to an instance of Instant, correct?

I have used the UTC offset because the comment on the "seconds" attribute in the Timestamp class says the following:

Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive

Have I used the correct ZoneOffset and is my conversion approach correct?

uneq95
  • 2,158
  • 2
  • 17
  • 28
  • Yes, zone offset is necessary to resolve a `LocalDateTime` to an `Instant`. The rest of your question is unclear. The part after "Because" doesn't seem connected to the part with the question mark. Please clarify. – Misha Jun 07 '18 at 06:05
  • I have edited the question, please have a look. – uneq95 Jun 07 '18 at 07:30
  • We cannot tell you what timezone to use. Why does your repository return a `LocalDateTime` instead of an `Instant`? Hopefully, you can find out what time zone the datetime is relative to. If it's not documented anywhere, the datetime is probably in server-local time (returned by `ZoneId.systemDefault()`). Relying on system timezone is an undesirable practice but people do it all the time nonetheless – Misha Jun 07 '18 at 07:41

4 Answers4

6

In general, no, your approach is not correct. The reason is that a LocalDateTime does not have an associated timezone, so it is ambiguous by nature. To convert it to an actual timestamp (an absolute point in time, independent of timezones), you need to know what timezone it was measured in.

By calling localDateTime.toInstant(ZoneOffset.UTC), you are assuming that your localDateTime was actually measured in the UTC timezone. Instead, you should be using the timezone that the LocalDateTime is stored in. If you don't know, then your input data is inherently ambiguous and you'll need to fix that first.

Note that this has nothing to do with the fact that the Unix epoch is usually specified in UTC. We might as well say that the Unix epoch is 1970-01-01T08:00:00+08:00, and it would be the same instant in time.

The rest of it seems correct to me.

Thomas
  • 174,939
  • 50
  • 355
  • 478
3

Here's a routine that pulls together the comments from the question and actual answer to this question:

 protected Timestamp convertLocalDateTimeToGoogleTimestamp(LocalDateTime localDateTime) {
    Instant instant = localDateTime.toInstant(ZoneOffset.UTC);

    Timestamp result = Timestamp.newBuilder()
            .setSeconds(instant.getEpochSecond())
            .setNanos(instant.getNano())
            .build();

    return result;
  }
Brad Parks
  • 66,836
  • 64
  • 257
  • 336
0
LocalDateTime localDateTime = LocalDateTime.now();//this can be any date

Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();

Timestamp timestamp = Timestamp.newBuilder()
                            .setSeconds(instant.getEpochSecond())
                            .setNanos(instant.getNano())
                            .build();
-1

Try this:

Timestamp currentTimeStamp =   Timestamps.fromMillis(System.currentTimeMillis());
Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
Sneha Mule
  • 641
  • 8
  • 6