22

我有这个奇怪的问题,当我创建一个带有语言环境的日历时,时区只是恢复到本地的

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....

我怎样才能从特定的语言环境中获得正确的时间?

4

2 回答 2

50

简短的回答:你不能。

长答案:没有“区域设置的适当时区”之类的东西。那只是因为有几个国家有多个时区(例如美国)。时区是一个不同的概念。

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

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

在这三个可能的选择中,我总是选择第一。通过将时区信息放入用户个人资料中,您可以确定他/她的首选时区是什么,而不管他们当前的网络浏览器等。请记住一些用户可能希望在访问其他国家/地区时使用您的应用程序...

于 2012-05-13T10:53:06.167 回答
9

语言环境和时区是正交问题

Locale

ALocale代表一对:

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

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

ZoneId

时区ZoneId表示过去、现在和未来对特定地区人民使用的UTC 偏移量变化的历史。偏移量只是 UTC 使用的本初子午线之前或之后的几个小时-分钟-秒。世界各地的政治家都表现出经常重新定义他们的时区和改变他们的管辖区使用的偏移量的倾向。事实上,那些采用愚蠢的夏令时 (DST) 的地区每年都会改变他们的偏移量两次,大约每六个月一次。

➥ 所以,不,你不能从给定的语言环境中获得当前时间或时区。


当我创建带有语言环境的日历时,时区只是恢复为本地日历

您正在使用现在遗留的糟糕的日期时间类,被JSR 310 定义的现代java.time类所取代。

要获取 UTC 中的当前时刻(零时分秒的偏移量),请使用Instant. 根据定义, AnInstant始终采用 UTC。

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

如果您想要特定时区的当前时刻,请指定ZoneId以获取ZonedDateTime对象。

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 ) ;

GregorianCalendar你可能会被这个使用a 的构造函数弄糊涂,这是可以Locale理解的。

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

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

于 2019-12-27T06:49:22.203 回答