2

我有一个存储 unix 时间和等效时间戳的表。

CREATE TABLE tbl_time
(
    time_unix BIGINT,
    time_timestamp TIMESTAMP WITHOUT TIME ZONE
);

该数据库在 PostgreSQL 中。数据库已配置Asia/Tehran时区。例如:

1333436817, 2012-04-03 11:36:57

当我在 python 中将 unix 时间转换为字符串格式时:

datetime.datetime.fromtimestamp(1333436817)

它给了我:datetime.datetime(2012, 4, 3, 11, 36, 57)这是正确的并且等于数据库。但是当我使用 java 进行这种转换时:

Calendar c = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tehran"));
c.setTimeInMillis(1333436817 * 1000);
System.out.println(c.getTime());

它给出:Sat Jan 24 06:12:35 IRST 1970. 系统本身在Asia/Tehran时区下运行。我在 Debian 6.0.5 上使用 PostgreSQL 8.4.11 和 python 3.1 和 openjdk 6。有人可以帮忙吗?

4

3 回答 3

6

1333436817 * 1000 的结果对于整数来说太大了,所以它会溢出。在这种情况下,Java 不会自动为您提升类型。

试试看:

    c.setTimeInMillis(1333436817 * 1000L);

请注意,L这会强制您的计算使用长整数。

于 2012-05-28T06:14:50.030 回答
1

tibo的回答是正确的。我的其他想法如下。

采用TIMESTAMP WITH TIME ZONE

您提到TIMESTAMP WITHOUT TIME ZONE在 Postgres 中使用数据类型。该类型仅适用于与任何特定时区无关的日期时间。例如,“圣诞节从 2015 年 12 月 25 日午夜开始”翻译为任何特定时区的不同时刻。例如,圣诞节在巴黎比在蒙特利尔更早开始。这种数据类型很少适用于业务应用程序。请参阅此 Postgres 专家的帖子,始终使用 TIMESTAMP WITH TIME ZONE

在 Postgres 中,另一种类型的TIMESTAMP WITH TIME ZONE意思是“尊重时区”。使用传入数据与 UTC 或时区信息的任何偏移都用于调整为 UTC。然后丢弃伴随的偏移量或时区信息。一些数据库保留此信息,但不保留 Postgres。

您的声明:

该数据库在 PostgreSQL 中。数据库已配置亚洲/德黑兰时区。

…没有意义。数据类型TIMESTAMP WITHOUT TIME ZONE没有时区(尽管您可能将其视为 UTC),并且数据类型TIMESTAMP WITH TIME ZONE始终为UTC。关于存储日期时间值,没有这样的时区配置。

您可能的意思是数据库会话的默认时区设置为德黑兰时区。见SET TIME ZONE命令。但该设置只是装点门面,在生成日期时间值的字符串表示时应用。当使用 JDBC 和 java.sql.Timestamp 类时,该会话设置是无关紧要的,因为 Postgres 没有生成任何字符串。您对时区的关注应该放在 Java 端(参见下面的代码)而不是 Postgres。

一般来说,您的主机服务器操作系统应设置为 UTC。但是您的应用程序的代码不应该依赖于此,而是指定任何所需/预期的时区。

java.time

在 Java 8 及更高版本中,新的 java.time 包取代了旧的 java.util.Date/.Calendar 类。这些新类受到 JSR 310 定义的 Joda-Time 库的启发,并由ThreeTen-Extra项目扩展。

最终 JDBC 驱动程序将被更新以直接处理这些新类型。同时使用添加到旧类和新类中的转换方法。

java.sql.Timestamp ts = myResultSet.getTimestamp( 1 ); 
Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "Asia/Tehran" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

或者给定您从Unix 时间纪元开始的整秒数,构造一个 Instant。

long secondsSinceUnixEpoch = 1_333_436_817L ;
Instant instant = Instant.ofEpochSecond( secondsSinceUnixEpoch );
ZoneId zoneId = ZoneId.of( "Asia/Tehran" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
于 2015-08-16T08:23:55.233 回答
-2

java Date 库的设计很糟糕,而且没有那么实用。我真的不能帮你解决你的问题,但我可以给你一个建议来试试Joda calendar

于 2012-05-28T06:13:22.627 回答