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

时间:2015-01-12 14:26:16

标签: java timezone osgi java-time threetenbp

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

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

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

  1. 从应用程序中,更改底层操作系统时区,另外对当前运行的JVM使用TimeZone.setDefault(...)并续订包含旧TZ的所有Clock实例(因此需要某种事件)。 Con:这种方法取决于操作系统,而且级别很低,我也希望保持OS时钟UTC。优点:操作系统负责存储TZ,下次启动应用程序时TZ会立即正确。
  2. 从应用中,更改用于启动的-Duser.timezone=...参数。 Con:非常难看,甚至更低级别,但允许以UTC为单位留下OS时钟,同时让应用程序以正确的TZ开始。还需要在更改时续订Clock个实例。
  3. 请勿触摸操作系统,只能使用TimeZone.setDefault(...)并在启动时将其称为早期。这将需要一个单独的持久性(首选项)来保存它。此外,在当前运行的JVM中,所有引用旧TZ的Clock实例都需要在更改时更新(需要事件)。在OSGi容器中运行时,无法保证bundle的启动顺序,因此我无法确定默认TZ在使用之前是否已设置。我怎么能保证这个?此外,JSR310明确建议不要使用"默认TZ"在时钟。
  4. 不使用"默认" TimeZone根本使用单独的全局变量,并且在InstantLocalXXX值之间的每次转换时,显式传递时区。这摆脱了需要更新Clock实例的事件。但我们需要注意不要使用LocalDate.now(clock),因为这会使用时钟的TZ(然后不再正确)。如何在OSGi中拥有这个全局变量?使用ConfigAdmin?如何使代码行为正确无法控制(例如,记录时间戳)?
  5. 编辑:为了摆脱更新Clock的需要,我可以使用一个始终检查默认TimeZone的时钟,但这从性能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,通过在地图中搜索来设置当前ZoneID - 这与上面使用我的DefaultZoneClock完全相同,不同的是,使用我的代码我可以注入任何其他Clock进行测试。 (所有客户端代码都将使用LocalDate.now(clock)

    下面的答案建议不要更改JVM TimeZone,而是根据用户定义的TimeZone进行转换,这意味着我必须注意不要使用调用TimeZone的java.time方法Clock,例如。如果我需要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);
    

1 个答案:

答案 0 :(得分:3)

根据我的经验,日期/时间应始终使用UTC在内部表示。只有在向用户显示时才转换为本地时间。此时,您还需要根据用户的区域设置对其进行格式化。

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

<强>更新

海报澄清该应用程序是嵌入式设备上的单用户。在这种情况下,每次需要显示时间时,查询当前系统时区是否更容易?这可以避免令人讨厌的全局变量,它还允许您的应用程序动态响应时区中的更改,例如,如果用户将设备从一个地方运送到另一个地方。

我不相信您应该从Java应用程序中调用TimeZone.setDefault,因为您要从哪里获取此信息?也许直接用户输入,但是用户不希望在操作系统中设置它,以便所有应用程序都能获得它?