如何在Java中从Locale的时区获取日期格式

7
我有用户的时区和Locale,现在我想获取日期格式。
例如:用户的时区为PST,Locale为美国,则期望的格式为“MM/dd/yyyy”,如果用户的时区为IST,Locale为印度,则期望的格式为“dd/MM/yyyy”。
如何获得这个日期格式?
注:我想获取格式而不是实际日期,以便在其他地方使用。

1
为什么不在“另一个地方”使用区域设置,而不仅仅是模式? - Petar Ivanov
嗨,Petal Ivanov,实际上,我想将模式传递给Javascript,所以我不能使用Locale。 - Kumar D
6个回答

3

Locale翻译为日期/时间格式的逻辑封装在java.text.SimpleDateFormat#SimpleDateFormat构造函数中,准确地说在sun.util.resources.LocaleData#getDateFormatData方法中。该方法提供了ResourceBundle,然后根据所选择的样式查询特定模式。

换句话说 - 不幸的是JDK似乎没有提供API/SPI来访问原始格式。我的建议是始终使用Locale并将其传递给格式化/解析方法。


将区域设置传递给您自己的格式化方法,这是最灵活的解决方案。 - Dapeng

1

你真的需要时区来设置日期格式吗?通常的做法是在本地化属性文件中为某个语言环境(或语言环境_国家)设置日期格式。我认为这已经足够了。


我不需要日期模式的时区信息。但通常情况下,这是我手头拥有的(用户时区详细信息)。通常的做法是在本地化属性文件中为某个语言环境(或语言环境_国家)设置数据模式。这是否意味着最好的方法是在国家级别上维护日期模式(并将其保存在数据库或文件系统中)? - Kumar D
是的,它就是这样。时区无法从HTTP请求中检索,因此您只能知道客户端的语言环境/国家。另一种方法是询问用户TZ并将其与其他用户信息一起保存在数据库中。 - yoprogramo

1

java.time

现代解决方案使用 java.time 类,取代了多年来令人不堪的遗留类,例如 SimpleDateFormat。具体被 DateTimeFormatter 替换。

跳过格式模式,让java.time自动本地化

您问道:

我有用户的时区和语言环境,现在我想获取日期格式。

实际上没有必要获得特定语言环境下使用的格式模式。

DateTimeFormatter 上的 .ofLocalized… 方法返回一个格式化对象,可以自动本地化表示日期时间对象值的文本。因此,您不需要查看模式,只需请求生成的文本结果即可。

FormatStyle对象控制文本的长度或缩写形式。Locale确定在本地化时使用的人类语言和文化规范。

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; 

Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = 
        DateTimeFormatter
        .ofLocalizedDateTime( FormatStyle.FULL )
        .withLocale( locale ) 
;
String output = zdt.format( f ) ;

将内容输出到控制台。

System.out.println( zdt.toInstant().toString() ) ;  // Adjust to UTC.
System.out.println( zdt.toString() ) ;              // Generate text in standard ISO 8601 format extended wisely to append the name of the time zone in square brackets.
System.out.println( output ) ;                      // Automatically formatted content.

请看此处

在IdeOne.com上实时运行代码

2020-07-13T23:26:40.554180Z

2020-07-14T08:26:40.554180+09:00[Asia/Tokyo]

2020年7月14日日本标准时间上午8点26分40秒


关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧传统日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多,请参阅Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

你可以直接使用与JDBC 4.2或更高版本兼容的JDBC驱动程序,直接与数据库交换java.time对象。不需要字符串,也不需要java.sql.*类。Hibernate 5和JPA 2.2支持java.time
在哪里获取java.time类?

0
如果您正在使用Joda Time(如果有选择,为什么不使用?它几乎被捆绑到JDK 1.7中),您可以像这样做:
String patternForStyleAndLocale = org.joda.time.format.DateTimeFormat.patternForStyle("S-", locale);

不幸的是,这只提供了两位数的年份。一个解决方法是:

if (!org.apache.commons.lang.StringUtils.contains(patternForStyleAndLocale, "yyyy"))
{
    // The default Joda pattern only has a two digit year for US and Europe, China etc - but we want four digit years
    patternForStyleAndLocale = StringUtils.replace(patternForStyleAndLocale, "yy", "yyyy");
}

你可以考虑将它们缓存到一个ConcurrentHashMap<Locale, String>中。
使用预本地化模式来获取数字日期的好处是,不需要后续进一步的本地化,而如果您使用诸如以下模式,则需要进行本地化:
"dd MMM yyyy" // UK: "25 Dec 2010" FRANCE: "25 déc. 2010" etc..

然而... 我刚刚从您后来的评论中注意到,您想将模式传递给JavaScript - 这可能会非常困难,因为JS使用不同的模式格式化Java(例如,ISO日期在Java中为"yyyy-MM-dd",在JS中为"yy-mm-dd")。我尚未尝试解决这个问题,但我可能会在JS或Java中使用一些字符串映射,简单地从Java模式映射到JS。当然,您必须事先了解每种语言可能遇到的每种模式。


0

听起来你想要在 DateFormat 上使用 静态getInstance方法。它们接受一个整数常量来表示风格(短格式、长格式等),还可以选择一个不同的 Locale(而不是 JVM 的默认值)。


0

你可以使用接口映射

k将是Locale, v将是一个带有日期模式的字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接