我有一个函数,可以将字符串转换为 joda 时间对象并格式化它。
public static String getFormattedDatetime(String someDate) {
DateTime newDate = DateTime.parse(someDate, DateTimeFormat.forPattern("yy-MM-dd HH:mm:ss.SSS")).minusHours(7);
String formattedDate = newDate.toString("dd-MMM-yy hh:mm a");
return formattedDate;
}
该函数接受字符串并返回格式化的日期时间,但我在为其分配时区时遇到了麻烦。我传入的字符串表示数据库中的 UTC 时间,我需要将其转换为 PST/PDT。我想不出一种方法来 1) 为新的 DateTime 对象分配时区,2) 将该对象的时区转换为 PST/PDT。现在我正在用 .minusHours 处理这个问题。当然不理想。
在任何情况下都不应该使用
.minusHours(7)
,因为它半年都会出错,并且DateTime
对象仍然会认为它是UTC。
使用
.withZone(DateTimeZone.forID("America/Los_Angeles"));
这里是 Joda Time 支持的所有时区及其对应 ID 的列表
我建议将
forID()
调用生成的常量重构为代码中适当位置的 static final
字段,并在需要进行转换的任何地方使用它。
您可能已经知道,但为了安全起见,
DateTime
对象是IMMUTABLE,这意味着withZone
调用将返回一个全新的DateTime
实例,并且不会更改原始的区域对象。
PST,但 PST 仅在半年中使用(因为夏令时)。我假设您指的是洛杉矶、西雅图等地的当前时间,而不是特指 PST 区域,因为这些城市在一年的另一半使用 PDT。但是,如果您确实 100% 想要 PST,则可以使用 forID("PST");
DateTime dateTime = DateTime.parse(date.toString(), DateTimeFormat.forPattern("yyyy-MM-dd")).withZoneRetainFields(DateTimeZone.forID("PST")); // it will change timezone to PST but not the actual date field value.
public static String getFormattedDatetime(String someDate) {
DateTime newDate = DateTime.parse(someDate, DateTimeFormat.forPattern("yy-MM-dd HH:mm:ss.SSS"));
LocalDateTime zonedDate = LocalDateTime.parse(newDate, DateTimeFormat.forPattern("yy-MM-dd HH:mm:ss.SSS"));
DateTime finalZonedDate = zonedDate.toDateTime(DateTimeZone.UTC);
String formattedDate = newDate.toString("dd-MMM-yy hh:mm a");
return formattedDate;
}
当我将字符串转换为变量时,我必须使用 joda 的
LocalDateTime
类来分配时区。然后我必须单独转换区域。
偏移。
offset 用于指定与 UTC 的固定偏移量。
另一方面,区域 ID,例如America/Los_Angeles 标识时区。因此,通过使用区域 ID,您可以确保生成的日期时间对象将自动考虑到DST。
接受的答案正确地提到:
在任何情况下都不应使用避免使用时区缩写
.minusHours(7)
文档的摘录:
三字母时区 ID为了与 JDK 1.1.x 兼容,其他一些三字母时区 ID(例如“PST”、“CTT”、“AST”)是 也支持。然而,
它们的使用已被弃用,因为同样的 缩写通常用于多个时区(例如,“CST” 可以是美国“中部标准时间”和“中国标准时间”),以及 那么 Java 平台只能识别其中之一。
java.time
Joda-Time 主页上的以下通知:
使用请注意,从 Java SE 8 开始,用户被要求迁移到
java.time
(JSR-310) - JDK 的核心部分,它取代了这个 项目。
java.time
API 的解决方案
yy-MM-dd HH:mm:ss.SSS
的日期时间字符串,请注意它没有时区信息;因此,将其解析为
LocalDateTime
对象,然后使用 LocalDateTime#atZone
. 添加时区信息。
或者,您可以使用 (不是我最喜欢的)将日期时间字符串直接解析为 ZonedDateTime
。
演示:
public class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
DateTimeFormatter parser = DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss.SSS");
LocalDateTime ldt = LocalDateTime.parse("14-05-29 17:42:20.123", parser);
ZonedDateTime zdt = ldt.atZone(zoneId);
System.out.println(zdt);
// Alternatively (not my favourite),
DateTimeFormatter parserWithTz = DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss.SSS")
.withZone(zoneId);
ZonedDateTime zdt2 = ZonedDateTime.parse("14-05-29 17:42:20.123", parserWithTz);
System.out.println(zdt2);
// A sample date-time DST is off
System.out.println(LocalDateTime.parse("14-12-29 17:42:20.123", parser).atZone(zoneId));
// If you need the date-time with just the time zone offset
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(odt);
}
}
输出:
2014-05-29T17:42:20.123-07:00[America/Los_Angeles]
2014-05-29T17:42:20.123-07:00[America/Los_Angeles]
2014-12-29T17:42:20.123-08:00[America/Los_Angeles]
2014-05-29T17:42:20.123-07:00
正如您在输出中看到的,ZonedDateTime
对象自动在区域偏移量 -07:00 和 -08:00 之间切换。从