当前位置: 首页 > 面试题库 >

在Java中解析日期时间字符串是否需要Locale?

谷梁镜
2023-03-14
问题内容
  • 在什么条件下我需要用LocaleJava解析日期时间字符串?
  • 语言环境与时区有什么关系?

有时我会在“问题与解答”中看到需要解析语言的地方。但是在其他语言中,没有提及语言环境。


问题答案:

就日期时间处理而言,语言环境和时区是相互独立的正交问题。

  • 区域设置

    • 语言
      人类语言,例如阿拉伯语,法语,波斯语。星期几名称,月份名称和序号指示符的文本。例如……是Monday还是Lundi

    • 文化
      通常使用成语来安排组成日期时间值的字符串表示形式的文本和数字。例如......在短短的形式,是month-date-yeardate-month- yearyear-month-date?从长远来看,星期几是第一位吗?月份名称是否具有首字母大写还是全部小写?缩写是否带有“ FULL
      STOP”(句号)
      字符?

  • 时区

    • 偏移 时间UTC(GMT)是一个地区的人们在墙上使用的时间
      之间的时差(以分钟为单位),这是世界调节时钟和时间的主要时间标准。

    • 异常
      偏移量的更改历史,当前应用的定义偏移量的规则(包括夏令时(DST)等调整)以及已确认的变更计划即将在不久的将来出现。

因此,您可以混合匹配区域设置和时区。以下是一些示例。

  • 一位在印度浦那参加会议的法国人需要查看印度会议时间的安排,但宁愿将“ Monday”读成他的母语“ Lundi”。
    • 法国语言环境
    • 印度时区
  • 一位在西雅图工作的巴西工程师希望收看来自Turku Finland的现场网络研讨会。她需要知道何时将网络浏览器指向网络研讨会。在调整为西雅图时区后,她需要知道芬兰的开始时间,但必须使用她的母语葡萄牙语来显示巴西语言环境。
    • __用于演示的 Locale(“ pt”,“ BR”) (用于生成文本表示)
    • 芬兰的预定开始时间必须从调整Europe/HelsinkiAmerica/Los_Angeles(西雅图时区)。
  • 冰岛的一家报纸可能会将在俄罗斯发生的一件事件报道为两个日期时间,莫斯科时区,为清楚起见添加了UTC时区。但是本文将使用冰岛语作为文本,包括星期几。
    • 莫斯科时区和冰岛语言环境
    • UTC时区和冰岛语言环境

解析/生成日期时间值的文本表示的字符串时,仅在两种情况下使用语言环境:

  • 星期几的名称和/或月份的名称(或序号,但最好避免使用)
  • 软编码的本地化格式

在第一种情况下,如果您的字符串包含“星期一” /“隆迪”或“三月” /“火星”之类的单词,则将使用语言环境来翻译这些字符串。

在第二种情况下,如果您没有显式的格式化模式,则使用语言环境来了解星期几,日期,月名,年等各部分的预期顺序。 。例如,说英语的美国人说“
10月11日”,而说法语的加拿大人则使用相反的顺序“
10月11日”。所谓的软编码,是指DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )相对于硬编码的格式,例如DateTimeFormatter.ofPattern("yyyy MM dd, EEE")

那么什么时候不需要区域设置?如果您输入的字符串全为数字,例如“ 2015-01-23”,并且您正在将该格式硬编码为“ yyyy-MM-dd”…

String input = "2015-01-23";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "yyyy-MM-dd")

…那么语言环境实际上是无关紧要的。您没有要翻译的单词,也没有“星期一”或“隆迪”。并且不要求使用本地化的格式化程序,该格式化程序需要一个语言环境才能知道日期是在月份之前还是之后,以及其他此类详细信息。

请注意,在这种情况下,您仍然可以指定语言环境。实际上,我建议您 养成始终指定语言环境 (以及时区)的 习惯

隐式语言环境和时区

那么,为什么您在StackOverflow上看到如此多与日期时间相关的问答,而没有任何语言环境?因为如果省略,则JVM的当前默认语言环境将自动且无提示地应用。

因此,如果您在设置为美国语言环境的JVM上运行带有英文文本的字符串,则没有问题。但是不建议这种对隐式语言环境的依赖。如果 在运行时
调用任何应用程序的任何线程中的任何代码Locale.setDefault,并且会影响该JVM中的所有其他代码。然后,您的代码将引发异常。最好养成明确指定期望/期望区域设置的习惯。

时区的建议相同。如果省略,则将自动且无提示地应用JMV的当前默认时区。同样, 在运行时
任何应用程序的任何线程中的任何代码都可以调用TimeZone.setDefault,并影响该JVM中的所有其他代码。然后,您的代码将引发Exception或行为异常。

运行时的意外更改应该足以养成始终指定区域设置和时区的习惯。但是另一个好处是,它还可以使您的代码自我记录。同样,在编程时自觉指定语言环境和时区可能会提醒您有关错误或未经证实的假设。

示例场景

想象一个魁北克的商人。她与土耳其的一位客户确认了他的交货时间,该交货时间为中午。因此,她使用壁挂时间在土耳其创建了一个可以接受交货的对象。

ZoneId zoneIdIstanbul = ZoneId.of( "Europe/Istanbul" );
ZonedDateTime zdtIstanbul = ZonedDateTime.of( 2015, 10, 11, 12, 30, 00, 0, zoneIdIstanbul );  // Half-past noon in Turkey.

为了方便客户,她使用土耳其语和习俗来设置文本格式。她定义了一个格式化程序对象,以处理日期时间值的文本表示形式的生成。我们还可以在生成文本表示时为要应用的格式程序分配一个时区。但是ZonedDateTime对象已经分配了一个时区,因此格式化程序将在该时区启动。

Locale locale_tr_TR = new Locale( "tr", "TR" );
DateTimeFormatter formatter_tr_TR = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale_tr_TR );
String outputTurkish = formatter_tr_TR.format( zdtIstanbul );

我们的业务人员知道客户使用芬兰的物流协调员,因此她使用芬兰语打印相同的日期时间值。因此,我们在土耳其时区设置了芬兰语区域。

Locale locale_fi_FI = new Locale( "fi", "FI" );
DateTimeFormatter formatter_fi_FI = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale_fi_FI );
String outputFinnish = formatter_fi_FI.format( zdtIstanbul );

就她自己而言,她需要在自己的固定时间内提供预期交货的字符串,以便可以设置警报以提醒她检查是否成功完成。她母语是法语,而不是土耳其语。

因此,下一个代码是不同的,因为我们需要调整时区
语言环境。在时间轴上的同一时刻,即预期交付的日期时间,但在文本中的表示方式有所不同。请注意,这次是如何withZone在链的末尾添加一个额外的调用,以创建一个格式化程序,在此我们指定时区调整以覆盖ZonedDateTime对象的已分配区域。

Locale locale_fr_CA = Locale.CANADA_FRENCH;
ZoneId zoneId_Montréal = ZoneId.of( "America/Montreal" );
DateTimeFormatter formatter_fr_CA_Adjusted = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale_fr_CA ).withZone( zoneId_Montréal );
String outputQuébec = formatter_fr_CA_Adjusted.format( zdtIstanbul );

最后,为了我们的讲英语的StackOverflow.com读者,我们来做一个英文版本。但是请注意,我们回收了魁北克格式器,保留了已设置的时区,但将语言环境替换为美国的语言环境。(从技术上讲,不是回收,而是说。不可变对象的使用意味着将基于旧对象的值实例化一个新对象。)

Locale locale_en_US = Locale.US;
DateTimeFormatter formatter_US_Unadjusted = formatter_fr_CA_Adjusted.withLocale( locale_en_US );
String output_US_Unadjusted = formatter_US_Unadjusted.format( zdtIstanbul );

让我们看看这些值的输出。转储到控制台。

首先,我们toStringZonedDateTime对象上隐式调用该方法。默认情况下,此方法使用ISO
8601定义的标准格式之一。但是java.time通过在方括号中添加时区名称来扩展该格式[Europe/Istanbul]。交换数据时,请使用这些明确的标准格式,而不要使用任何更人性化的格式。

System.out.println( "zdtIstanbul : " + zdtIstanbul );
System.out.println( "outputTurkish : " + outputTurkish );
System.out.println( "outputFinnish : " + outputFinnish );
System.out.println( "outputQuébec : " + outputQuébec );
System.out.println( "output_US_Unadjusted : " + output_US_Unadjusted );

输出信息告诉我们,土耳其的午餐时间对我们魁北克的女性来说意味着5:30 AM的警报。

zdtIstanbul : 2015-10-11T12:30+03:00[Europe/Istanbul]
outputTurkish : 11 Ekim 2015 Pazar 12:30:00 EEST
outputFinnish : sunnuntai, 11. lokakuuta 2015 12.30.00 EEST
outputQuébec : dimanche 11 octobre 2015 5 h 30 EDT
output_US_Unadjusted : Sunday, October 11, 2015 5:30:00 AM EDT


 类似资料:
  • 本实例演示了如何通过DateFormat类的parse方法根据不同的本地环境解析日期/时间字符串,并将其转换成Date对象。在最后还演示了parse方法如何解析不符合日期/时间逻辑的字符串。 例子 : 解析日期/时间字符串 实例的代码如下: package chapter8; import java.text.DateFormat; import java.util.Date; import ja

  • 问题内容: 我的日期格式为“ yyyy-MM-dd’T’HH:mm:ss.sssZ”。例如,日期为“ 2018-07-17T09:59:51.312Z”。我正在使用下面的代码来解析Java中的String。 这给了我“无法解析的日期:”例外。谁能告诉我该怎么做? 问题答案: 您忘了在 那会做的工作

  • 这就是问题所在: 我有一些带有旅行信息的. csv文件,日期显示为字符串(每一行代表一次旅行): “1-5月和10-12月的所有星期一。6-9月的所有日子” 我必须将字符串解析为日期,并为每次旅行将其保存到一个数组中。 问题是我不知道怎么做。甚至我的大学老师也告诉我,他们不知道如何做到这一点:S。我无法使用http://docs.oracle.com/javase/6/docs/api/java/

  • 我正在尝试在中解析这些日期,然后获取表示形式。 我阅读了这个类似的答案,并创建了一个方法来解析上述日期并返回具有所需格式的: 然而,没有一个图案是匹配的。我这里缺少什么? 更新:在这两个日期中,我都收到了字符的异常。

  • 我尝试在Go中解析日期字符串< code >“2014-09-12t 11:45:26.371 z”。该时间格式定义为: RFC-3339日期时间 ISO-8601日期时间 密码 我得到了这个错误: 解析时间“2014-11-12T11:47:39.489Z”:月超出范围 如何解析这个日期字符串?

  • 问题内容: 我有一个来自json响应的字符串: 如何将此字符串转换为Java DateTime对象? 我尝试使用以下内容: 但与此我只能创建一个日期对象。但是绑定在字符串中的时间还是很重要的。 任何帮助是极大的赞赏! 问题答案: 您可以从Java Date对象创建Joda DateTime对象,因为Java没有类。 尽管Java类也保存时间信息(这是您首先需要的信息),但我还是建议您使用a 代替J