Java 如何自定义Joda时间日期格式的数字格式?
我想格式化日期,同时格式化中日期中的数字 使用较旧的Java日期格式化API,我可以做到:Java 如何自定义Joda时间日期格式的数字格式?,java,jodatime,datetime-format,Java,Jodatime,Datetime Format,我想格式化日期,同时格式化中日期中的数字 使用较旧的Java日期格式化API,我可以做到: format = new SimpleDateFormat(pattern, new DateFormatSymbolsAdapter(locale)) {{ numberFormat = new DozenalNumberFormat(); }}; 不幸的是,SimpleDateFormat内部有一些愚蠢的代码,因为我经常格式化值,所以分配对象的速度太快。Joda Ti
format = new SimpleDateFormat(pattern, new DateFormatSymbolsAdapter(locale)) {{
numberFormat = new DozenalNumberFormat();
}};
不幸的是,SimpleDateFormat
内部有一些愚蠢的代码,因为我经常格式化值,所以分配对象的速度太快。Joda Time可能没有这个问题(到目前为止,他们的其他课程似乎还不错),所以我正在尝试切换
然而,对于Joda Time的日期格式类,我还不完全清楚如何做到这一点。很多API都以某种方式被锁定,很难进入并执行我想要的操作:
方法没有给我指定它的方法DateTimeFormatterBuilder
没有我可以看到的任意附加DateTimeFormatterBuilder
似乎没有任何明显的截取点DateTimeFormatter
- 所有有用的东西似乎都被锁在
及其实现中,它们是包私有的InternalPrinter
- 附加
、DateTimeFormatter
等的方法似乎需要大量的框架才能进行定制实现,而我的实现还没有成功。经过一番调查,这似乎是一件好事DateTimePrinter
当然,一定有办法做到这一点。有人知道吗?我想,也许过去也有人不得不这样做,以使阿拉伯语日期格式正确工作,因为我隐约记得Joda Time在这方面有问题,但也许那是在过去。我可能是第一个尝试这样做的人,因为我想要一个不同的数字基数…你的问题一点也不清楚,因为你没有具体说明你想做什么,也没有确切说明什么在阻止你。但我会提供一些信息 仅供参考,该项目目前正在进行中,团队建议迁移到类 使用java.time java.time和Joda时间都使用。这意味着你有内在的能力。因此,您可以缓存格式化程序对象并重新使用它们。无需重复实例化 在java.time中,该类可以为您自动本地化。人工语言和格式都可以从计算机自动分配。看见我建议在这些自动本地化格式足够时使用它们 捕获UTC中的当前时刻。调整到一个时区。请注意,时区与区域设置无关。您可能希望在格式化演示文稿时查看中的 生成用于向用户演示的字符串
Locale l = new Locale ( "ar" , "MA" ); // Arabic language, cultural norms of Morocco.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.FULL ).withLocale ( l );
保留对f
的引用以缓存该对象。无需再次实例化
转储到控制台
String output = zdt.format ( f );
System.out.println ( "zdt.toString(): " + zdt );
System.out.println ( "output: " + output );
zdt.toString():2017-01-01T15:06:34.255-05:00[美国/蒙特利尔]
输出:2017年美国东部时间01:06:34
我不确定阿拉伯文是否能在这里正确复制粘贴。看
关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,& 该项目现已启动,建议迁移到类 要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是 从哪里获得java.time类
- 后来
- 内置的李>
- 标准JavaAPI的一部分,带有捆绑实现
- Java9添加了一些次要功能和修复
- 及
- 大部分java.time功能都在中向后移植到Java6和Java7
-
- 该项目专门为Android采用了ThreeTen Backport(如上所述)
- 看
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,如、、和。Joda Time显然无法打印ASCII数字0-9以外的其他数字。我已经调查了Joda文档的所有相关部分,甚至包括类
DateTimeUtils
和FormatUtils
。将区域设置为强制使用替代编号系统的区域设置也没有帮助
String s = DateTimeFormat.forPattern("yyyy-MM-dd").withLocale(new Locale("ar"))
.print(System.currentTimeMillis()));
// output: 2017-01-02 (still ASCII)
最新的CLDR数据()告诉我们,阿拉伯语使用代号为“arab”的替代编号系统(xml标记defaultNumberingSystem
)。然而,JDK可能并不总是最新的。JDK通常依赖于旧的CLDR版本。但即便如此,据我记忆所及,旧的CLDR版本也没有使用ASCII数字表示阿拉伯语
结论:您不应该将Joda时间用于严肃的i18n工作(这是许多其他细节中的一个,比如固定的每周开始时间等,其中这个库是出了名的糟糕)。如果您仍然坚持使用Joda Time,那么您可以不遗余力地编写自己定制的DateTimePrinter
。但这并不有趣,正如您在您的应用程序中所注意到的(并且在可能的修复之后仍然没有乐趣,因为它太尴尬了)
让我们看看更好的选择
Java-8
Locale loc = new Locale("ar");
System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd")
.withDecimalStyle(DecimalStyle.of(loc))
.format(LocalDate.now()));
// output: 2017-01-02 (obviously my JDK uses wrong or outdated data)
System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd")
.withDecimalStyle(DecimalStyle.STANDARD.withZeroDigit('\u0660'))
.format(LocalDate.now()));
// correct output with hardwired numbering system
因此,我们看到在Java-8上使用该标准比Joda Time更好,但仍然有一些怪癖。正确且唯一灵活的解决方案是使用类
我的库(在版本行为v3.x的Java-6上也可以运行):
我已经编写了一个替代格式和解析引擎,它还可以处理Java-8类型,如LocalDate
,Instant
等。Time4J有自己的本地化资源存储库,独立于JDK,并且实际使用CLDR v30.0.2版。显示两种方式,一种是按区域设置的通用方式,另一种是使用有关编号系统的硬连线假设:
System.out.println(
ChronoFormatter.ofPattern(
"yyyy-MM-dd",
PatternType.CLDR,
new Locale("ar"),
PlainDate.axis(TemporalType.LOCAL_DATE)
).format(LocalDate.now()));
System.out.println(
ChronoFormatter.ofPattern(
"yyyy-MM-dd",
PatternType.CLDR,
Locale.ROOT,
PlainDate.axis(TemporalType.LOCAL_DATE)
)
.with(Attributes.NUMBER_SYSTEM, NumberSystem.ARABIC_INDIC)
.format(LocalDate.now()));
这两种方法都基于零位٠(unicode点0660)生成数字表示。2017年显示为:٢٠١٧
更新:
System.out.println(
ChronoFormatter.ofPattern(
"yyyy-MM-dd",
PatternType.CLDR,
new Locale("ar"),
PlainDate.axis(TemporalType.LOCAL_DATE)
).format(LocalDate.now()));
System.out.println(
ChronoFormatter.ofPattern(
"yyyy-MM-dd",
PatternType.CLDR,
Locale.ROOT,
PlainDate.axis(TemporalType.LOCAL_DATE)
)
.with(Attributes.NUMBER_SYSTEM, NumberSystem.ARABIC_INDIC)
.format(LocalDate.now()));
@Test
public void printDate() {
ChronoFormatter<PlainDate> f =
ChronoFormatter.setUp(PlainDate.axis(), Locale.ROOT)
.addFixedInteger(PlainDate.YEAR, 4)
.addLiteral('-')
.padNext(2)
.addInteger(PlainDate.MONTH_AS_NUMBER, 1, 2)
.addLiteral('-')
.padNext(2)
.addInteger(PlainDate.DAY_OF_MONTH, 1, 2)
.build()
.with(Attributes.NUMBER_SYSTEM, NumberSystem.DOZENAL)
.with(Attributes.PAD_CHAR, '0');
assertThat(
f.format(PlainDate.of(2017, 10, 11)),
is("1201-0\u218A-0\u218B"));
}
ChronoFormatter.setUp(
Moment.axis(TemporalType.JAVA_UTIL_DATE), Locale.getDefault())...