简体   繁体   English

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

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

I have a table which stores both unix time and the equivalent time stamp. 我有一个表,存储Unix时间和等效时间戳。

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

The database is in PostgreSQL. 该数据库位于PostgreSQL中。 database has been configured with Asia/Tehran time zone. 数据库已配置了Asia/Tehran时区。 for example: 例如:

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

When I convert the unix time into string format in python with: 当我使用以下命令将Unix时间转换为python中的字符串格式时:

datetime.datetime.fromtimestamp(1333436817)

it gives me: datetime.datetime(2012, 4, 3, 11, 36, 57) which is correct and equal to database. 它给我: datetime.datetime(2012, 4, 3, 11, 36, 57)正确,等于数据库。 But when I do this conversion with java using: 但是当我使用以下方式使用java进行此转换时:

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

It gives: Sat Jan 24 06:12:35 IRST 1970 . 给出: Sat Jan 24 06:12:35 IRST 1970 The system itself is running under Asia/Tehran time zone. 系统本身在Asia/Tehran时区下运行。 I'm using PostgreSQL 8.4.11 on Debian 6.0.5 with python 3.1 and openjdk 6. Can anyone help? 我在Debian 6.0.5上使用PostgreSQL 3.1和openjdk 6的PostgreSQL 8.4.11。有人可以帮忙吗?

The result of 1333436817 * 1000 is too big for an integer so it overflows. 1333436817 * 1000的结果对于整数而言太大,因此会溢出。 Java will not promote the type for you automatically in this case. 在这种情况下,Java不会自动为您升级类型。

Try that: 试试看:

    c.setTimeInMillis(1333436817 * 1000L);

Notice the L that force your calculation to use long integer. 注意, L强制您的计算使用长整数。

The Answer by tibo is correct. tibo 的答案是正确的。 My additional thoughts follow. 我的其他想法如下。

Use TIMESTAMP WITH TIME ZONE TIMESTAMP WITH TIME ZONE

You mentioned using the data type TIMESTAMP WITHOUT TIME ZONE in Postgres. 您提到在Postgres中使用数据类型TIMESTAMP WITHOUT TIME ZONE That type is only for a date-time not tied to any specific time zone. 该类型仅适用于与任何特定时区无关的日期时间。 For example, "Christmas starts at midnight on December 25, 2015" translates to a different moment in any particular time zone. 例如,“圣诞节从2015年12月25日午夜开始”转化为任何特定时区的不同时刻。 Christmas starts earlier, for example, in Paris than in Montréal. 例如,圣诞节开始于巴黎,而不是蒙特利尔。 This data type is rarely appropriate in business apps. 此数据类型在业务应用程序中很少使用。 See this Postgres expert's post, Always use TIMESTAMP WITH TIME ZONE . 请参阅此Postgres专家的帖子, 始终使用TIMESTAMP WITH TIME ZONE

In Postgres, the other type TIMESTAMP WITH TIME ZONE means "with respect for time zone". 在Postgres中,另一种类型TIMESTAMP WITH TIME ZONE表示“相对于时区”。 Any offset from UTC or time zone information with incoming data is used to adjust to UTC. 与输入数据的UTC或时区信息之间的任何偏移都用于调整UTC。 That accompanying offset or time zone info is then discarded. 然后,该附带的偏移量或时区信息将被丢弃。 Some databases preserve this info, but not Postgres. 一些数据库保留此信息,但不保留Postgres。

Your statement: 您的声明:

The database is in PostgreSQL. 该数据库位于PostgreSQL中。 database has been configured with Asia/Tehran time zone. 数据库已配置了亚洲/德黑兰时区。

…makes no sense. …没有意义。 The data type TIMESTAMP WITHOUT TIME ZONE has no time zone (though you may regard it as UTC), and the data type TIMESTAMP WITH TIME ZONE is always in UTC . 数据类型TIMESTAMP WITHOUT TIME ZONE没有时区(尽管您可以将其视为UTC),并且数据类型TIMESTAMP WITH TIME ZONE始终为UTC With regard to storing date-time values, there is no such time zone configuration. 关于存储日期时间值,没有这样的时区配置。

What you may have meant is that the default time zone for a database session is set to Tehran time zone. 您可能的意思是将数据库会话的默认时区设置为德黑兰时区。 See the SET TIME ZONE command. 请参阅SET TIME ZONE命令。 But that setting is mere window-dressing, applied when generating a string representation of the date-time value. 但是,该设置仅仅是窗口整理,是在生成日期时间值的字符串表示形式时应用的。 When using JDBC and the java.sql.Timestamp class, that session setting is irrelevant as no Strings are being generated by Postgres. 使用JDBC和java.sql.Timestamp类时,该会话设置无关紧要,因为Postgres不会生成任何字符串。 Your attention to time zones should be on the Java side (see code below) rather than Postgres. 您对时区的关注应该在Java方面(请参见下面的代码),而不是Postgres。

Generally speaking, your host server operating system should be set to UTC. 一般来说,您的主机服务器操作系统应设置为UTC。 But your app's code should never depend on that, instead specifying any desired/expected time zone. 但是,您的应用程序代码永远不应依赖于此,而应指定任何期望/期望的时区。

java.time java.time

In Java 8 and later, the new java.time package supplants the old java.util.Date/.Calendar classes. 在Java 8和更高版本中,新的java.time包取代了旧的java.util.Date/.Calendar类。 These new classes were inspired by Joda-Time library, defined by JSR 310, and extended by the ThreeTen-Extra project. 这些新类的灵感来自由 JSR 310定义并由ThreeTen-Extra项目扩展的Joda-Time库。

Eventually JDBC drivers will be updated to directly handle these new types. 最终,JDBC驱动程序将被更新以直接处理这些新类型。 In the mean time use the conversion methods added to both the old and new classes. 同时,使用添加到新旧类中的转换方法。

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

Or given your count of whole seconds from the Unix Time epoch, construct an Instant. 或者给定您从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 );

The java Date library has a bad design and not that functional. Java Date库的设计不正确,但功能不完善。 I can't really help you with your problem but i can give you an advice to try Joda calendar 我真的无法帮助您解决您的问题,但我可以为您提供尝试Joda日历的建议

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

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