为什么时间戳没有以UTC时间存储?

时间:2016-01-06 19:38:16

标签: java postgresql timezone jodatime jooq

我的store_time_period应该有两个TIMESTAMP WITH TIMEZONE。我正在使用joda org.joda.time.DateTime而不是java.sql.Timestamp而我正在初始化我的变量,例如这样:

DateTime day_from = new DateTime(DateTimeZone.UTC);

然而,在phpPgAdmin中我看到的是这个字符串:

  

2016-01-06 20:14:09.339 + 01

而不是

  

2016-01-06 19:14:09.339 + 00

表示UTC时间。为什么会这样?

这是我转换DateTimeTimeStamp的方式:

public class JodaDateTimeConverter implements Converter<Timestamp, DateTime> {
    @Override
    public DateTime from(Timestamp timestamp) {
        DateTime dateTime = new DateTime(timestamp.getTime());
        return dateTime;
    }

    @Override
    public Timestamp to(DateTime dateTime) {
        Timestamp timestamp = new Timestamp(dateTime.getMillis());
        return timestamp;
    }

    @Override
    public Class<Timestamp> fromType() {
        return Timestamp.class;
    }

    @Override
    public Class<DateTime> toType() {
        return DateTime.class;
    }
}

这是store_time_period的PostgreSQL代码:

CREATE TABLE store_time_period (

    -- PRIMARY KEY

    id BIGSERIAL PRIMARY KEY,

    -- ATTRIBUTES

    day_from TIMESTAMP WITH TIME ZONE NOT NULL, 
    day_to TIMESTAMP WITH TIME ZONE NOT NULL
);

3 个答案:

答案 0 :(得分:2)

此行为符合timestamp with time zone数据类型的定义,来自: http://www.postgresql.org/docs/current/static/datatype-datetime.html

  

对于带时区的时间戳,内部存储的值始终为   UTC(通用协调时间,传统上称为格林威治标准时间   时间,GMT)。具有指定显式时区的输入值是   使用该时区的适当偏移量转换为UTC。如果   在输入字符串中没有声明时区,则假定它是   在系统的TimeZone参数指示的时区中,是   使用时区的偏移量转换为UTC。

     

当输出带有时区值的时间戳时,始终为   从UTC转换为当前时区,并显示为   该地区的当地时间。要查看另一个时区的时间,也可以   更改时区或使用AT TIME ZONE构造(参见第9.9.3节)。

使用粗体回答您问题的部分。

答案 1 :(得分:1)

在您的代码中,构建DateTime时,您将使用接受long时间戳的构造函数。时间戳本身是基于UTC的,尽管在postgres中使用timestamp with time zone,因为postgres不会存储时区。

该特定构造函数说in the javadocs

  

使用默认时区中的1970-01-01T00:00:00Z 构造一个设置为ISOChronology的毫秒的实例。

关键是当您未指定时区时,将使用默认时区(系统的本地时区或您使用DateTimeZone.setDefault明确设置的时区)。

如果您可以使用其他方式确定时区(可能存储在应用程序或数据库的其他位置),则可以使用the constructor of DateTime that accepts a DateTimeZone as a second parameter

答案 2 :(得分:1)

这是JDBC 数据库级别的问题。您在java.sql.Timestamp上使用Converter<T, U>作为<T>类型。 jOOQ会将此时间戳绑定到JDBC,后者指定Timestamp是您的本地时间

请注意,jOOQ的代码生成器尚未完全支持TIMESTAMP WITH TIME ZONE。这是待处理的功能请求: https://github.com/jOOQ/jOOQ/issues/4429

如果你想绑定joda时间的DateTime,你必须使用org.jooq.Binding来自己实现JDBC级别的绑定。这样,您就可以完全控制发送到服务器的内容并从中检索。