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,而不是 Date
、DateFormat
、SimpleDateFormat
或 Calendar
.
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.85
和 02.850
只是表示完全相同值的不同方式。
方括号的这个作用也解释了为什么替换字符串中的 [0]
和 []
没有帮助:方括号从来不在字符串中,所以替换没有做任何改变到字符串。
其次,对SimpleDateFormat
(与DateTimeFormatter
相反)格式化模式字母大写S
表示毫秒。因此,输入除其中三个以外的任何其他数字都是没有意义的,并且会给您错误的结果。在你的代码中你放了两个。在十分之九的情况下,毫秒值在 100 到 999 之间,在这种情况下 SimpleDateFormat
打印所有三个数字,尽管只有两个模式字母 S
。这可能解释了为什么您的单元测试在您的开发环境中通过了。顺便说一句,在您的沙盒上,时间以 2.085 秒结束。正确的渲染方式包括 02.08
和 02.085
。您的 SimpleDateFormat
都没有选择。对它来说,毫秒值 85 要在两个位置呈现,因此它会在 765 毫秒后生成 02.85
,这是错误的值。你的单元测试反对,而这曾经只有两位小数,而不是三位。
第三,不是你问的,但是无论是使用麻烦的SimpleDateFormat
还是现代的DateTimeFormatter
你都必须永远硬编码Z
作为格式模式字符串中的文字。尾随 Z
表示 UTC 或与 UTC 的偏移量为零。它需要作为偏移量打印(如果是这种情况则解析),否则你会得到错误的结果。确保获得 Z
而不是 +02:00
偏移量的方法是确保指定偏移量为 0。这就是为什么我把 .withZone(ZoneOffset.UTC)
放在格式化程序上的原因。
链接
- Oracle tutorial: Date Time 解释如何使用 java.time。
- Wikipedia article: ISO 8601
我在下面 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,而不是 Date
、DateFormat
、SimpleDateFormat
或 Calendar
.
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.85
和 02.850
只是表示完全相同值的不同方式。
方括号的这个作用也解释了为什么替换字符串中的 [0]
和 []
没有帮助:方括号从来不在字符串中,所以替换没有做任何改变到字符串。
其次,对SimpleDateFormat
(与DateTimeFormatter
相反)格式化模式字母大写S
表示毫秒。因此,输入除其中三个以外的任何其他数字都是没有意义的,并且会给您错误的结果。在你的代码中你放了两个。在十分之九的情况下,毫秒值在 100 到 999 之间,在这种情况下 SimpleDateFormat
打印所有三个数字,尽管只有两个模式字母 S
。这可能解释了为什么您的单元测试在您的开发环境中通过了。顺便说一句,在您的沙盒上,时间以 2.085 秒结束。正确的渲染方式包括 02.08
和 02.085
。您的 SimpleDateFormat
都没有选择。对它来说,毫秒值 85 要在两个位置呈现,因此它会在 765 毫秒后生成 02.85
,这是错误的值。你的单元测试反对,而这曾经只有两位小数,而不是三位。
第三,不是你问的,但是无论是使用麻烦的SimpleDateFormat
还是现代的DateTimeFormatter
你都必须永远硬编码Z
作为格式模式字符串中的文字。尾随 Z
表示 UTC 或与 UTC 的偏移量为零。它需要作为偏移量打印(如果是这种情况则解析),否则你会得到错误的结果。确保获得 Z
而不是 +02:00
偏移量的方法是确保指定偏移量为 0。这就是为什么我把 .withZone(ZoneOffset.UTC)
放在格式化程序上的原因。
链接
- Oracle tutorial: Date Time 解释如何使用 java.time。
- Wikipedia article: ISO 8601