joda time to Date 不一致的时区

joda time to Date inconsistent time zones

我有大量日期要存储在使用 BST 的服务器上的数据库 运行 中:

  1. 2015-09-23
  2. 2024-05-07
  3. 2024-03-13

但是它们在数据库中存储为:

  1. 2015-09-23 01:00:00
  2. 2024-05-07 01:00:00
  3. 2024-03-13 00:00:00 <-- 我需要这个 01:00:00

这些值在存储到数据库之前被转换为 Date。调试时我注意到以下内容:

TimeZone timeZone = Calendar.getInstance().getTimeZone();
System.out.println(timeZone.getDisplayName(false, TimeZone.SHORT));

System.out.println(new SimpleDateFormat("zzz").format(new Date()));

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
System.out.println(formatter.parseDateTime("2015-09-23").toDate());
System.out.println(formatter.parseDateTime("2024-05-07").toDate());
System.out.println(formatter.parseDateTime("2024-03-13").toDate());

前两个日期使用 BST,最后一个使用 GMT。是否可以让它们都使用相同的时区?

GMT
BST
Wed Sep 23 01:00:00 BST 2015
Tue May 07 01:00:00 BST 2024
Wed Mar 13 00:00:00 GMT 2024

试试这个: SimpleTimeZone UTCTimeZone = new SimpleTimeZone(0, "UTC"); TimeZone.setDefault(UTCTimeZone); 所有日期对象都将使用 UTC 作为您后端代码的默认时区

首先,请记住 java.util.Date 没有时区(有关它的更多详细信息,请阅读 here)。

发生的事情是 Date.toString() 方法使用系统的默认时区来打印其值(检查 JVM 中 TimeZone.getDefault() 的值,它可能是 Europe/London)。

而在Europe/London时区,冬季的偏移量等于UTC(打印为GMT)并且是+01:00 在夏天(打印为 BST,又名 British Summer Time)。这些不同的 3 个字母名称表示偏移量变化,但并不表示日期 "changed" 他们的时区。

还要考虑到 timezone 不仅是偏移量或名称,而且 the set of all offset changes that occur in a region during history (发生变化时,以及每次变化前后的偏移量)。

因此,日期没有不同的时区,因为:

  1. 在同一个时区可以有超过1个偏移量。偏移量的一些变化导致 3 字母名称的变化 - 尽管这些 3 字母名称的使用被广泛使用,但它们是 ambiguous and not standard.
  2. java.util.Date doesn't have a timezone,所以改不了。

如果要将这些对象保存到DB中,需要注意的是时间戳(从1970-01-01T00:00:00Z开始的毫秒数),转换为Date时保留。

如果您检查创建的对象中的时间戳毫秒,您会发现它没有改变:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd").withZone(DateTimeZone.UTC);
DateTime d1 = formatter.parseDateTime("2015-09-23");
DateTime d2 = formatter.parseDateTime("2024-05-07");
DateTime d3 = formatter.parseDateTime("2024-03-13");

// comparing timestamp millis between DateTime and java.util.Date
System.out.println(d1.getMillis() == d1.toDate().getTime());
System.out.println(d2.getMillis() == d2.toDate().getTime());
System.out.println(d3.getMillis() == d3.toDate().getTime());

上面的所有 3 个案例都打印 true,这意味着它们代表同一时刻(因此日期没有改变)。

实际上,您可以看到所有 DateTime 个对象都采用 UTC:

System.out.println(d1);
System.out.println(d2);
System.out.println(d3);

这会打印:

2015-09-23T00:00:00.000Z
2024-05-07T00:00:00.000Z
2024-03-13T00:00:00.000Z

结论:

  • 您可以毫无问题地保存 Date 个对象,因为它们的值是正确的
  • 如果你想向用户显示日期,你可以使用 DateTime 对象(如果你想要不同的格式,则使用 DateTimeFormatter),因为它们不使用toString() 方法中的默认 TimeZone