如何使用 DateTimeFormatter 正确格式化 JSON (Javascript) 的 Java LocalDateTime?

How to format properly a Java LocalDateTime for JSON (Javascript) using a DateTimeFormatter?

提问人:sentenza 提问时间:10/11/2023 最后编辑:sentenza 更新时间:10/11/2023 访问量:73

问:

我需要将 Java 格式化为与此格式匹配的 JSON 字符串:java.time.LocalDateTime

2023-09-17T00:00:00.000+00:00

我正在考虑用以下命令定义我的 LocalDateTime:DateTimeFormatter.ISO_DATE_TIME

date.plusDays(daysToAdd)
   .atZone(ZoneOffset.UTC)
   .format(DateTimeFormatter.ISO_DATE_TIME)

但这会产生:

2023-09-17T00:00:00Z

此日期格式是否有预定义的格式化程序?我是否需要创建自定义 DateTimeFormatter,如果是这样,您能否提供此格式的示例?

编辑

我最终使用了基于 Mark Rotteveel 的示例解决方案的格式化程序以及随后对这个问题的评论:

val jsonDateTimeFormatter: DateTimeFormatter = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ISO_LOCAL_DATE)
    .appendLiteral('T')
    .appendPattern("HH:mm:ss.SSS")
    .appendOffset("+HH:MM", "+00:00")
    .toFormatter()
Scala Java-Time

评论

1赞 Mark Rotteveel 10/11/2023
有什么问题?它是偏移量 00:00 的可接受呈现,大多数解析器都支持它。无论如何,如果您确实需要 +00:00,则需要使用 for 偏移量创建自定义模式,另请参阅 DateTimeFormatter 文档。2023-09-17T00:00:00Zxxx
0赞 sentenza 10/11/2023
我需要复制 DateTime 的确切格式。我看到我也可以使用 DateTimeFormatterBuilder,但我想知道这个特定格式是否有预定义的格式。我正在寻找一个可能的示例解决方案来添加..000+00:00
2赞 Mark Rotteveel 10/11/2023
如果您有非零小数秒(MILLI_OF_SECOND值),您编辑的解决方案(顺便说一句,您通常不应该在问题中这样做)将无法正常工作。另请参阅对我的回答的评论。
0赞 sentenza 10/11/2023
谢谢你指出@OleV.V.已根据您的建议进行修补

答:

3赞 Mark Rotteveel 10/11/2023 #1

没有标准的格式化程序可以给出您想要的确切结果。offset 0 的使用是标准的(可能源自 ISO 8601,但我懒得验证)。Z

对于所需的格式,您需要构建它(请参阅第一个示例)或使用模式(请参阅第二个示例)。我的例子是用 Java 编写的,但我认为它将直接转换为 Scala:

public static void main(String[] args) {
    var date = LocalDateTime.parse("2023-09-17T00:00:00");

    var fm = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral('T')
            .appendValue(HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(MINUTE_OF_HOUR, 2)
            .appendLiteral(':')
            .appendValue(SECOND_OF_MINUTE, 2)
            .appendFraction(MILLI_OF_SECOND, 3, 3, true)
            .appendOffset("+HH:MM", "+00:00")
            .toFormatter();

    System.out.println(date.atOffset(ZoneOffset.UTC).format(fm));
}

对于您的要求,这里最重要的部分是:

  • .appendFraction(MILLI_OF_SECOND, 3, 3, true)

    确保小数秒以 3 位数字呈现。

  • .appendOffset("+HH:MM", "+00:00")

    将偏移量呈现为 (例如),将偏移量 0 呈现为 。{+/-}HH:mm-01:00+00:00

输出:

2023-09-17T00:00:00.000+00:00

您还可以使用基于模式的格式化程序:

DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")

使用 确保三个小数位,并将偏移量呈现为 ,将偏移量 0 呈现为 。.SSSxxx{+/-}HH:mm+00:00

请注意,最好将这些格式化程序中的任何一个仅用于格式化日期,并用于解析,因为它更灵活和宽松。ISO_DATE_TIME

评论

0赞 Mark Rotteveel 10/11/2023
(注意:此答案的早期版本代替了 ,这会产生错误的结果)ISO_DATEISO_LOCAL_DATE
0赞 sentenza 10/11/2023
非常感谢。我设法使用以下方法使它满足我的需求:val jsonDateTimeFormatter: DateTimeFormatter = new DateTimeFormatterBuilder() .append(DateTimeFormatter.ISO_LOCAL_DATE) .appendLiteral('T') .append(DateTimeFormatter.ISO_LOCAL_TIME) .appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true) .appendOffset("+HH:MM", "+00:00") .toFormatter()
0赞 sentenza 10/11/2023
我也用于解析,因为在测试过程中,正如您已经预料到的那样,我在某些边缘情况下遇到了解析错误。ISO_DATE_TIME
2赞 Mark Rotteveel 10/11/2023
关于使用 (vs ) 的好点。但是,追加然后使用将无法正常工作(也追加分数)。例如,如果您的日期以 120 毫秒为小数秒,则最终会得到(请注意 )。+HH:MM+HH:mmISO_LOCAL_TIMEappendFractionISO_LOCAL_TIME2023-09-17T00:00:00.12.120+00:00.12.120
1赞 Mark Rotteveel 10/11/2023
@sentenza 无论如何,使用而不是构建器可能更简单。DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")