Java 6中对ISO 8601格式的通用支持

Java 7通过字符X (而不是小写或大写Z )在ISO 8601格式的SimpleDateFormat类中引入了支持。 在Java 6中支持这样的格式需要预处理,因此最好的方法是问题。

这种新格式是Z (大写Z)的超集,另外还有两种变体:

  1. “分钟”字段是可选的(即,2位而不是4位时区有效)
  2. 冒号字符(’:’)可用于将2位“小时”字段与2位“分钟”字段分开。

因此,正如人们可以从SimpleDateFormat的Java 7文档中看到的那样,以下3种格式现在是有效的(而不仅仅是Java 6中由Z覆盖的第二种格式),当然,等效:

  1. -08
  2. -0800
  3. -08:00

正如之前关于支持这种“扩展”时区格式的特殊情况所讨论的那样 ,总是以’:’作为分隔符,将Java 7function向后移植到Java 6中的最佳方法是将SimpleDateformat类子类化并覆盖它parse()方法,即:

 public Date parse(String date, ParsePosition pos) { String iso = ... // Replace the X with a Z timezone string, using a regex if (iso.length() == date.length()) { return null; // Not an ISO 8601 date } Date parsed = super.parse(iso, pos); if (parsed != null) { pos.setIndex(pos.getIndex()+1); // Adjust for ':' } return parsed; } 

请注意,必须使用相应的基于Z的模式初始化上面的子类化SimpleDateFormat对象,即如果子类是ExtendedSimpleDateformat并且您想要解析符合模式yyyy-MM-dd'T'HH:mm:ssX ,那么您应该使用实例化的对象

 new ExtendedSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 

在前面提到的问题中 ,正则表达式:(?=[0-9]{2}$)已被建议用于删除’:’并且在类似的问题中正则表达式(?<=[+-]\d{2})$如果需要,建议(?<=[+-]\d{2})$将“分钟”字段附加为00

显然,成功运行2个替换可用于实现全部function。 因此,重写的parse()方法中的iso局部变量将设置为

 iso = date.replaceFirst(":(?=[0-9]{2}$)",""); 

要么

 iso = iso.replaceFirst("(?<=[+-]\\d{2})$", "00"); 

使用if检查以确保稍后也正确设置pos值以及之前的length()比较。

问题是:我们是否可以使用单个正则表达式来实现相同的效果,包括不必要地检查长度以及以后正确设置几行所需的信息?

该实现旨在用于读取可以采用任何格式(甚至完全非日期)的大量字符串字段的代码,仅选择符合该格式的字符串并返回已解析的Java Date对象。

因此, 准确性速度都是至关重要的(即,如果使用2次传递更快,这种方法是可取的)。

似乎你可以使用这个:

 import java.util.Calendar; import javax.xml.bind.DatatypeConverter; public class TestISO8601 { public static void main(String[] args) { parse("2012-10-01T19:30:00+02:00"); // UTC+2 parse("2012-10-01T19:30:00Z"); // UTC parse("2012-10-01T19:30:00"); // Local } public static Date parse(final String str) { Calendar c = DatatypeConverter.parseDateTime(str); System.out.println(str + "\t" + (c.getTime().getTime()/1000)); return c.getTime(); } } 

您可以在Java 6中使用现代Java日期和时间API java.time。这在我看来是一个很好的,也是面向未来的解决方案。 它对ISO 8601有很好的支持。

 import org.threeten.bp.OffsetDateTime; import org.threeten.bp.format.DateTimeFormatter; public class DemoIso8601Offsets { public static void main(String[] args) { System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+0200", DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXX"))); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02", DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX"))); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02:00")); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00Z")); } } 

该计划的输出是:

 2012-10-01T19:30+02:00 2012-10-01T19:30+02:00 2012-10-01T19:30+02:00 2012-10-01T19:30Z 

它要求您将ThreeTen Backport库添加到项目设置中。

  • 在Java 8及更高版本和更新的Android设备上(来自API级别26),现代API内置。
  • 在Java 6和7中获取ThreeTen Backport,这是新类的后端(JST 310的ThreeTen;请参见底部的链接)。
  • 在(较旧的)Android上使用Android版的ThreeTen Backport。 它被称为ThreeTenABP。 并确保从子包中导入org.threeten.bp的日期和时间类。

从代码中可以看出,+ 02和+0200需要格式化程序,您可以在其中指定偏移的格式,而+02:00 (以及Z也)符合默认格式,不需要指定。

我们可以使用相同的格式化程序解析所有偏移格式吗?

读取混合数据时,您不希望特别处理每种偏移格式。 最好在格式模式字符串中使用可选部分:

  DateTimeFormatter allInOne = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[XXX][XX][X]"); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+0200", allInOne)); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02", allInOne)); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00+02:00", allInOne)); System.out.println(OffsetDateTime.parse("2012-10-01T19:30:00Z", allInOne)); 

输出与上面相同。 [XXX][XX][X]的方括号表示可能存在+02:00+0200+02格式。

链接

  • Oracle教程:Date Time解释了如何使用java.time
  • Java规范请求(JSR)310 ,其中首先描述了java.time
  • ThreeTen Backport项目 , java.time到Java 6和7(用于JSR-310的ThreeTen)。
  • ThreeTenABP ,Android版ThreeTen Backport
  • 问题:如何在Android项目中使用ThreeTenABP ,并给出了非常详尽的解释。