月份名称以大写字母开头,而不是小写as they should。
我在本地计算机上运行了一些示例代码:
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());
这就是我得到的:
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!
所以法语是正确的,但由于某些原因,这两个葡萄牙语变体不正确。
即使很奇怪,我也尝试添加与IDEAONE snippet完全相同的代码,并且它根本不会本地化。
我在这里误会什么?
答案 0 :(得分:2)
对于Oracle JDK和OpenJDK项目,版本9和更高版本在其自己的规则集和Unicode CLDR定义的规则集之间切换(请参阅Wikipedia)。请参阅Release Notes和OpenJDK JEP 252。
运行以下代码:
Month.JULY.getDisplayName( TextStyle.FULL , new Locale( "pt" ) )
在Java 8中,默认情况下,Oracle JDK使用其自己的本地化规则,我们获得了首字母大写。
朱利叶
在Java 10,Oracle JDK中,默认情况下使用Unicode CLDR 规则,我们将小写。
julho
在Java 10中,将VM选项-Djava.locale.providers=COMPAT,SPI
设置为恢复为旧行为而不是使用Unicode CLDR之后,Oracle JDK便获得了首字母大写。
朱利叶
代码。
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.
2018年7月11日NZST 17:57:36
确定诸如月姓大写之类的问题取决于文化的规范。当然,这些规范可能会有所不同,并且理性的人可能会不同意。
但是在某些时候,必须做出决定。 Java实现必须具有一组用于制定这些本地化规则的规则。
也许您正在使用Java 8或更早版本。我在此答案中的代码是使用Java 10制作的。
一个重要的区别是,从Java 9开始,对于Oracle JDK和OpenJDK项目,localization rules changed的默认来源是使用Unicode CLDR的(请参阅Wikipedia)。在Java 8和更早版本中,每个JVM提供了自己的规则集。
此外,请注意,Unicode CLDR会不时更新,并且某些规则可能会更改。
因此,您可能会看到不同的本地化结果,具体取决于所使用的Java版本和所使用的Java实现。
也许这里的问题是上下文之一。在某些文化中,格式规则(例如,月份名称的大写)因月份是单独显示还是嵌入在日期中而异。
让我们尝试翻译。Google.com:
July
产生Julho
Early in the month of July
产生no início do mês de julho
12th of July, 2018
产生12 de julho de 2018
因此Google似乎因上下文而异,但是我不确定第一种情况是首字母大写情况是什么。
可以通过使用TextStyle
方法中使用的Month::getDisplayName
枚举来指示此上下文。该枚举提供了…STANDALONE
个变体。
Month.JULY.getDisplayName(
TextStyle.FULL ,
new Locale( "pt" )
)
julho
Month.JULY.getDisplayName(
TextStyle.FULL_STANDALONE ,
new Locale( "pt" )
)
julho
所以不,使用Java 10时上下文似乎不是问题。
您正在使用麻烦的旧类,而这些旧类现在已被 java.time 类取代。
使用java.util.Date
代替java.time.Instant
。两者都代表UTC的时刻。现代的Instant
类使用的是纳秒级而不是毫秒级的更精细分辨率。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
instant.toString():2018-07-11T05:57:36.446917Z
从UTC调整到该地区的人使用您想要的特定挂钟时间的时区。应用ZoneId
获得ZonedDateTime
对象。时区与语言环境完全正交。一个与当下的内容有关,另一个仅影响用于生成表示该内容的字符串的本地化。例如,您可以将日本时区与葡萄牙语一起使用。
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
现在,我们要生成表示该时刻的字符串。首先,生成标准ISO 8601格式的String
,方法是将时区的名称附加在方括号中。
String output = zdt.toString() ; // Generate ISO 8601 format string.
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 ) ) ;
quarta-feira,2018年7月11日17:57:36HorárioPadrãoda NovaZelândia
quarta-feira,2018年7月11日17:57:36HorárioPadrãoda NovaZelândia
mercredi 11 juillet 2018à17:57:36 heure normale de laNouvelle-Zélande
为了娱乐,我们尝试使用FormatStyle.LONG
而不是FULL
。
2018年7月11日NZST 17:57:36
2018年7月11日NZST 17:57:36
2018年6月11日NZSTe 17:57:36
我喜欢使用IdeOne.com演示Java代码。不幸的是,其JVM拒绝使用除美国英语以外的任何Locale
。因此,不要使用上面的代码。
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
回复对此答案的评论…
时间轴:
java.util.Date
等)。不幸的是,它们的设计欠佳,有缺陷,令人困惑和麻烦。java.util.Calendar
等)中添加了更多类,以改善日期时间处理。但是事实证明,这些设计不当且令人困惑,不是真正的改进。import
语句从org.threeten.bp.*
更改为java.time.*
。 tzdata
更改和错误修复,以积极方式进行更新,但无需进行进一步的功能工作。他们建议从Joda-Time迁移到 java.time 类。