如何从区域设置获取当前时间和时区?区域设置和时区是正交问题

2022-09-01 18:17:05

我有这个奇怪的问题,当我创建一个带有区域设置的日历时,时区只是恢复到本地的日历

public void start(Locale locale){
    String s = locale.getDisplayName(); 
    System.err.println(s);
    Calendar c = new GregorianCalendar(locale);
    System.err.println(c.getTimeZone());
}

这是输出:

 español (Argentina)
 sun.util.calendar.ZoneInfo[id="Europe/Bucharest", //etc more useless date here....

如何从特定区域设置获得适当的时间?


答案 1

简短的回答:你不能。

很长的答案:没有“区域设置的正确时区”这样的东西。这只是因为有几个国家/地区具有多个时区(例如美国)。时区是一个不同的概念。

无论如何,您正在寻求解决您的问题。我猜你正在编写一个Web应用程序,你看到时区正在恢复到服务器默认值。这是一个典型的情况。两者都将返回与服务器相关的信息。JVM 无法知道“正确”的时区。那么你能做些什么呢?Locale.getDefault()TimeZone.getDefault()

  1. 您可以将时区信息添加到用户配置文件(如果有),或创建时区组合框(以便用户可以在运行时切换)。然后,您可以为实例分配适当的对象,它将自动转换时区。DateFormat
  2. 您可以通过 JavaScript Date Object 的 getTimezoneOffset() 函数从客户端读取当前时区偏移量,并以某种方式 (AJAX) 将其发送到服务器。此方法的问题在于,有多个时区具有该偏移量,并且所选时区可能不适合其他日期。当然,您可以通过围绕时间更改日期轮询数据来猜测时区,但这可能不是您想要做的。
  3. 您可以将无格式时间发送到客户端(例如,编写为 ISO 8601 日期时间格式或与 UTC 相关的纪元的 Unix 时间),并为您提供全球化Dojo 格式的日期和时间。

在这三个可能的选择中,我总是选择1号。通过将时区信息放入用户配置文件,您可以确定他/她的首选时区是什么,无论他们当前的Web浏览器等如何。请记住,某些用户可能希望在访问其他国家/地区时使用您的应用程序...


答案 2

区域设置和时区是正交问题

Locale

区域设置表示以下对:

  • 人类语言,如法语、英语或中文。
  • 一组文化规范,用于确定诸如大写、缩写、元素顺序(如日期中的日-月-年)等格式问题,以及使用逗号与句号作为小数点分隔符等问题。

区域设置不是地理区域设置。虽然可以使用国家或地区作为表示文化规范的一种方式,但这并不意味着用户位于特定的地理区域。例如,来自魁北克的工程师在日本东京举行的会议上将使用一个区域设置,但她的时区可能是在她旅行期间。LocaleLocale.CANADA_FRENCHAsia/Tokyo

ZoneId

时区 ZoneId 表示特定区域的人员使用的 UTC 偏移量的过去、现在和将来更改的历史记录。偏移量只是 UTC 使用的本初子午线之前或之后的小时-分钟-秒数。世界各地的政治家都表现出经常重新定义时区并更改其司法管辖区使用的偏移量的倾向。事实上,那些采用夏令时 (DST) 愚蠢的地区每年更改两次偏移量,大约每六个月。

➥所以,不,你不能从给定的区域设置获取当前时间和时区。


当我使用区域设置创建日历时,时区只是恢复到本地日历

您正在使用可怕的日期时间类,这些类现在是遗留的,被JSR 310定义的现代java.time类所取代。

要获取 UTC 的当前时刻(零小时-分钟-秒的偏移量),请使用 。根据定义,An 始终采用 UTC 格式。InstantInstant

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

如果希望当前时刻位于特定时区,请指定 以获取对象。ZoneIdZonedDateTime

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Capture the current moment as seen in the wall-clock time used by the people of a particular region.

至于知道适用的时区,正如我上面所说,您必须:

您可以通过调用 ZoneId.getAvailableZoneIds 来获取已知时区的列表。

Calendar c = new GregorianCalendar( locale ) ;

您可能会对采用 的构造函数感到困惑,这是可以理解的。GregorianCalendarLocale

此构造函数是在旧版日期时间类中发现的许多不良和不正确的设计决策之一。坦率地说,这些遗留类非常糟糕,由不了解日期时间处理的复杂性和微妙之处的人设计。Sun、Oracle 和 JCP 社区决定java.time 取代它们,这是有充分理由的。

Locale在生成表示日期时间对象值的文本以向用户显示时,与时区相交。A 指定在翻译月份名称、星期几名称等时要使用的人类语言。并指定用于决定诸如缩写月份或星期几之类的问题的文化规范(名称是否大写?是否附加了句号?),排序日,月,年,以及其他此类方面。LocaleLocale


推荐