SimpleDateFormat [0] 问题

SimpleDateFormat [0] issue

我在下面 SimpleDateFormat 代码

Date date = new Date();
DateFormat inpuDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS'Z'");
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
String dateStr = inpuDateFormat.format(cal.getTime());

它在我的开发服务器上完美运行,但在沙盒实例上失败并出现以下错误。

org.junit.ComparisonFailure: expected:<...20-08-12T19:06:02.85[0]Z> but was:<...20-08-12T19:06:02.85[]Z>

我处理过

dateStr = dateStr.replace("[0]","");
dateStr = dateStr.replace("[]","");

但是,我仍然不明白为什么我的日期在不同的服务器实例上不同,有没有更好的方法来处理它

尝试删除 'Z' 周围的引号,因为 'Z' 是一个常量,而没有引号则表示 'time zone':

DateFormat inpuDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

(顺便说一句,在大多数情况下,您希望使用小数点后三位表示毫秒:“SSS”。)

java.time

当然有更好的方法来处理它。使用 java.time,现代 Java 日期和时间 API,而不是 DateDateFormatSimpleDateFormatCalendar.

    Instant now = Instant.now();
    String dateStr1 = now.toString();
    System.out.println(dateStr1);

一个 运行 的输出是:

2020-07-24T18:06:07.988093Z

你注意到秒上输出了六位小数,而不是两位。在其他 运行 中,您可能有三位小数或根本没有小数。别担心,对于大多数目的,你会没事的。打印的格式是 ISO 8601,根据 ISO 8601,秒的小数位数,甚至秒的存在,都是可选的。因此,无论您需要什么字符串,只要需要 ISO 8601 格式,就应该接受上述代码片段中的字符串。

我正在利用 Instant.toString() 生成 ISO 8601 格式这一事实,因此我们不需要任何格式化程序。

如果由于某些奇怪的原因你确实需要在秒上正好有两位小数,请使用格式化程序来指定(编辑:现在输出 Z):

    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSX")
            .withZone(ZoneOffset.UTC);
    String dateStr2 = formatter2.format(now);
    System.out.println(dateStr2);

2020-07-24T18:06:07.98Z

格式模式字符串中的DateTimeFormatter(与SimpleDateFormat相对)大写S表示秒的分数,你是自由放置其中的一到九位以获得一到九位小数。

你的代码出了什么问题?

首先,您从 JUnit 测试中得到的消息是:

org.junit.ComparisonFailure: expected:<...20-08-12T19:06:02.85[0]Z> but was:<...20-08-12T19:06:02.85[]Z>

方括号是 JUnit 提醒我们注意预期值和实际值之间差异的方式。所以它们不是这些价值观的一部分。 JUnit 告诉我们的是,该值应该以 .850Z 结尾,但实际上只以 .85Z 结尾。所以少了一个零。你的测试可能太严格了,因为正如我所说,有两位小数还是三位小数应该无关紧要。 02.8502.850 只是表示完全相同值的不同方式。

方括号的这个作用也解释了为什么替换字符串中的 [0][] 没有帮助:方括号从来不在字符串中,所以替换没有做任何改变到字符串。

其次,对SimpleDateFormat(与DateTimeFormatter相反)格式化模式字母大写S表示毫秒。因此,输入除其中三个以外的任何其他数字都是没有意义的,并且会给您错误的结果。在你的代码中你放了两个。在十分之九的情况下,毫秒值在 100 到 999 之间,在这种情况下 SimpleDateFormat 打印所有三个数字,尽管只有两个模式字母 S。这可能解释了为什么您的单元测试在您的开发环境中通过了。顺便说一句,在您的沙盒上,时间以 2.085 秒结束。正确的渲染方式包括 02.0802.085。您的 SimpleDateFormat 都没有选择。对它来说,毫秒值 85 要在两个位置呈现,因此它会在 765 毫秒后生成 02.85,这是错误的值。你的单元测试反对,而这曾经只有两位小数,而不是三位。

第三,不是你问的,但是无论是使用麻烦的SimpleDateFormat还是现代的DateTimeFormatter你都必须永远硬编码Z 作为格式模式字符串中的文字。尾随 Z 表示 UTC 或与 UTC 的偏移量为零。它需要作为偏移量打印(如果是这种情况则解析),否则你会得到错误的结果。确保获得 Z 而不是 +02:00 偏移量的方法是确保指定偏移量为 0。这就是为什么我把 .withZone(ZoneOffset.UTC) 放在格式化程序上的原因。

链接