Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instant vs ZonedDateTime

I just do not quite understand which one of those two I should use for the following example:

We have an OfferEntity which has a member availableDay which is the date at which the offer is available.

Now, the table will look something like this:

CREATE TABLE IF NOT EXISTS offer (
  created   timestamp with time zone NOT NULL DEFAULT NOW(),
  id        BIGSERIAL PRIMARY KEY,
  available timestamp with time zone
);

From the PostgreSQL docs we know that:

For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system's TimeZone parameter, and is converted to UTC using the offset for the timezone zone.

Which means I should be fine when it comes to persisting any date/time information.

But what does this mean for my OfferEntity and the REST endpoints I define in OfferController?

@Entity
@Table(name = "offer")
public class OfferEntity {    
    @Column(name = "available", nullable = false)
    private ZonedDateTime availableDay;
}

vs

@Entity
@Table(name = "offer")
public class OfferEntity {    
    @Column(name = "available", nullable = false)
    private Instant availableDay;
}

From what I understood - this should not make a difference. PostgreSQL stores everything as UTC anyway so I should be able to take Instant or ZonedDateTime right? Write something -> UTC. Read it again -> still UTC.

Even the client won't be able to tell the difference:

@RequestMapping(value = "/hello", method = RequestMethod.GET)
public Object hello() {

    class Hello {
        public Instant instant = Instant.now();
        public ZonedDateTime zonedDateTime = ZonedDateTime.now();
        public ZonedDateTime viennaTime = ZonedDateTime.now(ZoneId.of("GMT+2"));
        public LocalDateTime localDateTime = LocalDateTime.now();
    }

    return new Hello();
}

Will return:

{
  "instant":       "2018-10-07T15:30:08.579Z",
  "zonedDateTime": "2018-10-07T15:30:08.579Z",
  "viennaTime":    "2018-10-07T17:30:08.579+02:00",
  "localDateTime": "2018-10-07T15:30:08.579",
}

But there must be a crucial difference which I am apparently not seeing.


There are two differences I can make out. It seems to be that Spring has no problem with converting "2018-10-07T15:30:08.579Z" to an Instant object, but fails to do so if I change the type to ZonedDateTime. At least out of the box.

@RequestMapping("/places/{placeId}/offers", method = RequestMethod.GET)
public List<OfferDto> getOffers(
        @PathVariable(name = "placeId") Long placeId,
        @RequestParam(name = "date") ZonedDateTime date) {
    return this.offerService.getOffers(placeId, date);
}

The other difference is the fact that if I use Instant I am forcing my clients to convert all their date/time strings to UTC first. So any client will have to myDate.toUTCString() first. ZonedDateTime would take anything as long as it has a time zone set but why would we care?


So which of the two is the better choice and why would I chose one over the other?

like image 588
Stefan Falk Avatar asked Oct 07 '18 16:10

Stefan Falk


People also ask

What is difference between OffsetDateTime and ZonedDateTime?

ZonedDateTime handles a date and time with a corresponding time zone with a time zone offset from Greenwich/UTC. OffsetDateTime handles a date and time with a corresponding time zone offset from Greenwich/UTC, without a time zone ID.

Should I use LocalDateTime or instant?

Instant and LocalDateTime are two entirely different animals: One represents a moment, the other does not. Instant represents a moment, a specific point in the timeline. LocalDateTime represents a date and a time-of-day. But lacking a time zone or offset-from-UTC, this class cannot represent a moment.

What is a ZonedDateTime?

ZonedDateTime is an immutable representation of a date-time with a time-zone. This class stores all date and time fields, to a precision of nanoseconds, and a time-zone, with a zone offset used to handle ambiguous local date-times. For example, the value "2nd October 2007 at 13:45.30.


1 Answers

The answer in the following link explains it better than I ever could. The answer goes into all the different date/time classes in Java, as well as their relation to sql types.

What's the difference between Instant and LocalDateTime?

A short summary: The classes Instant and ZonedDateTime (as well as OffsetDateTime) represent the same thing: a moment in time. The difference is that ZonedDateTime and OffsetDateTime offer extra context and functionality about timezones or time offsets, whereas Instant has no timezone or offset specified. This can lead to differences especially when Daylight Saving Time is involved. For instance, take the following snippet of code:

    ZonedDateTime z1 = zonedDateTime.of(LocalDateTime.of(2019,10,26,6,0,0),ZoneId.of("Europe/Amsterdam"));
    Instant i1 = z1.plus(1,ChronoUnit.DAYS).toInstant();
    Instant i2 = z1.toInstant().plus(1,ChronoUnit.DAYS);
    System.out.println(i1);
    System.out.println(i2);

The result will be this:

    2019-10-27T05:00:00Z
    2019-10-27T04:00:00Z

The difference stems from the fact that in the Amsterdam timezone, the 27th of October has an extra hour. When we convert to Instant the timezone information is lost, so adding a day will add only 24 hours.

LocalDateTime is a different beast alltogether. It represents a date and time without timezone information. It does not represent a moment in Time. It is useful for writing things such as "Christmas morning starts at december 25th 00:00:00". This is true regardless of timezone, and as such a ZonedDateTime or Instant would not be appropriate.

like image 174
Joost Lambregts Avatar answered Sep 18 '22 10:09

Joost Lambregts