Java:从 OSGi 应用程序中设置时区

标签 java timezone osgi java-time threetenbp

我在 Linux 上运行的嵌入式 Java 应用程序应该允许用户通过 GUI 更改时区。我的应用程序在 OSGI 容器中运行(请参阅下文为什么我认为这是相关的)并且在使用新时区之前不需要重新启动。

从我的 Java/OSGi 应用程序持久设置时区的推荐方法是什么?

我可以想到以下方法,我列出了一些优点和缺点。我错过了什么吗?推荐什么?:

  1. 在应用程序中,更改底层操作系统时区,另外对当前运行的 JVM 使用 TimeZone.setDefault(...) 并更新所有保存 Clock 的实例旧 TZ(因此需要某种事件)。缺点:这种方法依赖于操作系统并且级别很低,我也想保持操作系统时钟 UTC。优点:操作系统负责存储 TZ,TZ 在下次启动应用程序时立即正确。
  2. 在应用程序中,更改用于启动的 -Duser.timezone=... 参数。缺点:非常丑陋,甚至更低级别,但允许将操作系统时钟保留为 UTC,同时让应用程序以正确的 TZ 启动。还需要在发生变化时更新 Clock 实例。
  3. 不要接触操作系统,只使用 TimeZone.setDefault(...) 并在启动时调用它early。这将需要一个单独的持久性(首选项)来保存它。同样,在当前运行的 JVM 中,所有引用旧 TZ 的 Clock 实例都需要在更改时更新(需要事件)。在 OSGi 容器中运行时,无法保证 bundle 的启动顺序,因此我无法确定默认 TZ 在使用前是否已设置。我怎么能保证这一点?此外,JSR310 明确建议不要在 Clock 中使用“默认 TZ”。
  4. 根本不使用“默认”时区,使用单独的全局变量,并在 InstantLocalXXX 值之间的每次转换时,显式传递时区。这摆脱了需要一个事件来更新 Clock 实例。但我们需要注意不要使用LocalDate.now(clock),因为它使用了时钟的TZ(之后不再正确)。如何在 OSGi 中拥有这个全局变量?使用 ConfigAdmin?如何使我无法控制的代码正常运行(例如,记录时间戳)?

编辑:为了摆脱更新 Clock 的需要,我可以使用一个始终检查默认时区的时钟,但从性能 POV 来看这似乎不是最佳选择:

public class DefaultZoneClock extends Clock {
  private final Clock ref = Clock.systemUTC();

  @Override
  public ZoneId getZone() {
    return ZoneId.systemDefault(); // probed on each request
  }

  @Override
  public Clock withZone(ZoneId zone) {
    return ref.withZone(zone);
  }

  @Override
  public Instant instant() {
    return ref.instant();
  }
}

这是个好主意吗?

编辑 2:

关于我上面的性能问题:它们显然是不合理的。当您调用 LocalDate.now() 时,会在内部构建一个新的 SytemClock,它通过在 map 中搜索来设置当前的 ZoneID - 这是与上面使用我的 DefaultZoneClock 完全相同,区别在于使用我的代码我可以注入(inject)任何其他 Clock 进行测试。 (所有客户端代码都将使用 LocalDate.now(clock) )

下面的答案建议不要更改 JVM TimeZone,而是在必要时根据用户定义的 TimeZone 进行转换,这意味着我必须注意不要使用从中调用 TimeZone 的 java.time 方法时钟,例如。如果我需要 LocaTime 使用

// OK, TimeZone is set explicitely from user data
LocalTime t = clock.instant().atZone(myUserZoneID).toLocalTime();

// Not OK, uses the Clock's internal TimeZone which may not have been set or updated
LocalTime t2 = LocalTime.now(clock);

最佳答案

根据我的经验,日期/时间应该始终在内部使用 UTC 表示。仅在向用户显示时转换为本地时间。此时,您还需要根据用户的语言环境对其进行格式化。

那么问题就变成了,您如何知道用户的时区和语言环境?这取决于应用程序的性质。如果它是单用户桌面应用程序,那么您应该在操作系统中查找这些应用程序或使用与 Config Admin 服务一起存储的配置。如果它是一个多用户网络应用程序,那么您可能会在网络 session 中获得一些与用户相关的信息;或使用 Accept-Language 标题甚至地理位置。

更新

Poster 澄清了该应用程序是嵌入式设备上的单用户应用程序。在这种情况下,每次需要显示时间时,只查询当前系统时区不是更容易吗?这避免了讨厌的全局变量,并且还允许您的应用程序动态响应时区的变化,例如,如果用户将设备从一个地方带到另一个地方。

我认为您不应该从您的 Java 应用程序调用 TimeZone.setDefault,因为您要从哪里获得这些信息?也许直接用户输入,但用户不会更喜欢在操作系统中设置它,以便所有应用程序都能获得它吗?

关于Java:从 OSGi 应用程序中设置时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27904219/

相关文章:

java - 图形用户界面 : how to properly set layout

java - 如何动态加载目录中的所有jar?

java - OSGi解决可插拔架构

mysql 没有在 Windows 服务器中使用正确的时区

c++ - Windows 程序如何临时更改其时区?

java - OSGi 中的反序列化问题

java - 为什么更新mysql用户权限后必须重启服务?

java - 如何...使用 MigLayout

java - 如何使用 Android Webview 检查链接是否离线或损坏?

java - 如何将 UTC 时间转换为其他时区 ("CST","IST")