生成&从Java

时间:2015-12-22 04:54:51

标签: java parsing datetime

我有一个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中有一些更好的方法来处理一年+一个月吗?

1 个答案:

答案 0 :(得分:0)

确实有一种更优雅的方式来处理现代Java中的YearMonth,其中java.time框架内置于Java 8及更高版本中。

此外,您的示例代码还会遇到其他一些问题:

  • 获取当前时刻两次。
    两次,冗余地获取当前时刻是一种不好的做法。如果这两行代码碰巧发生在午夜时分,那么你将会处理两个不同的日期,可能还有两个月甚至几年!
  • 忽略时区问题。
    讨论如下。

java.time

旧的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() ;