【问题标题】:How to format Date object to match @JsonFormat?如何格式化日期对象以匹配@JsonFormat?
【发布时间】:2021-10-22 07:19:59
【问题描述】:

我对控制器有一个 json 格式的响应日期,如下所示:

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago")
private Date date;

所以当我发出一个 post call 时,它看起来像:

"date": "2021-08-20 14:17:43"

所以响应字符串看起来像这样{"date":"2021-05-21 14:23:44"}。在 JUnit 中,我手动创建了一个响应对象并设置了 Date 对象,因此我可以使用 Gson 将其转换为字符串,然后断言两者相等。 我试图通过尝试在我的 SpringMVC JUnit 测试用例中匹配这个:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
        
String formattedDate = sdf.format(new Date());
LocalDate localDate = LocalDate.parse(formattedDate);
        
Date date = Date.from(localDate.atStartOfDay(ZoneId.of("America/Chicago")).toInstant());

但由于yyyy-MM-ddHH:mm:ss 之间的空格,解析时出错:

java.time.format.DateTimeParseException: Text '2021-08-20 14:23:44' could not be parsed, unparsed text found at index 10

我认为我这样做可能效率低下,所以我想知道是否有更简单的方法来制作与 @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago") 格式匹配的 Date 对象

我正在尝试匹配响应正文,以便它通过 mockito 传递。

【问题讨论】:

  • 代替 SimpleDateFormat,您可以像这样使用 java.time.format.DateTimeFormatter:String formattedDate = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.of("America/Chicago")).format(LocalDateTime.now());
  • 有没有办法让它成为Date 对象?因为我需要使用 setter 来设置日期对象。
  • 我建议你不要使用Date。该课程设计不良且早已过时。而是仅使用来自java.time, the modern Java date and time APILocalDateTime 和/或Instant
  • 您希望您的单元测试测试哪种场景?在 Java 中创建响应对象?将响应对象转换为 JSON?将 JSON 转换为 Java 对象?抱歉,不清楚。

标签: java date datetime gson java.util.date


【解决方案1】:

您可能缺少日期反序列化器

@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
@JsonDeserialize(using = LocalDateTimeDeserializer.class)

【讨论】:

  • 这会做什么?我以为我只是想格式化 JUnit Date 对象,而不是 responsebody 日期对象
  • 你想在你的 JUnit 测试中测试什么?
  • 我正在尝试匹配响应正文,以便它通过 mockito 传递
【解决方案2】:

不要混合使用现代和传统的 Date-Time API

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-08-20 14:17:43";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse(strDate, dtf);
        System.out.println(ldt);

        // Get the required Instant
        ZonedDateTime zdtUtc = ldt.atZone(ZoneOffset.UTC);
        ZonedDateTime zdtChicago = zdtUtc.withZoneSameInstant(ZoneId.of("America/Chicago"));
        Instant instant = zdtChicago.toInstant();
        System.out.println(instant);
    }
}

输出:

2021-08-20T14:17:43
2021-08-20T14:17:43Z

ONLINE DEMO

java.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到modern Date-Time API*。但是,无论出于何种原因,如果您需要将Instant 的对象转换为java.util.Date 的对象,您可以这样做:

Date date = Date.from(instant);

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


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport 将大部分 java.time 功能反向移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

【讨论】:

  • 问题在于 Date 对象显示为Fri Aug 20 16:19:47 EDT 2021。但是我的 responsebody 通过@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago") 将日期显示为2021-08-20 14:17:43,因此这两种格式不会对齐
  • 我几乎只需要一个Date 对象,其格式为yyyy-MM-dd HH:mm:ss,时区为America/Chicago
  • @stackerstack - 我已根据您的要求对其进行了更新。如果有任何进一步的问题/疑问,请随时发表评论。
  • 有没有办法更新String strDate,因为它应该是传入的new Date(),而不是传入的硬编码预格式化字符串日期
  • @stackerstack - java.util.Date 对象仅表示时间轴上的一个瞬间——自 UNIX 纪元(格林威治标准时间 1970 年 1 月 1 日 00:00:00)以来毫秒数的包装;它没有任何时区或格式
【解决方案3】:

发布此内容只是为了尝试满足您想要实现的目标。但是您应该遵循@Arvind 的回答:

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;


SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
String formattedDate = sdf.format(new Date());

// Updated the lines below
LocalDateTime localDateTime = LocalDateTime.parse(formattedDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Date date = Date.from(localDateTime.atZone(ZoneId.of("America/Chicago")).toInstant());

【讨论】:

    【解决方案4】:

    如果您可以完全跳过 Date 类并在响应中使用现代 Java 日期和时间 API java.time 中的 InstantZonedDateTime,则最好。

    如果你无法避免使用过时的 Date 类

    ...我想知道是否有更简单的方法来制作Date 对象 这将匹配@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone = "America/Chicago")的格式

    基本编辑:这在很大程度上取决于您所说的匹配格式Date 既不能有格式也不能有时区。 JSON 中的字符串具有上述格式。 Date 没有,因为这是不可能的。时区 America/Chicago 既不在 JSON 中也不在 Date 中。它仅用于两者之间的转换。如果两个 Date 对象表示相同的时间点,则它们是相等的,仅此而已。当您询问格式化Date 以匹配@JsonFormat 时,这必然意味着将格式化为字符串

    要将像2021-08-20 14:23:44 这样的字符串转换为老式的Date 对象,我首先要静态定义格式和时区:

    private static final DateTimeFormatter FORMATTER
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ROOT);
    private static final ZoneId ZONE = ZoneId.of("America/Chicago");
    

    然后做:

        String responseDateString = "2021-08-20 14:23:44";
    
        Instant inst = LocalDateTime.parse(responseDateString, FORMATTER)
                .atZone(ZONE)
                .toInstant();
        Date oldfashionedDate = Date.from(inst);
        
        System.out.println(oldfashionedDate);
    

    我的时区的输出是:

    2021 年 8 月 20 日星期五 21:23:44 CEST

    如果我在运行前将时区设置为 America/Chicago,则更容易看出结果是正确的:

    2021 年 8 月 20 日星期五 14:23:44 CDT

    你的代码出了什么问题?

    首先,您是正确的,将Date 格式化为字符串只是为了将其解析回来是过于复杂的事情。其次,您注意到您的异常来自这一行:

    LocalDate localDate = LocalDate.parse(formattedDate);
    

    LocalDate 是没有时间的日期。所以它的单参数parse 方法只需要字符串中的2021-08-20,仅此而已。它在抱怨空格,不是因为它是空格,而是因为在预期的字符之后还有更多字符。

    【讨论】:

    • 因此,即时日期的格式在 JUnit 中显示为 Fri Aug 20 14:23:44 CDT 2021,而响应正文的结果将显示为 2021-08-20 14:23:44,因为 @JsonFormat。有没有办法让这两个匹配并相等,因为我需要对两者执行 assertEquals。
    • 没错,@stackerstack。但是 JSON 中的那个是一个字符串,而不是 Date,所以它们无论如何都不相等(JSON 是一种文本格式)。
    • @stackerstack 我有疑问,您的问题可能存在误解,我不知道。我在答案的开头附近进行了编辑,以将其清除,以防万一。阅读和学习。
    猜你喜欢
    • 2021-05-14
    • 1970-01-01
    • 2019-10-02
    • 1970-01-01
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多