我有一个奇怪的问题,当我创建一个带有区域设置的日历时,时区只是恢复到本地时区
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....
如何从特定区域设置获取适当的时间?
简短的回答:你不能。
长答案:没有"区域设置的正确时区"这样的东西。这只是因为有几个国家/地区拥有多个时区(例如美国(。时区是一个不同的概念。
无论如何,您正在寻找解决您的问题。我猜您正在编写一个 Web 应用程序,并且您看到时区正在恢复为服务器默认值。这是一个典型的情况。Locale.getDefault()
和TimeZone.getDefault()
都将返回与服务器相关的信息。JVM无法知道"正确"的时区。那么你能做些什么呢?
- 可以将时区信息添加到用户配置文件(如果有(,或创建时区组合框(以便用户可以在运行时切换(。然后,您可以将适当的对象分配给
DateFormat
实例,它将自动转换时区。 - 您可以通过JavaScript Date Object的getTimezoneOffset((函数从客户端读取当前时区偏移量,并以某种方式(AJAX(将其发送到服务器。此方法的问题在于有多个时区具有该偏移量,并且所选时区可能不适合其他日期。当然,您可以通过在时间更改日期周围轮询数据来猜测时区,但这可能不是您想要做的。
- 您可以将未格式化的时间发送到客户端(例如,以 ISO 8601 日期时间格式或与 UTC 相关的纪元的 Unix 时间编写(,并为您设置全球化或 Dojo 格式的日期和时间。
在这三种可能的选择中,我总是选择第一。通过将时区信息放入用户个人资料中,您可以确定他/她的首选时区是什么,无论他们当前的网络浏览器等如何。请记住,某些用户可能希望在访问其他国家/地区时使用您的应用程序...
区域设置和时区是正交问题
Locale
Locale
表示以下一对:
- 一种人类语言,例如法语、英语或中文。
- 一组文化规范,用于决定诸如大写、缩写、元素顺序(如日期中的日-月-年(的格式问题,以及使用逗号与句号作为小数分隔符等问题。
Locale
不是地理上的。虽然Locale
可以使用国家或地区作为代表文化规范的一种方式,但这并不代表用户位于特定的地理区域。例如,来自魁北克的工程师在日本东京的一次会议上将使用Locale.CANADA_FRENCH
的区域设置,但她的时区可能在旅行期间Asia/Tokyo
。
ZoneId
时区ZoneId
表示特定区域用户使用的 UTC 偏移量的过去、现在和未来更改的历史记录。偏移量只是 UTC 使用的本初子午线前面或后面的小时-分钟-秒数。世界各地的政治家都表现出经常重新定义时区并更改其司法管辖区使用的偏移量的倾向。事实上,那些采用夏令时(DST(愚蠢的地区每年更改两次偏移量,大约每六个月一次。
➥ 因此,不,您无法仅从给定的区域设置获取当前时间和时区。
当我使用区域设置创建日历时,时区只会恢复为本地日历
您正在使用糟糕的日期时间类,这些类现在是遗留的,被JSR 310定义的现代java.time类所取代。
要获取 UTC 格式的当前时刻(零小时-分钟-秒的偏移量(,请使用 Instant
。根据定义,Instant
始终采用 UTC
Instant instant = Instant.now() ; // Capture the current moment in UTC.
如果希望当前时刻处于特定时区,请指定获取ZonedDateTime
对象的ZoneId
。
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.systemDefault
(,或... - 与用户确认。
您可以通过调用 ZoneId.getAvailableZoneIds
来获取已知时区的列表。
Calendar c = new GregorianCalendar( locale ) ;
您可能会对这个GregorianCalendar
采用Locale
的构造函数感到困惑,这是可以理解的。
此构造函数是在旧日期时间类中发现的许多糟糕和不正确的设计决策之一。坦率地说,这些遗留类非常糟糕,由不了解日期时间处理的复杂性和微妙性的人设计。Sun、Oracle 和 JCP 社区决定用 java.time 取代它们,这是有充分理由的。
在生成表示要向用户显示的日期时间对象值的文本时,Locale
与时区相交。Locale
指定用于翻译月份名称、星期几名称等的人类语言。Locale
指定了决定问题的文化规范,例如缩写月份或星期几(名称是否大写?是否附加了句号?(,订购日,月和年,以及其他此类方面。