3

We are currently migrating from Joda-Time to java.time. I have the following doubts about the fromDateFields()method. Old joda code:

Date date = new Date(); //some java Date
LocalDateTime lt = LocalDateTime.fromDateFields(date);

A colleague migrated it to the following lines (java.time code):

lt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

Is that correct? The Joda-Time docs describe the method fromeDateFieldslike this:

Constructs a LocalDateTime from a java.util.Date using exactly the same field values.

Each field is queried from the Date and assigned to the LocalDateTime. This is useful if you have been using the Date as a local date, ignoring the zone.

What would be the correct way to reach the same result?

Update (just found the following solution):

lt= LocalDateTime.from(date.toInstant());
Lonzak
  • 9,334
  • 5
  • 57
  • 88
  • 1
    I would say that your colleagues code is correct, however if you want to be sure to get exact same result, implement the same method. See Joda-Time source: https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/LocalDateTime.java#L232. – Andreas Jan 31 '18 at 17:49
  • 1
    Looks correct. Keep in mind that the joda doc also says: "the local field values are transferred, calculated using the JDK time zone data" – Meno Hochschild Jan 31 '18 at 17:52
  • Didn't think of looking at the Joda-time source code. Good hint! Also just found the following solution which looks better? `LocalDateTime.from(date.toInstant()); ` Personally I don't like the zone part in the above code... – Lonzak Jan 31 '18 at 18:16

1 Answers1

3

I looked at Joda-Time source, and the fromDateFields method uses the getXXX methods from java.util.Date to get the values for the date/time fields. Something like that (I'm using Joda-Time 2.9.9):

return new LocalDateTime(
    date.getYear() + 1900,
    date.getMonth() + 1,
    date.getDate(),
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    (((int) (date.getTime() % 1000)) + 1000) % 1000
);

If you look at the javadoc, you'll see that all these methods return the correspondent value interpreted in the local time zone. Which means that it's implicity using the JVM default timezone.

Actually, looking at Date source code, all the getters call normalize(), which is a method that uses the default timezone to convert the fields.

You said that Personally I don't like the zone part, but in Joda-Time, it's implicity/indirectly using the default timezone.

And it makes sense to use a zone, because a java.util.Date represents a point in the timeline (a specific instant), without any timezone information. The same instant can correspond to a different date and time in different parts of the world, so you need a timezone to do this conversion.

Joda-Time uses the Date::getXXX methods, which implicity uses the default timezone. But in java.time, things must be more explicit, so you must use a ZoneId object.

By the way, your solution (LocalDateTime.from(date.toInstant())) didn't work for me. In Java 8, it gives an error:

java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: 2018-02-01T10:50:16.882Z of type java.time.Instant

So you'll need to convert the Date to Instant, then tell in what timezone you want that, and then get the local part, just as you're already doing:

LocalDateTime dt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

Or:

// the result is the same
LocalDateTime dt = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());

Although java.time forces you to use a timezone, I believe it's a good thing, because it makes you think about it, instead of doing some "magic" behind the scenes.

And you can even change it to another timezones if needed (such as ZoneId.of("America/New_York")). Even if you end up using the JVM's default, it was a conscient choice - ideally, because some people just use the default without thinking about it.

jodarules
  • 31
  • 2