1

I want to know how to write JUnit test case for below spring forwrd-transition in Canada. please see below information

Canada's Yukon, represented by America/Whitehorse and America/Dawson, advanced to -07 year-round, beginning with its spring-forward transition on 2020-03-08, and will not fall back on 2020-11-01

see this link https://www.iana.org/time-zones

I need the code in Java 7 and I need to write in Joda-Time.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161

2 Answers2

0

java.time

I recommend that you use java.time, the modern Java date and time API, for your date and time work.

@Test
void doesNotFallBackToMinus8InNovember2020() {
    ZoneId whitehorse = ZoneId.of("America/Whitehorse");
    ZoneOffset offsetAtAbsentTransition
            = LocalDateTime.of(2020, Month.NOVEMBER, 1, 1, 0)
                    .atZone(whitehorse)
                    .withLaterOffsetAtOverlap()
                    .getOffset();
    assertEquals(ZoneOffset.ofHours(-7), offsetAtAbsentTransition);
}

In the same way for America/Dawson.

On my JUnit 5 the test fails:

org.opentest4j.AssertionFailedError: expected: <-07:00> but was: <-08:00>
  at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
  at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:195)
  at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:184)
  at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:179)
  at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1124)
(many more lines)

This is because I haven’t got the latest update to the time zone database.

My Java erroneously “thinks” that the clock is turned back from 2 AM to 1 AM on November 1. This is the error that you want the test to catch. So the wall clock will show 01:00 twice, once with offset -07:00 (correct) and once with offset -08:00 (wrong). To catch the wrong one, we need to use withLaterOffsetAtOverlap(). On an updated Java installation this call will not make any difference because there won’t be any overlap.

Edit: You may of course also take a date in the middle of the winter rather than the exact time of when the transition is not supposed to happen. I’d probably do both, just in case.

Edit 2:

i need the above code in java 7. how can we write the same in java 7

You use ThreeTen Backport, that backport of java.time, the modern Java date and time API, to Java 6 and 7. Then you just use exactly the same code. See the links at the bottom for the backport. You don’t need to upgrade your production code to java.time (even though there would be advantages of doing so) in order to use java.time in (one of) your unit tests.

As you said after updating to new time zone database the assert statement works??

It should. I didn’t try myself, but that was the idea.

Question: How to use the backport of java.time with Java 7?

java.time just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Edit 3: Joda-Time

i want to use joda time istead of java.time but iam struggling at getting getoffset as you written in the code. could you please tell me that the same code in joda time

I really see no compelling reason why you should want to use Joda-Time for this when you can use ThreeTen Backport and thus java.time, the successor of Joda-Time. From the Joda-Time home page:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

I know you’re using Java 7; but if you are adding an external dependency to your tests, why not add the best and most modern one you can get?

In any case, here’s an equivalent JUnit 4 test for Joda-Time:

@Test
public void test() {
    DateTimeZone timezone = DateTimeZone.forID("America/Whitehorse");
    Instant dt = new DateTime(2020, 11, 1, 1, 0, timezone)
            .withLaterOffsetAtOverlap()
            .toInstant();
    long offsetInMilliseconds = timezone.getOffset(dt.getMillis());
    assertEquals(TimeUnit.HOURS.toMillis(-7), offsetInMilliseconds);
}

Again, on Joda-Time 2.9.9 and Java 7 it fails:

java.lang.AssertionError: expected:<-25200000> but was:<-28800000>
  at org.junit.Assert.fail(Assert.java:88)
  at org.junit.Assert.failNotEquals(Assert.java:834)
(etc.)

You notice that the failure message includes milliseconds values that are somewhat harder to read then the offsets reported in the failure message from the java.time test above.

I am no Joda-Time expert, but if I have understood correctly, Joda-Time keeps its own copy of the time zone database. So upgrading your Java installation is not the right means for getting the test to pass. Instead you need to upgrade your Joda-Time. Instructions are on the Joda-Time website, see the link at the bottom.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    i need the above code in java 7. how can we write the same in java 7 – Kanakasundar Sarma May 07 '20 at 12:17
  • Hi Ole. As you said after updating to new time zone database the assert statement works?? – Kanakasundar Sarma May 07 '20 at 12:25
  • you explanation was very helpful. Thanks – Kanakasundar Sarma May 08 '20 at 11:02
  • please check my solution in the below. Can i do like that – Kanakasundar Sarma May 08 '20 at 11:10
  • i want to use joda time istead of java.time but iam struggling at getting getoffset as you written in the code. could you please tell me that the same code in joda time – Kanakasundar Sarma May 08 '20 at 17:52
  • caould you please guide me how to wrote your same code in joda time???? – Kanakasundar Sarma May 08 '20 at 17:59
  • I am chasing a moving target here. First you said nothing about Java version or library restrictions, and I answered the question. Then you required Java 7 and I modified my answer to accommodate that. Now you’re asking for Joda-Time. It’s no longer the same question. And there’s no strong reasons why you should want to use Joda-Time when you can use the ThreeTen Backport. – Ole V.V. May 10 '20 at 17:45
  • the assert statement(assertEquals(ZoneOffset.ofHours(-7), offsetAtAbsentTransition) in the method are causing failures in my existing test cases.i did not understand how it is happening. for every testcase failure In failure trace the error is showing at this assert statement. Is this because of order of test execution? i dont have idea how to solve – Kanakasundar Sarma May 12 '20 at 16:46
  • yes. if that assert statement passes then i am not getting any failure. but this assert statement obviously will fail as you know that we have not updated tz db. But how after adding your test method causes failures in my existing test cases. – Kanakasundar Sarma May 12 '20 at 17:00
  • 1
    i found that my test class is parameterized test class. so that's why it is executing the same test over and over again causing failures. – Kanakasundar Sarma May 13 '20 at 12:26
0

@ole that assert statement is not generalizable assertion. i think we could do this calculation at Nov,1st and the day before. my idea is if we subtract on value from the other, we will get -1,0,+1. so we can detect spring forward,normalday and backward. Main thing is i need to write in joda time. is this below code amy not be correct. because getoffset is not getting as you write in your code.

    DateTimeZone timezone = DateTimeZone.forID("America/Whitehorse");
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
    DateTime dateTimeStart = formatter.parseDateTime("2020-11-1T01:00:00");
    dateTimeStart.withZone(timezone).withLaterOffsetAtOverlap();
    DateTime dateTimeStop = formatter.parseDateTime("2020-10-31T01:00:00");
    dateTimeStop.withZone(timezone).withLaterOffsetAtOverlap();
    assertEquals((dateTimeStart.getMillis() / 10000), (dateTimeStop.getMillis() / 10000));
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161