如何确保测试始终在同一时区运行

Kir*_*ari 2 java timezone unit-testing epoch datetime-format

我有一个函数可以将 Unix 纪元时间解析为yyyy-MM-dd'T'HH:mm:ss.SSSXXX如下格式,以便将其导出到文件中:

    public static final SimpleDateFormat REQIF_DATE_FORMAT_WITH_MILLIS
        = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

    public static String convertEpochStringToReqifDateString(String epochString) {
        Date timestamp = new Date(Long.parseLong(epochString));
        return REQIF_DATE_FORMAT_WITH_MILLIS.format(timestamp);
    }
Run Code Online (Sandbox Code Playgroud)

现在,我对此导出进行了测试,但是当它们在本地通过时,它们在服务器上失败,因为它显然位于不同的时区。具体来说,差异如下:

LAST-CHANGE="2017-03-13T21:36:44.261+01:00"
LAST-CHANGE="2017-03-13T20:36:44.261Z"
Run Code Online (Sandbox Code Playgroud)

我已经在测试之前尝试运行一些东西,以确保测试始终在同一时区运行,例如:

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Run Code Online (Sandbox Code Playgroud)
System.setProperty("user.timezone", "UTC");
Run Code Online (Sandbox Code Playgroud)

以及 JUnitPioneer 注释:

@DefaultTimeZone("UTC")
Run Code Online (Sandbox Code Playgroud)

...但是,它们似乎都没有影响解析输出。

对此我能做什么?我想要的只是某种方法来确保我的测试在同一时区运行,无论运行的机器位于何处,以便我可以正确测试导出。

Arv*_*ash 6

java.time

日期java.util时间 API 及其格式化 APISimpleDateFormat已经过时且容易出错。建议完全停止使用它们并切换到现代 Date-Time API *

您可以使用Instant.ofEpochMilli将纪元毫秒转换为Instant然后使用Instant#toString. 但是,Instant#toString如果秒的小数部分为零,则忽略它们。因此,如果您需要严格采用模式 的值,yyyy-MM-dd'T'HH:mm:ss.SSSXXX则可以将 转换InstantOffsetDateTime并使用 对其进行格式化DateTimeFormatter

java.time使用现代日期时间 API 的解决方案:

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // An example epoch milliseconds
        long millis = 1631113620000L;

        Instant instant = Instant.ofEpochMilli(millis);
        String strDateTime = instant.toString();
        System.out.println(strDateTime);

        // If you need the value strictly in the pattern, yyyy-MM-dd'T'HH:mm:ss.SSSXXX
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
        OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);
        strDateTime = odt.format(dtf);
        System.out.println(strDateTime);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

2021-09-08T15:07:00Z
2021-09-08T15:07:00.000Z
Run Code Online (Sandbox Code Playgroud)

ONLINE DEMO

从Trail: Date Time中了解有关现代日期时间 API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,则可以使用ThreeTen-Backport,它将大多数java.time功能向后移植到 Java 6 和 7。如果您正在处理 Android 项目和 Android API level 仍然不符合 Java-8,请检查通过脱糖可用的 Java 8+ API以及如何在 Android 项目中使用 ThreeTenABP