joda 时区 ID 是否与 java 时区 ID 相同?

Are joda timezone ids the same as java time zone ids?

我在 Android 上使用 ACTION_TIMEZONE_CHANGED 意图过滤器来响应时区更改。

我注意到此时 Jodas 当前时区未更新,使用: DateTimeZone.getDefault()

当我使用 Java 的默认值 TimeZone.getDefault() 时,时区是正确的。

注意:当我再次更改它时:Joda 具有我之前更改的值。所以它落后了(当 Android 触发广播意图时尚未更新)。

所以我只能使用当前时区的 Java 时区。但是我的域对象使用 Joda DateTimeZone`s。现在我想将当前时区与我的域对象中的时区进行比较。这样做省钱吗:

TimeZone currenTimeZone = TimeZone.getDefault();
if(action.getLocation().getDateTimeZone().getID().equals(currenTimeZone.getID()))) {
 [...]
}

? 或者两个库之间的时区 ID 可以不同吗?

tl;博士

不,假设时区不安全

  • 存在。
  • 定义了一个特定的标识符。
  • 具有相同的definition/rules。

tzdata

大多数操作系统和软件库都依赖 tz database maintained by IANA 来提供当前和过去的时区信息。也称为 tzdataTZDB。以前称为 Olson 数据库

经常更改

在世界范围内,政治家喜欢经常改变、重新定义、重新安排时间、重新命名,以及以其他方式搞乱时区定义和规则。他们通常在没有预先警告的情况下这样做,例如 Turkey(2016 年秋季)现在不到两个月。

有时会定义新的时区。因此,在这方面,具体回答您的问题:是的,某些 tzdata 副本可能具有旧副本中不存在的较新时区定义,因此时区标识符可能有所不同。

此外,有时会为现有时区赋予新名称。例如,随着印度最近恢复其城市名称,Asia/Calcutta 现在也被标记为 Asia/Kolkota。同样,旧的 tzdata 副本不会知道这个新名称。

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们 不是 真正的时区,不是标准化的,甚至不是唯一的(!)。

某些软件会扩展 tzdata 以尝试识别这些伪时区。这不是个好主意。但是,这再次意味着使用这些非标准时区标识符可能在一个地方有效,但在另一个地方无效。坚持使用官方时区名称。

有些区域有 display name,例如 British Time。但是你应该永远不要使用它作为标识符。

正在更新

系统管理员必须努力在所有可能使用它的地方更新 tzdata:

  • 操作系统
  • Java 虚拟机
  • 软件库(例如 Joda-Time,可能 ThreeTen-Backport)。

JVM 的提供者通常在 JVM 的更新中包含最新版本的 tzdata。但是政客们更频繁地摆弄时区而不是 Java 更新。因此您可能需要手动更新 JVM。 Oracle 为 Oracle 和 OpenJDK JVM 提供 Timezone Update Tool

Joda-Time 包含它自己的 tzdata 副本。因此,您需要更新 Joda-Time 库或手动替换 tzdata。请注意,Joda-Time 项目现在处于维护模式,并建议移动到与 Java 8 及更高版本捆绑在一起的 java.time 类。

列出已知标识符

java.time 类 可以显示他们的列表 known zone identifiers.

Set<String> zoneIds = ZoneId.getAvailableZoneIds() ;

其他图书馆和操作系统或许也能做到这一点。

避免遗留日期时间类

与 Java 的最早版本捆绑在一起的麻烦的旧日期时间 类 现在是遗留的,由 java.time 类.

取代

所以你使用 TimeZone.getDefault() is now outmoded by ZoneId.systemDefault:

ZoneId z = ZoneId.systemDefault() ;
String zoneIdentifier = z.toString() ;

使用它来获取特定区域的当前时刻。

ZonedDateTime zdt = ZonedDateTime.now( z );