从UNIX纪元时间创建日历时日期不正确(1970年的某个时候)?

时间:2012-05-28 05:57:08

标签: java datetime

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

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

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

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

当我使用以下命令将unix时间转换为python中的字符串格式时:

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.有人可以帮忙吗?

3 个答案:

答案 0 :(得分:6)

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

试试:

    c.setTimeInMillis(1333436817 * 1000L);

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

答案 1 :(得分:1)

tibo的{p> The Answer是正确的。我的其他想法如下。

使用TIMESTAMP WITH TIME ZONE

您提到在Postgres中使用数据类型TIMESTAMP WITHOUT TIME ZONE。该类型仅适用于与任何特定时区无关的日期时间。例如,“圣诞节从2015年12月25日午夜开始”转换为任何特定时区的不同时刻。例如,圣诞节开始于巴黎,而不是蒙特利尔。此数据类型很少适用于商业应用。请参阅Postgres专家的帖子Always use 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类。这些新类的灵感来自Joda-Time库,由JSR 310定义,并由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 Time时代开始计算整秒数,构建一个瞬间。

long secondsSinceUnixEpoch = 1_333_436_817L ;
Instant instant = Instant.ofEpochSecond( secondsSinceUnixEpoch );
ZoneId zoneId = ZoneId.of( "Asia/Tehran" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

答案 2 :(得分:-2)

java Date库设计不好而且功能不强。我无法真正帮助你解决问题,但我可以给你一个建议,试试Joda calendar