【发布时间】:2012-10-13 22:58:57
【问题描述】:
Java 7 通过字符X(而不是小写或大写Z)在SimpleDateFormat 类中引入了对ISO 8601 格式的支持。在 Java 6 中支持此类格式需要预处理,因此最好的方法就是问题。
这种新格式是 Z(大写 Z)的超集,还有 2 个额外的变体:
- “分钟”字段是可选的(即,2 位而不是 4 位时区有效)
- 冒号 (':') 可用于将 2 位“小时”字段与 2 位“分钟”字段分开。
因此,从Java 7 documentation of SimpleDateFormat 可以看出,以下 3 种格式现在是有效的(而不是在 Java 6 中 Z 仅涵盖第二种格式),当然,它们是等效的:
- -08
- -0800
- -08:00
正如earlier question 中所讨论的,关于支持这种“扩展”时区格式的特殊情况,始终使用 ':' 作为分隔符,将 Java 7 功能反向移植到 Java 6 的最佳方法是将 @ 子类化987654334@ 类并覆盖其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;
}
注意,上面的子类SimpleDateFormat对象必须用对应的基于Z的模式初始化,即如果子类是ExtendedSimpleDateformat并且你想解析符合模式yyyy-MM-dd'T'HH:mm:ssX的日期,那么你应该使用实例化为的对象
new ExtendedSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
在上述earlier question 中,建议使用正则表达式:(?=[0-9]{2}$) 去掉':',在similar question 中建议使用正则表达式(?<=[+-]\d{2})$ 将“分钟”字段附加为00 ,如果需要的话。
显然,成功运行 2 个替换可用于实现全部功能。因此,被覆盖的parse() 方法中的iso 局部变量将被设置为
iso = date.replaceFirst(":(?=[0-9]{2}$)","");
或
iso = iso.replaceFirst("(?<=[+-]\\d{2})$", "00");
在两者之间使用if 检查以确保稍后也正确设置pos 值,并且还用于之前的length() 比较。
问题是:我们是否可以使用单个正则表达式来达到相同的效果,包括不需要检查长度以及在几行之后正确设置pos所需的信息?
该实现适用于读取大量可以是任何格式(甚至完全非日期)的字符串字段的代码,仅选择符合格式并返回已解析的 Java Date 对象。
因此,accuracy 和 speed 都至关重要(即,如果使用 2 次通道更快,则首选此方法)。
【问题讨论】:
-
你检查过JDK 7中的相应代码吗?
-
还没有,因为我没有使用它,但可能这不会提供太大帮助,因为在 SimpleDateFormat 类中,模式在处理之前被编译成语法,因此与任何正则表达式都没有对应关系.谢谢,无论如何+1。 :-)
-
你考虑过javax.xml.datatype.DatatypeFactory吗?它支持 8601 格式的日期字符串。见download.java.net/jdk7/archive/b123/docs/api/javax/xml/datatype/…
-
你为什么不试试 Joda Time 让它返回一个
Date对象? -
取代旧的日期时间类(
Date、Calendar等)和 Joda-Time 的 java.time 类的使用要容易得多。大部分 java.time 功能在ThreeTen-Backport 中向后移植到 Java 6 和 7,并在 ThreeTenABP 中进一步适应 Android。
标签: java regex date simpledateformat java-6