繁体   English   中英

从UNIX时代创建日历时,日期不正确(有时是1970年)?

[英]Incorrect date (sometime in 1970) when creating Calendar from UNIX epoch time?

我有一个表,存储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 3.1和openjdk 6的PostgreSQL 8.4.11。有人可以帮忙吗?

1333436817 * 1000的结果对于整数而言太大,因此会溢出。 在这种情况下,Java不会自动为您升级类型。

试试看:

    c.setTimeInMillis(1333436817 * 1000L);

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

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

TIMESTAMP WITH TIME ZONE

您提到在Postgres中使用数据类型TIMESTAMP WITHOUT TIME ZONE 该类型仅适用于与任何特定时区无关的日期时间。 例如,“圣诞节从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定义并由ThreeTen-Extra项目扩展的Joda-Time库。

最终,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 );

Java Date库的设计不正确,但功能不完善。 我真的无法帮助您解决您的问题,但我可以为您提供尝试Joda日历的建议

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM