Setting timezone for maven unit tests on Java 8
Asked Answered
W

1

44

How do I set the timezone for unit tests in maven surefire on Java 8?

With Java 7 this used to work with systemPropertyVariables like in the following configuration, but with Java 8 the tests just use the system timezone.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <systemPropertyVariables>
      <user.timezone>UTC</user.timezone>
    </systemPropertyVariables>

Why is that, and how do I fix it?

Wyon answered 5/5, 2014 at 6:32 Comment(1)
Use the full Etc/UTC instead of just UTC because three-letter time zone abbreviations are considered deprecated since they can cause confusion.Boil
W
85

Short answer

Java now reads user.timezone earlier, before surefire sets the properties in systemPropertyVariables. The solution is to set it earlier, using argLine:

<plugin>
  ...
  <configuration>
    <argLine>-Duser.timezone=UTC</argLine>

Long answer

Java initializes the default timezone, taking user.timezone into account the first time it needs it and then caches it in java.util.TimeZone. That now happens already when reading a jar file: ZipFile.getZipEntry now calls ZipUtils.dosToJavaTime which creates a Date instance that initializes the default timezone. This is not a surefire-specific problem. Some call it a bug in JDK7. This program used to print the time in UTC, but now uses the system timezone:

import java.util.*;

class TimeZoneTest {
  public static void main(String[] args) {
    System.setProperty("user.timezone", "UTC");
    System.out.println(new Date());
  }
}

In general, the solution is to specify the timezone on the command line, like java -Duser.timezone=UTC TimeZoneTest, or set it programmatically with TimeZone.setDefault(TimeZone.getTimeZone("UTC"));.

Full'ish example:

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        ... could specify version, other settings if desired ...
        <configuration>
          <argLine>-Duser.timezone=UTC</argLine>
        </configuration>
      </plugin>
    </plugins>
  </build>
Wyon answered 5/5, 2014 at 6:32 Comment(11)
Uhm, if you use Java 8, why use Date at all? Use the new DateTime, LocalDateTime etcOops
@Oops That's irrelevant, new Date() is just a simple example to be able to compare with Java 7. The new time classes use the same default timezone, so they have exactly the same problem.Wyon
It's weird that mvn -Duser.timezone=UTC doesn't work either. Only <argLine> works.Continuate
Setting TimeZone.setDefault(TimeZone.getTimeZone("UTC")); in @Before worked for me. argLine didn't not sure why. On junit4.10 and mvn3Caprice
We can use <argLine>-Duser.timezone="Europe/London"</argLine> alsoGriffe
add user.timezone in MAVEN_OPTS eg: export MAVEN_OPTS=-Duser.timezone=GMT+8Mercie
For me this worked. If it works command line but not IntelliJ (and jacoco is also at play) see https://mcmap.net/q/128259/-maven-jacoco-plugin-error or use the @Before workaround from zengr's comment...Sponger
@SanghyunLee That applies the system property to the Maven process. By default, Surefire / Failsafe will run tests in a separate process. See "Forked Test Execution" hereTatter
element <argLine> is not allowed?Glim
WARNING: Be careful not to override the javaagent argLine, or risk spending hours to figure out why jacoco no longer works for instance...Sacrosanct
Use the full Etc/UTC instead of just UTC because three-letter time zone abbreviations are considered deprecated since they can cause confusion.Boil

© 2022 - 2024 — McMap. All rights reserved.