When the Duration.between() in Java DateTime return negative value

Viewed 3882

I am preaparing for the Java OCP Test, and in the mock test there is a question about Java DateTime like this:

Given that New York is 3 hours ahead of Los Angeles, what will the following code print?

LocalDateTime ldt = LocalDateTime.of(2017, 12, 02, 6, 0, 0);         
ZonedDateTime nyZdt = ldt.atZone(nyZone);
ZonedDateTime laZdt = ldt.atZone(laZone);
Duration d = Duration.between(nyZdt, laZdt);
System.out.println(d);

And the correct answer is PT3H but I am a little bit confused here is if the book gives the wrong answer or not?

Given is NY 3 hours ahead of LA, does it mean, for example, NY is 5:00 and then LA will be 2:00. So the Duration.between(5,2) should be PT-3H because according to the Javadoc: The result of this method can be a negative period if the end is before the start. To guarantee to obtain a positive duration call abs() on the result., and in this case "2" is before "5" so the result should be PT-3H, not PT3H.

What do you think, which one is correct?

4 Answers

Another approach will be to convert nyZdt and laZdt to Instant.

LocalDateTime ldt = LocalDateTime.of(2017, 12, 02, 6, 0, 0);  

ZoneId nyZone = ZoneId.of("America/New_York");
ZonedDateTime nyZdt = ldt.atZone(nyZone);
System.out.println(nyZdt.toInstant()); //Prints 2017-12-02T11:00:00Z

ZoneId laZone = ZoneId.of("America/Los_Angeles");
ZonedDateTime laZdt = ldt.atZone(laZone);
System.out.println(laZdt.toInstant()); //Prints 2017-12-02T14:00:00Z

Duration d = Duration.between(nyZdt, laZdt);
System.out.println(d); //Prints PT3H

In this example you can see more clearly why the minus sign does not appear in your output. As you can see end IS NOT before start. Start is 2017-12-02T11:00:00Z and end is 2017-12-02T14:00:00Z, with other words, LA is after NY, so the difference is: PT3H.

What do you do if you are asked to find the difference between 2 km 300 m1 and 1020 m 45 cm?

Your answer: I will convert each distance in the same unit and then subtract one from the other.

This is exactly what you need to do in order to understand and solve this problem. You need to convert both the date-times to the same timezone and then find the duration.

ZonedDateTime#withZoneSameInstant

Use it to get a copy of a ZonedDateTime with a different time-zone, retaining the instant. In simple terms, it will return you the local date-time in the target time-zone.

Demo:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        ZoneId nyZone = ZoneId.of("America/New_York");
        ZoneId laZone = ZoneId.of("America/Los_Angeles");
        LocalDateTime ldt = LocalDateTime.of(2017, 12, 02, 6, 0, 0);
        ZonedDateTime nyZdt = ldt.atZone(nyZone);
        ZonedDateTime laZdt = ldt.atZone(laZone);
        System.out.println("laZd ----------------------------> " + laZdt);

        // Convert the nyZdt to LA date-time
        ZonedDateTime nyZdtConverted = nyZdt.withZoneSameInstant(laZone);
        System.out.println("nyZdt converted to LA date-time -> " + nyZdtConverted);

        Duration d = Duration.between(nyZdt, laZdt);
        System.out.println(d);

        d = Duration.between(nyZdtConverted, laZdt);
        System.out.println(d);
    }
}

Output:

laZd ----------------------------> 2017-12-02T06:00-08:00[America/Los_Angeles]
nyZdt converted to LA date-time -> 2017-12-02T03:00-08:00[America/Los_Angeles]
PT3H
PT3H

As you can see, nyZdt is 3 hours before laZd and hence the duration is PT3H.


1 km stands for kilometres, m stands for metre and cm stands for centimetre

Related