How to check LocalDateTime instance is local or UTC in java?

Viewed 7094

I have want to find whether my LocalDateTime instance holds local date&time or UTC date&time (like DateTime.Kind property in C#)

LocalDateTime date1=LocalDateTime.now(); // it is local

LocalDateTime date2=LocalDateTime.now(ZoneId.of("UTC")); // it is UTC

Anything like (date1.getKind() == Kind.UTC || date1.getKind() == Kind.Local) in Java?

2 Answers

The LocalDateTime object itself doesn't store the timezone information - it has only the date and time related fields: day, month and year; hour, minute, seconds and nanoseconds. But the now method uses a timezone or an offset to get the correct values for those fields.

That's because the answer to the questions "What day is today?" and "What time is it?" is not as simple as we might think.

It's common to think that the answer is as simple as taking a look at our calendar/cell phone/whatever and seeing the current date/time. But the technically correct answer is: "It depends".

It depends, basically, on where you are. At this moment, each place in the world has its own local date and time. For example, in July 5th, 2017: while it was 14h (or 2 PM) in São Paulo, it was 6 PM in London and 5 PM in UTC, but in Tokyo it was 2 AM of the next day (July 6th).

Each region in the world has specific rules to determine what's their local time during history, and of course it affects their local date. And the concept that maps a country/city/region to these rules is a timezone.

That's why the now method needs a timezone. The ZoneId object loads all the timezone data to check what's the current date and time in that zone and adjust the day/month/year/hour/minute/second/nanosecond values accordingly. The version that receives no parameters (LocalDateTime.now()) will use the system's default timezone, so the API always uses some timezone in the end.

The timezone (or the offset, such as ZoneOffset.UTC) is used to get the correct values for day, month, year, hour, minute, second and nanosecond, and then - in the case of LocalDateTime and any other classes that don't keep the zone - discarded.

So, the concept might be a little different from what you're thinking. If I do:

// ZoneOffset.UTC is equivalent to ZoneId.of("UTC")
LocalDateTime date = LocalDateTime.now(ZoneOffset.UTC);

What this code does is: "take the current date and time in UTC, and get just the date and time fields, discarding the timezone/offset information".

When I ran this code, the current date/time in UTC was 2017-09-25T12:15:43.570Z, so the LocalDateTime has the value equivalent to 2017-09-25T12:15:43.570 (without any timezone information, just the date and time fields). If I call now() without arguments, it'll use the JVM default timezone (in my case, it's America/Sao_Paulo), and the value will be 2017-09-25T09:15:43.570.

So, with a LocalDateTime you can get the values, but you can't know from which timezone those values came from, because it doesn't keep this information.

If you want a UTC date, you must use another classes, designed to keep this information:

  • Instant.now() - this will always get the current UTC instant
  • OffsetDateTime.now(ZoneOffset.UTC) - with this you can query for date and time fields (such as getDayOfMonth() or getHour())
  • ZonedDateTime.now(ZoneOffset.UTC) - for UTC, it's the same as OffsetDateTime, but if you use a different timezone, it handles all timezone specific data, such as Daylight Saving Time changes.

To check if such object is in UTC, one way is to use the getZone() method:

ZonedDateTime z = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println(z.getZone().equals(ZoneOffset.UTC)); // true

But if you use equivalents like ZoneId.of("UTC"), the equals method return false. So you could also check if z.getZone().getId() is equals to Z or UTC. With OffsetDateTime, it's similar:

OffsetDateTime odt = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(odt.getOffset().equals(ZoneOffset.UTC)); // true

With Instant you don't need to check, because it's always in UTC.

You can check all the available types in Oracle's date/time tutorial.


Both ZonedDateTime and OffsetDateTime can be converted to a LocalDateTime using the toLocalDateTime() method:

// dt will have the current date and time in UTC
LocalDateTime dt = ZonedDateTime.now(ZoneOffset.UTC).toLocalDateTime();

// or
LocalDateTime dt = OffsetDateTime.now(ZoneOffset.UTC).toLocalDateTime();

With this, the dt variable will have all the date and time fields (day/month/year, hour/minute/second/nanosecond) that corresponds to the current date/time in UTC. But it won't keep any timezone/offset information, so the LocalDateTime object itself can't know from which timezone those values came from.

I realize this question is a bit old, but I am learning Java and found myself trying to do something very similar. After some reading I found I could do what you are asking with this:

    public static void main (String args[]) {
    LocalDateTime now = LocalDateTime.now(Clock.systemDefaultZone()); // The clock argument is not really needed here.

    String pattern = "dd MMM yyyy HH:mm:ss"; // Setup your format for output
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern);
    System.out.println("Local time is: " + dtf.format(now));

    LocalDateTime utc = LocalDateTime.now(Clock.systemUTC()); // Define alternate timezone
    System.out.println("GMT/UTC is: "+dtf.format(utc));
}
Related