我在Linux上运行的嵌入式Java应用程序应该允许用户通过GUI更改时区。我的应用程序在OSGI容器中运行(请参阅下面我相信这是相关的原因),并且在使用新时区之前不需要重新启动。
持久从我的Java / OSGi应用程序设置时区的推荐方法是什么?
我可以想到以下方法,我列出了一些优点和缺点。我错过了什么吗?推荐什么?:
TimeZone.setDefault(...)
并续订包含旧TZ的所有Clock
实例(因此需要某种事件)。 Con:这种方法取决于操作系统,而且级别很低,我也希望保持OS时钟UTC。优点:操作系统负责存储TZ,下次启动应用程序时TZ会立即正确。-Duser.timezone=...
参数。 Con:非常难看,甚至更低级别,但允许以UTC为单位留下OS时钟,同时让应用程序以正确的TZ开始。还需要在更改时续订Clock
个实例。TimeZone.setDefault(...)
并在启动时将其称为早期。这将需要一个单独的持久性(首选项)来保存它。此外,在当前运行的JVM中,所有引用旧TZ的Clock
实例都需要在更改时更新(需要事件)。在OSGi容器中运行时,无法保证bundle的启动顺序,因此我无法确定默认TZ在使用之前是否已设置。我怎么能保证这个?此外,JSR310明确建议不要使用"默认TZ"在时钟。Instant
和LocalXXX
值之间的每次转换时,显式传递时区。这摆脱了需要更新Clock
实例的事件。但我们需要注意不要使用LocalDate.now(clock)
,因为这会使用时钟的TZ(然后不再正确)。如何在OSGi中拥有这个全局变量?使用ConfigAdmin
?如何使代码行为正确无法控制(例如,记录时间戳)? 编辑:为了摆脱更新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);
答案 0 :(得分:3)
根据我的经验,日期/时间应始终使用UTC在内部表示。只有在向用户显示时才转换为本地时间。此时,您还需要根据用户的区域设置对其进行格式化。
问题就变成了,你怎么知道用户的时区和地区?这取决于应用程序的性质。如果它是单用户桌面应用程序,那么您应该在操作系统中查看这些应用程序,或者使用随Config Admin服务存储的配置。如果它是一个多用户Web应用程序,那么您可能会在Web会话中获得一些与用户相关的信息;或使用Accept-Language标题甚至地理位置。
<强>更新强>
海报澄清该应用程序是嵌入式设备上的单用户。在这种情况下,每次需要显示时间时,查询当前系统时区是否更容易?这可以避免令人讨厌的全局变量,它还允许您的应用程序动态响应时区中的更改,例如,如果用户将设备从一个地方运送到另一个地方。
我不相信您应该从Java应用程序中调用TimeZone.setDefault
,因为您要从哪里获取此信息?也许直接用户输入,但是用户不希望在操作系统中设置它,以便所有应用程序都能获得它?