【问题标题】:Date object formatting日期对象格式
【发布时间】:2020-03-02 21:45:30
【问题描述】:

我正在尝试在 Java 中格式化输入日期,在调试器中如下所示。

result = {Date@13861} "2019-09-29"
 fastTime = 1569729600000
 cdate = {Gregorian$Date@13873} "2019-09-29T00:00:00.000-0400"

我需要将其转换为:2019-09-28 20:00:00.0

我的代码:

DateTimeFormatter dateTimeformatter_Test = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

LocalDate tempDate = LocalDate.parse(date.toString(), DateTimeFormatter.ofPattern( "yyyy-MM-dd" , Locale.US ));

但下面的行会引发运行时错误:Unsupported field: HourOfDay

String result= tempDate.format(dateTimeformatter_Test);

请问我在这里错过了什么?

谢谢。

【问题讨论】:

  • 请提供一个minimal reproducible example 来重现确切的错误。我们应该能够复制代码并自己运行它,而不会出现您所询问的错误之外的任何其他错误。
  • date.toString() 是个坏主意,因为格式未指定并且可能会更改。看起来您有 java.util.Datejava.util.CalendarLocalDate 也没有时间概念,因此您需要提供一些方法来注入它(即 LocalDateLocalDateTime :/)
  • 我认为您的区域偏移量错误,因为2019-09-29T00:00:00.000-04002019-09-29 04:00:00 UTC 时间相同,而不是2019-09-28 20:00:00.0,所以除非您在America/New_York 时区和目标时区-08:00 (America/Anchorage),你的价值观没有意义。
  • 我觉得你说的不是parse而是format?! 解析是将字符串转换为内部形式,在本例中为日期时间对象。 格式化是相反的转换。请清楚你在追求哪一个?
  • 你还需要这种格式做什么?询问是因为它可疑地看起来像一个 SQL 时间戳,并且您不应该将时间戳作为字符串传递给您的 SQL 数据库。通过OffsetDateTmeInstantLocalDateTime

标签: java date-formatting date


【解决方案1】:

您的问题缺少时区信息,但这是将2019-09-29 转换为2019-09-28 20:00:00.0 的一种方法:

System.out.println(
        LocalDate.parse("2019-09-29")
        .atStartOfDay(ZoneOffset.UTC)
        .withZoneSameInstant(ZoneId.of("America/New_York"))
        .format(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S")));

输出

2019-09-28 20:00:00.0

这是一种完全不同的方式,显示您在调试器中看到的值:

TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));

java.sql.Date result = java.sql.Date.valueOf("2019-09-29");
System.out.println("result = " + result);

long fastTime = result.getTime();
System.out.println("fastTime = " + fastTime);

System.out.println("cdate = " + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(result));

ZonedDateTime zdt = Instant.ofEpochMilli(fastTime).atZone(ZoneId.of("America/Anchorage"));
System.out.println("zdt = " + zdt.format(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S")));

输出

result = 2019-09-29
fastTime = 1569729600000
cdate = 2019-09-29T00:00:00.000-0400
zdt = 2019-09-28 20:00:00.0

【讨论】:

    【解决方案2】:

    如果这是为您的 SQL 数据库提供时间戳:不要将时间戳作为字符串提供给您的数据库。给它一个适当的日期时间对象。从 JDBC 4.2 开始,这意味着:

    • 对于 SQL timestamp with time zone(推荐用于绝大多数用途)提供OffsetDateTime;许多司机也接受Instant
    • 对于没有时区的 SQL timestamp,请提供 LocalDateTime

    例如:

        java.sql.Date inputDate = getFromSomewhere();
        OffsetDateTime dateTimeForDatabase = inputDate.toLocalDate()
                .atStartOfDay(ZoneOffset.UTC)
                .toOffsetDateTime();
        System.out.println(dateTimeForDatabase);
    
        PreparedStatement stmt = yourDatabaseConnection.prepareStatement(
                "insert into your_table(your_timestamp_col) values (?)");
        stmt.setObject(1, dateTimeForDatabase);
        int rowsInserted = stmt.executeUpdate();
    

    中间打印语句的示例输出:

    2019-09-29T00:00Z

    Z 表示 UTC,因此这与您要求的 2019-09-28 20:00:00.0 是同一时间点,假设您的 JVM 的时区是北美东部时间(美国/多伦多或美国/纽约)的某个变体.

    您在调试器中看到的对象看起来很像java.sql.Date 对象,所以我以这种类型为出发点。 java.sql.Date 类的设计很差,但实际上是对已经设计得很差的 java.util.Date 类的真正破解。它也早已过时。因此,如果您可以改用现代类型,例如LocalDate,那将是有利的。

    你的代码出了什么问题?

    LocalDate 是没有时间的日期,例如 2019-09-29。您试图使用格式模式yyyy-MM-dd'T'HH:mm:ss.SSS'Z' 格式化一个。所以你要求在结果中包含一天中的时间,但正如我所说,LocalDate 没有一天中的时间,所以这没有意义。您收到的错误消息实际上非常准确:

    不支持的字段:HourOfDay

    【讨论】:

      猜你喜欢
      • 2012-07-27
      • 2012-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多