Dmi*_*i V 2 java localization date messageformat
月份名称以大写字母而不是小写字母开头,正如它们应该的那样。
我在本地机器上运行的一些示例代码:
Locale portugal = new Locale("pt");
Locale brazil = new Locale("pt", "BR");
Locale france = new Locale("fr", "FR");
Object[] params = new Object[] { new Date() };
String pattern = "Today is {0,date,long}!";
MessageFormat ptFormat = new MessageFormat(pattern, portugal);
MessageFormat brFormat = new MessageFormat(pattern, brazil);
MessageFormat frFormat = new MessageFormat(pattern, france);
StringBuffer ptResult = ptFormat.format(params, new StringBuffer(), new FieldPosition(0));
StringBuffer brResult = brFormat.format(params, new StringBuffer(), new FieldPosition(0));
StringBuffer frResult = frFormat.format(params, new StringBuffer(), null);
System.out.println("Portugal result: " + ptResult.toString());
System.out.println("Brazil result: " + brResult.toString());
System.out.println("France result: " + frResult.toString());
Run Code Online (Sandbox Code Playgroud)
这就是我得到的:
Portugal result: Today is 10 de Julho de 2018!
Brazil result: Today is 10 de Julho de 2018!
France result: Today is 10 juillet 2018!
Run Code Online (Sandbox Code Playgroud)
所以法语是正确的,但由于某种原因,两个葡萄牙语变体不是。
更奇怪的是,我尝试添加与IDEAONE 片段完全相同的代码,但它根本无法本地化。
我在这里误解了什么?
对于 Oracle JDK 和 OpenJDK 项目,版本 9 及更高版本在其自己的规则集和Unicode CLDR定义的规则集之间切换(请参阅Wikipedia)。请参阅发行说明和OpenJDK JEP 252。
运行此代码:
Month.JULY.getDisplayName( TextStyle.FULL , new Locale( "pt" ) )
Run Code Online (Sandbox Code Playgroud)
在 Java 8 中,Oracle JDK 默认使用自己的本地化规则,我们得到了 initial-cap。
朱略
在 Java 10、Oracle JDK 中,默认情况下使用 Unicode CLDR规则,我们得到小写。
朱略
在 Java 10 中,Oracle JDK 在将 VM 选项设置-Djava.locale.providers=COMPAT,SPI为恢复到旧行为而不是使用 Unicode CLDR 后,我们得到了初始上限。
朱略
代码。
ZonedDateTime // Use modern class for a moment seen from a particular time zone.
.now() // Capture the current moment, using the JVM’s current default time zone. Better to specify a zone explicitly.
.format( // Generate a `String` representing the value of our `ZonedDateTime` object.
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( new Locale( "pt" , "BR" ) )
) // Returns a `String` object.
Run Code Online (Sandbox Code Playgroud)
11 de julho de 2018 17:57:36 NZST
决定月份名称大写等问题取决于文化规范。当然,这些规范可能会有所不同,理性的人可能会不同意。
但在某些时候,必须做出决定。Java 实现必须有一套规则来制定这些本地化规则。
也许您使用的是 Java 8 或更早版本。我在这个答案中的代码是用 Java 10 生成的。
一个重要的区别是,从 Java 9 开始,对于 Oracle JDK 和 OpenJDK 项目,本地化规则的默认来源已更改为使用Unicode CLDR(请参阅维基百科)。在 Java 8 及更早版本中,每个 JVM 都提供了自己的一组规则。
另请注意,Unicode CLDR 会不时更新,某些规则可能会更改。
因此,您很可能会看到不同的本地化结果,具体取决于所使用的 Java 版本以及所使用的 Java 实现。
也许这里的问题是上下文之一。在某些文化中,格式规则(例如月份名称的大小写)因月份是单独显示还是嵌入在日期中而异。
让我们试试 translate.Google.com:
July 产量 JulhoEarly in the month of July 产量 no início do mês de julho12th of July, 2018 产量 12 de julho de 2018所以谷歌似乎因上下文而异,但我不确定第一种情况是初始上限是怎么回事。
该上下文可以通过使用方法中使用的TextStyle枚举来指示Month::getDisplayName。该枚举提供了…STANDALONE变化。
Month.JULY.getDisplayName(
TextStyle.FULL ,
new Locale( "pt" )
)
Run Code Online (Sandbox Code Playgroud)
朱略
Month.JULY.getDisplayName(
TextStyle.FULL_STANDALONE ,
new Locale( "pt" )
)
Run Code Online (Sandbox Code Playgroud)
朱略
所以不,在使用 Java 10 时,上下文似乎不是问题。
您正在使用现在被java.time类取代的麻烦的旧类。
而不是java.util.Date,使用java.time.Instant。两者都代表 UTC 中的一个时刻。现代Instant类使用更精细的纳秒分辨率而不是毫秒。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Run Code Online (Sandbox Code Playgroud)
Instant.toString(): 2018-07-11T05:57:36.446917Z
从 UTC 调整到该地区的人们使用您想要的特定挂钟时间的时区。应用 aZoneId来获取一个ZonedDateTime对象。时区与语言环境完全正交。一个与当前的内容有关,另一个仅影响用于生成字符串以表示该内容的本地化。例如,您可以使用带有葡萄牙语语言环境的日本时区。
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Run Code Online (Sandbox Code Playgroud)
现在,我们想要生成代表那个时刻的字符串。首先,通过在方括号中附加时区名称来生成String标准ISO 8601格式。
String output = zdt.toString() ; // Generate ISO 8601 format string.
Run Code Online (Sandbox Code Playgroud)
2018-07-11T17:57:36.446917+12:00[太平洋/奥克兰]
您想要本地化生成的String对象。使用DateTimeFormatter控制的格式String产生。指定一个FormatStyle来控制多长时间或缩写。
Locale l_pt = new Locale( "pt" ) ;
Locale l_ptBR = new Locale( "pt" , "BR" ) ;
Locale l_FR = Locale.FRANCE ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ) ;
String output_pt = zdt.format( f.withLocale( l_pt ) ) ;
String output_ptBR = zdt.format( f.withLocale( l_ptBR ) ) ;
String output_FR = zdt.format( f.withLocale( l_FR ) ) ;
Run Code Online (Sandbox Code Playgroud)
quarta-feira, 11 de julho de 2018 17:57:36 Horário Padrão da Nova Zelândia
quarta-feira, 11 de julho de 2018 17:57:36 Horário Padrão da Nova Zelândia
mercredi 11 juillet 2018 à 17:57:36 heure normale de la Nouvelle-Zélande
为了好玩,让我们尝试FormatStyle.LONG代替FULL.
11 de julho de 2018 17:57:36 NZST
11 de julho de 2018 17:57:36 NZST
11 juillet 2018 à 17:57:36 NZSTe
我喜欢使用 IdeOne.com 来演示 Java 代码。不幸的是,它的 JVM 拒绝使用Locale除美国英语之外的任何其他语言。所以,不要去上面的代码。
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
从哪里获得 java.time 类?
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval,YearWeek,YearQuarter,和更多。
回应对此答案的评论……
时间线:
java.util.DateIBM/ Taligent捐赠的一些日期时间类(等)。不幸的是,它们设计不佳且有缺陷,令人困惑且麻烦。java.util.Calendar等)中添加了更多类以尝试改进日期时间处理。但是这些也被证明是设计不佳和混乱的,而不是真正的改进。import语句从更改org.threeten.bp.*为java.time.*。tzdata更改和错误修复,但没有进一步的功能工作要做。他们建议从 Joda-Time 迁移到java.time类。