【问题标题】:Converting date to timestamp with timezone in Java在Java中使用时区将日期转换为时间戳
【发布时间】:2021-03-28 19:33:46
【问题描述】:

我有一个 PostgreSQL 数据库,其中有一列定义为时间戳

我正在接收时区格式为 yyyy-MM-ddTHH:mm:ss.SSSX"的日期,例如2020-12-16T15:05:26.507Z。如果我想将其插入带有时间戳的列中,它将抛出 "Timestamp 格式必须是 yyyy-mm-dd hh:mm:ss"

我在做

Timestamp.valueOf("2020-12-16T15:05:26.507")

现在时区日期来自 JSON,所以我现在将其作为字符串字符串。

如何将其转换为简单的时间戳格式?至 2020-12-16 15:05:26

【问题讨论】:

  • 我建议你不要使用java.sql.Timestamp。该课程设计不良且早已过时。而是使用LocalDateTimeOffsetDateTime,两者都来自java.time, the modern Java date and time API
  • 对不起...日期是 2020-12-16T15:05:26.507Z
  • @user955165 - 如果其中一个答案解决了您的问题,您可以通过将其标记为已接受来帮助社区。接受的答案有助于未来的访问者自信地使用该解决方案。要mark an answer as accepted,您需要单击答案左侧的大勾号(✓)。

标签: java timestamp localdate


【解决方案1】:

我认为你可以使用另一个时间戳的 API

静态时间戳 valueOf(LocalDateTime dateTime)

并将您的代码更改为:

    LocalDateTime localDateTime = LocalDateTime.parse("2020-12-16T15:05:26.507");
    Timestamp.valueOf(localDateTime);

如果您想使用系统时区以外的其他时区,您还可以使用:ZonedDateTime

然后使用 ZonedDateTime 获取 localDateTime,并将其传递给 Timestamp.valueOf()。

【讨论】:

  • 对不起,我的意思是添加它是时区,所以我收到的 incming 日期和时间是 Z -> "2020-12-16T15:05:26.507Z" 以上将不起作用 LocalDateTime将无法解析它
【解决方案2】:

两个建议:

  1. 由于您收到的字符串包含 UTC 指示符 (Z),请将 UTC 时间保存到您的数据库中。如果允许,请将 PostgreSQL 数据库中的数据类型更改为 timestamp with time zone
  2. 使用现代 Java 日期和时间 API java.time。不要将日期和时间以TimestampString 的形式保存到数据库中。 java.sql.Timestamp 类设计不佳,是对已经设计不佳的 java.util.Date 类的真正破解,并且早已过时。

您从 JSON 获得的字符串是 ISO 8601 格式。这很棒,因为它是一个国际标准,而且 java.time 的类通常会本地解析 ISO 8601 格式,也就是说,没有任何显式的格式化程序。解析它:

    String fromJson = "2020-12-16T15:05:26.507Z";
    OffsetDateTime dateTime = OffsetDateTime.parse(fromJson);
    System.out.println(dateTime);

目前的输出:

2020-12-16T15:05:26.507Z

OffsetDateTime 还打印 ISO 8601 格式。插入 Postgress:

    String sql = "insert into your_table(your_timestamp_with_time_zone_col)"
            + " values(?);";
    PreparedStatement ps = yourDatabaseConnection.prepareStatement(sql);
    ps.setObject(1, dateTime);
    int rowsInserted = ps.executeUpdate();

如果您无法更改数据库中的数据类型,您需要将LocalDateTime 插入到您的timestamp(无时区)列中:

    LocalDateTime dateTime = OffsetDateTime.parse(fromJson)
            .atZoneSameInstant(ZoneOffset.UTC)
            .toLocalDateTime();
    
    String sql = "insert into your_table(your_timestamp_col) values(?);";

其余的和以前一样。

我选择转换为 UTC 以防万一。在您的示例中,字符串已经是 UTC,因此转换是无操作的;但可能并不总是这样,所以最好这样做。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。

【讨论】:

【解决方案3】:

下表总结了PostgreSQL 列类型与Java SE 8 日期时间类型的映射:

--------------------------------------------------
PostgreSQL                          Java SE 8
==================================================
DATE                                LocalDate
--------------------------------------------------
TIME [ WITHOUT TIMEZONE ]           LocalTime
--------------------------------------------------
TIMESTAMP [ WITHOUT TIMEZONE ]      LocalDateTime
--------------------------------------------------
TIMESTAMP WITH TIMEZONE             OffsetDateTime
--------------------------------------------------

请注意,不支持 ZonedDateTimeInstantOffsetTime / TIME [ WITHOUT TIMEZONE ]。另外请注意,所有OffsetDateTime 实例都必须位于UTC(其时区偏移量为+00:00 小时)。这是因为后端将它们存储为UTC

因此,有两种选择。

选项 - 1(推荐):

将列类型更改为TIMESTAMP WITH TIMEZONE。这是推荐的,因为您的日期时间字符串有Z,它代表Zulu 日期时间或UTC 日期时间。使用OffsetDateTime,您可以解析此日期时间字符串,而无需明确要求任何DateTimeFormatter

演示:

import java.time.OffsetDateTime;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odt = OffsetDateTime.parse("2020-12-16T15:05:26.507Z");
        System.out.println(odt);
    }
}

输出:

2020-12-16T15:05:26.507Z

下面是一个示例,说明如何将此 OffsetDateTime 用于 DB CRUD 操作:

OffsetDateTime odt = OffsetDateTime.parse("2020-12-16T15:05:26.507Z");
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, odt);
st.executeUpdate();
st.close();

选项 - 2:

如果您仍想保持列类型为TIMESTAMP [ WITHOUT TIMEZONE ],您可以从OffsetDateTime 获取LocalDateTime 并使用如下所示:

OffsetDateTime odt = OffsetDateTime.parse("2020-12-16T15:05:26.507Z");
LocalDateTime ldt = odt.toLocalDateTime();
PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, ldt);
st.executeUpdate();
st.close();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-16
    • 2014-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多