5

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

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是 UTC (GMT-0)。日期的输出值如下:

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

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

我尝试了所有组合以尝试将 UTC 值dstDateTime作为 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

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

在方法的参数方面:

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

任何帮助是极大的赞赏。

缺口。

编辑 3

你好,马特,

非常感谢你的回复。我们得到和你一样的结果。不知道关于打印等的事情。更具体地说:

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) 正在传递给数据库(无法发布图像,没有足够的点......)。数据类型是直接时间戳,没有字符串操作。也许eclipse调试器String.println()也在使用函数,不确定..

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

亲切的问候,

缺口。

4

5 回答 5

24

我希望这可以为某人节省 3 天的废话时间。在代码中的某个逻辑位置设置默认时区。使必须设置环境变量等的事情更便携。您可以通过在代码、构造函数等逻辑上添加以下内容来做到这一点:

DateTimeZone.setDefault(DateTimeZone.UTC);

你可以打印UTC,连接UTC任何东西......

于 2013-09-06T17:14:39.217 回答
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()或来获取 UTC 时间.toDateTime(DateTimeZone.UTC)。但即使你不调用两个,你仍然会在调用时得到 UTC 值getMillis()

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

创建 时java.sql.Timestamp,您从 1970 年 1 月 1 日 UTC 开始以毫秒为单位传递。只有当您显示它时,它才会将本地时区应用于结果。

假设您将它作为 a 传递给数据库Timestamp并且没有进行一些中间字符串表示,那么您应该没问题。仅仅因为它看起来像您调用时的本地时间System.out.println,并不意味着它在内部是本地时间。

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

于 2013-09-05T02:10:27.960 回答
1

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

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

db.default.url="jdbc:mysql://localhost/continuum?characterEncoding=UTF-8&serverTimezone=UTC"

(添加“&serverTimezone=UTC”)

于 2015-05-08T19:12:30.017 回答
0

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

如果您date已经在srcTZ'sDateTimeZone中,但加载为LocalDateTime,那么您应该返回

new Timestamp(date.toDateTime(srcTZ).toDateTime(DateTimeZone.UTC).getMillis());

或者,如果您确定dateUTC 已经是 GMT+0,那么您可以返回

new Timestamp(date.toDateTime(DateTimeZone.UTC).getMillis());

最后,大多数数据库接受时间戳作为 ISO 格式的字符串,这是默认toString输出:

date/*.toDateTime(srcTZ)*/.toDateTime(DateTimeZone.UTC).toString()
于 2013-09-04T05:23:47.710 回答
0

您需要 UTC 值还是可以简单地使用 Timestamp.toString() 方法?这将为您提供一个格式化的时间字符串,以便在 SQL 语句中使用。

于 2013-09-04T05:05:09.840 回答