joda time to Date 不一致的时区
joda time to Date inconsistent time zones
我有大量日期要存储在使用 BST 的服务器上的数据库 运行 中:
2015-09-23
2024-05-07
2024-03-13
但是它们在数据库中存储为:
2015-09-23 01:00:00
2024-05-07 01:00:00
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个偏移量。偏移量的一些变化导致 3 字母名称的变化 - 尽管这些 3 字母名称的使用被广泛使用,但它们是 ambiguous and not standard.
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
。
我有大量日期要存储在使用 BST 的服务器上的数据库 运行 中:
2015-09-23
2024-05-07
2024-03-13
但是它们在数据库中存储为:
2015-09-23 01:00:00
2024-05-07 01:00:00
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个偏移量。偏移量的一些变化导致 3 字母名称的变化 - 尽管这些 3 字母名称的使用被广泛使用,但它们是 ambiguous and not standard.
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
。