1

I have two DateTime instances, A and B, where:

DateTime A = new DateTime(2018, 11, 4, 1, 00, 0).plusHours(1);
DateTime B = new DateTime(2018, 11, 4, 2, 00, 0);

println("A: "+ A +", "+ A.getChronology() +", ms "+ A.getMillis());
println("B: "+ B +", "+ B.getChronology() +", ms "+ B.getMillis());
println("A == B is "+ A.equals(B));

produces:

A: 2018-11-04T01:00:00.000-05:00, ISOChronology[America/New_York], ms 1541311200000
B: 2018-11-04T02:00:00.000-05:00, ISOChronology[America/New_York], ms 1541314800000
A == B is false

How do I compare A and B to see if they are the same instance?

Take a closer look at how A and B are instantiated. The point is that both A and B actually refer to the same moment in time, that is when the clock is set back from EDT to EST in NYC.

pist
  • 165
  • 4
Norcal
  • 11
  • 2

2 Answers2

1

To compare, you're correctly using equals. But it's returning false because they're not the same point in time. If you look at their values, you'll see that A is actually one hour before B:

A: 2018-11-04T01:00:00.000-05:00, ISOChronology[America/New_York], ms 1541311200000
B: 2018-11-04T02:00:00.000-05:00, ISOChronology[America/New_York], ms 1541314800000

The result of getMillis() are also different, meaning that those dates are not the same point in time.

That's because new DateTime(2018, 11, 4, 1, 00, 0) produces a date/time that's still in EDT ("2018-11-04T01:00:00.000-04:00" -> 1 AM in -04:00 offset).

One hour later (plusHours(1)), you should get 2 AM in offset -04:00, but that's the instant when DST ends in New York: clocks are set 1 hour back to 1 AM, and the offset changes to -05:00 - that's why A is 1 AM at -05:00.

B, on the other hand, is already in EST (not in DST anymore), so it's set to 2 AM in -05:00. It's one hour after A.


When DST ends, we have this strange situation where a local time exists twice (in this case, the times between 1AM and 1:59AM occur twice: in -04:00 offset, and then in -05:00 offset), and Joda-Time by default chooses the offset before the DST changeover (-04:00).

You can override this, though, using withLaterOffsetAtOverlap(), which will take the offset after DST ends.

// new DateTime creates 2018-11-04T01:00:00.000-04:00
DateTime A = new DateTime(2018, 11, 4, 1, 00, 0)
    // adjust to offset after DST ends (2018-11-04T01:00:00.000-05:00)
    .withLaterOffsetAtOverlap()
    // add 1 hour
    .plusHours(1);
DateTime B = new DateTime(2018, 11, 4, 2, 00, 0);

// now A and B are the same instant
System.out.println(A.equals(B)); // true
studx
  • 39
  • 3
  • My question was about how to compare, not how to create the DateTime instances, as I don't create those instances. But the fact of the matter remains that they are representing the same actual moment, whether you chose to represent it via EST or EDT. Its like saying the two ratios 10/5 and 8/4 are different, but they do evaluate to the same number, ie, 2. So when I compare 10/5 with 8/4, I can use 10/5 == 8/4. Claiming they are not the same instance is wrong, since when I convert to UTC, both will give me exactly the same – Norcal Mar 21 '18 at 18:02
  • @Norcal if `getMillis()` returns different values, then they are **not** the same instant - they don't correspond to the same UTC instant, just call `toInstant()` and you'll see that A and B are different. I'm just explaining, **based on the code in the question**, why A and B are different. If you still think they are the same, there's nothing more I can do. Good luck – studx Mar 21 '18 at 18:08
  • @Norcal Anyway, using `equals` is the right way to compare, so if it returns `false`, then they're not the same. Your output shows that A is 1 AM and B is 2 AM, so I'm failing to see how they can be the same. – studx Mar 21 '18 at 18:11
  • Perhaps you tested in some environment where America/New_York is not the default timezone - in this case, A and B will be the same. But when the default timezone is America/New_York, which seems to be the case, then you have the DST effects I mention in my answer (actually, that's how I could reproduce the error - by setting my default timezone to New York, because using another one, this doesn't happen) - I'm just guessing of course. If you say they're the same, why the output in the question shows different values for A and B? – studx Mar 21 '18 at 18:13
  • @Norcal Just to make it clear, A and B are not the same because they don't evaluate to the same UTC instant. `A` is `2018-11-04T01:00:00.000-05:00`, and converting to UTC (with `A.toInstant()`) I get `2018-11-04T06:00:00.000Z`, while `B` is `2018-11-04T02:00:00.000-05:00` and converting to UTC (`B.toInstant()`) gives `2018-11-04T07:00:00.000Z`. Using the code you provided in the question (and assuming the default timezone is America/New_York, based on the output of `getChronology()`), A is one hour before B, so they are **not** the same. – studx Mar 21 '18 at 18:46
1

According to javadoc, you can use:

  • equals: equality based on the millisecond instant, chronology and time zone
  • isEqual: Is this instant equal to the instant passed in comparing solely by millisecond

But using the dates in your example, both methods return false. And that makes sense, mainly because the values returned by getMillis() are different, so the dates really don't correspond to the same UTC instant, as explained by the other answer.

yousx
  • 11
  • 1