我有一个HTML弹出菜单,列出了各种年月组合。每个菜单项都有一个本地化的字符串表示形式,例如Nov 2015
用于内容显示,以及编码值的属性,例如201511
。
例如:
<select name="selectPeriod">
<option value="201511">Nov 2015</option>
<option value="201510">Oct 2015</option>
<option value="201509">Sept 2015</option>
我使用java.util.Calendar生成编码值字符串。
int month = Calendar.getInstance().get(Calendar.MONTH)+1;
int year = Calendar.getInstance().get(Calendar.YEAR);
String v = String.valueOf( year ) + String.valueOf( month );
这很有效,但是当我真正关心的是没有日期或时间的年份+月份时,使用日历(日期加上一个时间)似乎很奇怪。
在现代Java中有一些更好的方法来处理一年+一个月吗?
答案 0 :(得分:0)
确实有一种更优雅的方式来处理现代Java中的YearMonth,其中java.time框架内置于Java 8及更高版本中。
此外,您的示例代码还会遇到其他一些问题:
旧的java.util.Calendar / .Date类非常麻烦,应该避免使用。它们已经在Java 8及更高版本的java.time框架中被取代。
新课程的灵感来自非常成功的Joda-Time框架,旨在作为其继承者,在概念上类似但重新设计。由JSR 310定义。由ThreeTen-Extra项目扩展。请参阅Tutorial。
YearMonth
新课程包括一个类YearMonth
,完全符合您的目的:代表一年+月,没有任何日期,时间或时区。
我建议在业务逻辑中使用此类的对象,仅在必要时使用字符串,例如生成HTML。
虽然YearMonth中没有包含时区,但请注意,时区对于确定当前YearMonth至关重要。当前日期,因此YearMonth,随时都在世界各地变化。新的一天在东方如巴黎早于西方如蒙特利尔,它仍然是“昨天”。
如果在示例代码中省略了时区,则隐式使用JVM的当前默认时区。这种隐式使用意味着您的结果可能因以下几个原因而有所不同:您的代码可能会移动到另一台计算机,系统管理员可能会更改主机的默认设置,甚至更糟糕的是,在同一JVM中运行的任何应用程序的任何线程中的任何代码都可以{ {3}}。最好指定期望/预期的时区(java.time中的change the time zone at runtime)。
ZoneId zoneId = ZoneId.of( "America/Montreal" );
YearMonth yearMonth = YearMonth.now( zoneId );
java.time类中的toString
方法默认使用标准ZoneId
格式。您的格式YYYYMM
与标准格式类似,但在此特定情况下(年 - 月),需要使用连字符来避免歧义,YYYY-MM
。大多数标准格式允许省略连字符的“基本”变体,但不在此。
我强烈建议尽可能以ISO 8601格式制作日期时间值的字符串表示。
String output = yearMonth.toString ();
2015-12
我强烈建议您在HTML属性中使用该格式。坚持使用ISO 8601将简化您的生活。像这样(注意连字符):
<option value="2015-11">Nov 2015</option>
但是如果你坚持,你可以通过指定ISO 8601来构建没有连字符的字符串。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "yyyyMM" );
String output = yearMonth.format ( formatter );
201512
让java.time完成本地化显示文本的工作。注意custom formatter pattern传递给DateTimeFormatter而不是隐式依赖于JVM的当前默认Locale。
Locale locale = Locale.CANADA_FRENCH;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "MMM yyyy" , locale );
String output = yearMonth.format ( formatter );
(分解)。 2015
如果您需要特定日期,请指定与该年份和月份结合的日期。
LocalDate ld = ym.atDay( 1 ) ; // Get first day of that year-month.
从那里你可以得到一个特定的时刻,例如一天的第一时刻。 不假设当天从00:00:00开始。让 java.time 确定第一时刻。
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
如果您需要在UTC中查看同一时刻,请提取Instant
。
Instant instant = zdt.toInstant() ;