UTC时间戳+ Joda时间

时间:2013-09-04 03:36:34

标签: java jodatime

我正在尝试使用Joda在一个简单的Java程序中获取UTC TimeStamp:

public Timestamp getCurrentUTC(LocalDateTime date, DateTimeZone srcTZ, DateTimeZone dstTZ, Locale l) {
    DateTime srcDateTime = date.toDateTime(srcTZ);
    DateTime dstDateTime = srcDateTime.toDateTime(dstTZ);

    System.out.println("UTC Time:" + dstDateTime.getMillis());      
    System.out.println("UTC Time:" + new Timestamp(dstDateTime.getMillis()));

    return new Timestamp(dstDateTime.getMillis());
}

该计划的输出如下:

UTC Time:1378265162047
UTC Time:2013-09-03 23:26:02.047

毫秒值是正确的UTC时间(即使用GMT-4时区确认) 第二个值是EST时区。

我需要的是UTC值不变为java.sql.Timestamp(即TZ独立), 用于数据库写入。这可能吗?

编辑1

DateTime srcDateTime = date.toDateTime(srcTZ);

DateTime dstDateTime = srcDateTime.toDateTime(dstTZ);

System.out.println("UTC Time:" + dstDateTime.getMillis());

我知道srcDateTime是本地日期(GMT-4),而dstDateTime是。{1}} UTC(GMT-0)。日期的输出值如下:

Source Date:2013-09-04T09:10:43.683-04:00

Destination Date: 2013-09-04T13:10:43.683Z

我尝试了所有组合,尝试将dstDateTime的UTC值作为java.sql.TimeStamp:

System.out.println("UTC Time:" + dstDateTime.getMillis());

System.out.println("UTC Time:" + new Timestamp(srcDateTime.toDateTime(DateTimeZone.UTC).getMillis()));

System.out.println("UTC Time:" + new Timestamp(dstDateTime.toDateTime(DateTimeZone.UTC).getMillis()));

用于测试的打印输出:

UTC Time:1378298760226 - Correct UTC

UTC Time:2013-09-04 08:46:00.226 - Incorrect Local Date Time instead of the Expected UTC

UTC Time:2013-09-04 08:46:00.226 - Incorrect Local Date Time instead of the Expected UTC

第一个打印行是正确的UTC时间戳。我所需要的只是同样的价值 作为类型java.sql.TimeStamp。我尝试的任何东西总是返回当地的日期时间 机器。

编辑2

我尝试了以下内容:

System.out.println("UTC Timestamp:" + date.toDateTime(srcTZ).getMillis());
System.out.println("UTC Timestamp:" + new Timestamp(date.toDateTime(srcTZ).getMillis()));

输出如下:

UTC Time:1378342856315 - Correct UTC Time
UTC Timestap:2013-09-04 21:00:56.315 - Local Time other than the expected UTC Time

每当我尝试转换为TimeStamp时,我都会丢失我所追求的有效UTC值。

就方法的参数而言:

srcTZ = DateTimeZone.forTimeZone(TimeZone.getTimeZone("America/Montreal")
dstTZ = DateTimeZone.forTimeZone(TimeZone.getTimeZone("Etc/UTC"))
Local l = new Locale("en", "CA")

非常感谢任何帮助。

尼克。

编辑3

Hello Matt,

非常感谢您的回复。我们得到的结果与您相同。不知道关于印刷等的事情。更具体地说:

System.out.println("UTC Timestamp:" + srcDateTime.toDateTime(dstTZ).getMillis());
System.out.println("UTC Timestamp:" + srcDateTime.toDateTime(dstTZ));
System.out.println("UTC Timestamp:" + new Timestamp(srcDateTime.toDateTime(dstTZ).getMillis()));

收益输出:

UTC Timestamp:1378389098468 - Correct UTC Timestap (Thu, 05 Sep 2013 13:51:38 GMT)
UTC Timestamp:2013-09-05T13:51:38.468Z - Correct UTC Time
UTC Timestamp:2013-09-05 09:51:38.468 - Local time is printed, UTC is expected

当我们意识到数据库存储本地时间而不是UTC时,问题引起了我的注意:

+---------------------+
| effectivedate       |
+---------------------+
| 2013-09-05 09:34:11 |
+---------------------+

Mysql时区设置为'-00:00'

mysql> SELECT CURRENT_TIMESTAMP;
+---------------------+
| CURRENT_TIMESTAMP   |
+---------------------+
| 2013-09-05 13:48:09 |
+---------------------+

使用eclipse调试器调试应用程序我们意识到本地日期时间(2013-09-05 09:51:38.468)正在传递给DB(无法发布图像,没有足够的点......)。数据类型是直接的TimeStamp,没有字符串操作。也许eclipse调试器也在使用String.println()函数,不确定..

我非常感谢调试我们的应用程序的所有帮助。不想占用这么多时间(没有双关语)和努力......

亲切的问候,

尼克。

5 个答案:

答案 0 :(得分:24)

我希望这可以节省3天的废话。在代码中将默认时区设置为逻辑。使事情变得更加便携,必须设置一个env变量等。你可以通过在代码,构造函数等逻辑上添加以下内容来实现这一点。:

DateTimeZone.setDefault(DateTimeZone.UTC);

你可以打印UTC,连接UTC无论......

答案 1 :(得分:6)

尝试这个简短的程序,它应该说明发生了什么:

LocalDateTime date = LocalDateTime.now();
DateTimeZone tz = DateTimeZone.getDefault();

System.out.println(date);
System.out.println(tz);
System.out.println("-----");
System.out.println(date.toDateTime(tz));
System.out.println(date.toDateTime(tz).toInstant());
System.out.println(date.toDateTime(tz).toDateTime(DateTimeZone.UTC));
System.out.println("-----");
System.out.println(date.toDateTime(tz).getMillis());
System.out.println(date.toDateTime(tz).toInstant().getMillis());
System.out.println(date.toDateTime(tz).toDateTime(DateTimeZone.UTC).getMillis());
System.out.println("-----");
System.out.println(new Timestamp(date.toDateTime(tz).getMillis()));
System.out.println(new Timestamp(date.toDateTime(tz).toInstant().getMillis()));
System.out.println(new Timestamp(date.toDateTime(tz).toDateTime(DateTimeZone.UTC).getMillis()));

在我的电脑上输出:

2013-09-04T19:08:35.111
America/Phoenix
-----
2013-09-04T19:08:35.111-07:00
2013-09-05T02:08:35.111Z
2013-09-05T02:08:35.111Z
-----
1378346915111
1378346915111
1378346915111
-----
2013-09-04 19:08:35.111
2013-09-04 19:08:35.111
2013-09-04 19:08:35.111

如您所见,您可以使用.toInstant().toDateTime(DateTimeZone.UTC)来加速UTC时间。但即使你打电话 ,你也会在致电getMillis()时获得UTC值。

所以问题不在于JodaTime。问题在于您如何评估结果。

创建java.sql.Timestamp时,您将在1970年1月1日UTC之后的毫秒内传递。仅当您显示时,它才会将当地时区应用于结果。

假设您将它作为Timestamp传递给数据库而没有做一些interm字符串表示,那么您应该没问题。只是因为它看起来像是拨打System.out.println的当地时间,并不意味着它是内部的当地时间。

java.sql.Timestamp类扩展java.util.Date - 这是从中获取此行为的地方。

答案 2 :(得分:1)

我挣扎了几个小时,终于找到了解决方案。

我正在使用PlayFramework - 不确定这是否会对任何人有所帮助,但对于我的数据库连接设置我必须使用:

promise

(添加'& serverTimezone = UTC')

答案 3 :(得分:0)

您需要UTC值还是只需使用Timestamp.toString()方法?这将为您提供在SQL语句中使用的格式化时间字符串。

答案 4 :(得分:0)

LocalDateTime已经排除了时区,这意味着它或者意味着字面意思是用户输入“他们的”时间的本地时间(例如,用于葬礼邀请,这将始终是在当地时间)或者它如果你提前计划,它已经是UTC了。

如果您的date已经在srcTZ的{​​{1}}中,但已加载为DateTimeZone,那么您应该返回

LocalDateTime

或者,如果您确定new Timestamp(date.toDateTime(srcTZ).toDateTime(DateTimeZone.UTC).getMillis()); 已经是UTC,即GMT + 0,那么您可以返回

date

最后,大多数数据库接受时间戳作为ISO格式的字符串,这是默认的new Timestamp(date.toDateTime(DateTimeZone.UTC).getMillis()); 输出:

toString