从时间戳构造java.util.Date对象时的时区问题

San*_*ndy 0 java timezone date

我正面临着时区问题.让我试着描述:

我的Web应用程序和数据库运行在具有与当地时区(印度/加尔各答即UTC + 5:30)不同的时区(欧洲/马德里,即UTC + 1)的服务器上.

假设我当地的当前时间是:2014年1月15日星期三14:35:00,服务器当前时间是:2014年1月15日星期三10:05:00 CET,即延迟4:30.

现在,当我尝试使用我的网页(GUI)中的日历选择来保存数据库上的日期时间时,我所选择的日期时间是:Wed Jan 15 18:30:00,即将保存的最终日期在DB正在成为1月15日星期三14:00:00(看到差异正好是4:30小时滞后时间).

让我告诉你上面流程的编码部分.

从我的网页日历中选择 - >将所选日期时间的时间戳(长)传递给我的服务器端控制器 - >在服务器端,我正在构建java.util.Date对象并保存到DB,如下所示:

java.util.Date newDt = new java.util.Date(timeStampInMillis);
Run Code Online (Sandbox Code Playgroud)

这里,timeStampInMillis是long,我从GUI中选择的日期时间转换而来.

这里它将该服务器的当前时区(UTC + 01:00)中的给定时间戳保存,这就是保存的日期时间如何滞后4:30小时.

但我想保存,因为它是从日历GUI中选择的日期时间.

我有一些解决方案,比如在我的服务器端控制器中传递构造Date对象的时间戳,我可以从我的日历GUI传递所选日期时间的String表示,然后解析格式并保存到DB中.

但我想知道我是否可以使用Timezone API做任何事情.

希望我的问题对你很清楚.如果没有,请澄清您的疑问.

需要你的帮助...

谢谢.

Bas*_*que 5

问题不明确

你的问题可以写得更好.您应该尝试将其缩小到一个非常具体的示例.您甚至没有指定讨论中的毫秒值.

服务器时间

服务器几乎总是设置为UTC/GMT时区而没有夏令时.在某些系统(如Mac OS X)上,这很困难.在这种情况下,将机器的时区设置为"Atlantic/Reykjavik",因为冰岛全年保持UTC/GMT,没有任何夏令时废话.

避免使用java.util.Date

与Java捆绑在一起的java.util.Date和.Calendar类非常麻烦.

其中一个难点是,虽然Date没有分配时区,但其toString方法在渲染字符串时使用默认时区.所以对于天真的程序员来说,似乎 Date没有时区.

使用Joda-Time库或与Java 8捆绑在一起的新java.time.*类.搜索StackOverflow以获取两者的许多示例.

全球思考,本地化

您的大多数业务逻辑和数据库存储都应以UTC/GMT(无时区偏移)完成.像Postgres这样的称职数据库默认会这样做.

作为一般规则,仅切换到用于呈现给用户的时区.

时区

始终指定时区.不要依赖默认时区,因为这会导致生产中的意外或机器更改时区的任何时间.

避免使用三字母代码,因为它们既不标准也不唯一.使用适当的时区名称.

在像这样的列表中查找您的时区名称(稍微过时,阅读详细信息).在你的问题中,你提到"印度/加尔各答",我认为是错误的.应该是"亚洲/加尔各答".

ISO 8601

如果必须序列化,请仅使用ISO 8601格式.这种格式是人类可读的,明确的,并且明确定义.

印度时区示例:2014-01-19T12:38:31 + 05:30

UTC/GMT"Zulu"的示例:2013-11-22T18:28.023Z

java.sql.*类

使用java.sql.*类通过JDBC与数据库进行通信.

您通过传递自1970年开始的毫秒来构造java.sql.Timestamp对象.在Joda-Time中,调用getMillis以获取要传递的值.

避免毫秒

通常,我更愿意避免处理毫秒来跟踪时间.人们往往会遇到麻烦,因为有些系统会在几秒,几毫秒或几纳秒的时间内跟踪时间.此外,有许多时代在使用,并不总是1970年第一天的Unix风格.

我尝试传遍:

示例代码

但是如果你确定你的毫秒值代表自1970年第一天起以UTC/GMT为单位的真实毫秒数,那么就将这种代码与Joda-Time一起使用.注意'L'将数字标记为长整数.

DateTime dateTime = new DateTime( 1390276603054L );

DateTime dateTimeSpain = dateTime.toDateTime( DateTimeZone.forID( "Europe/Madrid" ) );
DateTime dateTimeIndia = dateTime.toDateTime( DateTimeZone.forID( "Asia/Kolkata" ) );
DateTime dateTimeUtcGmt = dateTime.toDateTime( DateTimeZone.UTC );

// For database.
java.sql.Timestamp timestamp = new java.sql.Timestamp( dateTimeSpain.getMillis() );
Run Code Online (Sandbox Code Playgroud)

转储到控制台......

System.out.println( "dateTime (default time zone): " + dateTime );
System.out.println( "dateTimeSpain: " + dateTimeSpain );
System.out.println( "dateTimeIndia: " + dateTimeIndia );
System.out.println( "dateTimeUtcGmt: " + dateTimeUtcGmt );
System.out.println( "timestamp: " + timestamp ); // "toString" uses default time zone.
Run Code Online (Sandbox Code Playgroud)

跑的时候......

dateTime (default time zone): 2014-01-20T19:56:43.054-08:00
dateTimeSpain: 2014-01-21T04:56:43.054+01:00
dateTimeIndia: 2014-01-21T09:26:43.054+05:30
dateTimeUtcGmt: 2014-01-21T03:56:43.054Z
timestamp: 2014-01-20 19:56:43.054
Run Code Online (Sandbox Code Playgroud)

关于java.time

该java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式的Joda-Time项目建议迁移到java.time类.

要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

您可以直接与数据库交换java.time对象.使用符合JDBC 4.2或更高版本的JDBC驱动程序.不需要字符串,不需要课程.java.sql.*

从哪里获取java.time类?

该ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.