Java 6中对ISO 8601格式的通用支持
Java 7通过字符X
(而不是小写或大写Z
)在ISO 8601格式的SimpleDateFormat
类中引入了支持。 在Java 6中支持这样的格式需要预处理,因此最好的方法是问题。
这种新格式是Z
(大写Z)的超集,另外还有两种变体:
- “分钟”字段是可选的(即,2位而不是4位时区有效)
- 冒号字符(’:’)可用于将2位“小时”字段与2位“分钟”字段分开。
因此,正如人们可以从SimpleDateFormat
的Java 7文档中看到的那样,以下3种格式现在是有效的(而不仅仅是Java 6中由Z
覆盖的第二种格式),当然,等效:
- -08
- -0800
- -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 ,并给出了非常详尽的解释。