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

时间:2012-10-23 22:11:54

标签: java regex date simpledateformat java-6

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

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

  1. “分钟”字段是可选的(即2位而不是4位时区有效)
  2. 冒号字符(':')可用于将2位“小时”字段与2位“分钟”字段分开。
  3. 因此,正如人们可以从Java 7 documentation of SimpleDateFormat观察到的,以下3种格式现在是有效的(而不仅仅是Java 6中Z覆盖的第二种格式),当然,等同于:< / p>

    1. -08
    2. -0800
    3. -08:00
    4. earlier question中所述,关于支持这种“扩展”时区格式的特殊情况,总是使用'​​:'作为分隔符,将Java 7功能向后移植到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;
      }
      

      请注意,必须使用相应的基于SimpleDateFormat的模式初始化上面的子类Z对象,即子类是ExtendedSimpleDateformat并且您想要解析符合模式的日期{ {1}},那么你应该使用实例化为

      的对象
      yyyy-MM-dd'T'HH:mm:ssX

      在前面提到的earlier question中,建议使用正则表达式new ExtendedSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); 来删除“:”而在similar question中,建议使用正则表达式:(?=[0-9]{2}$)附加如果需要,“分钟”字段为(?<=[+-]\d{2})$

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

      parse()

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

      iso = iso.replaceFirst("(?<=[+-]\\d{2})$", "00"); 之间进行检查,以确保稍后也正确设置if值,并且之前也进行pos比较。

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

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

      因此,准确度速度都至关重要(例如,如果使用2次传递更快,则此方法更为可取。)

2 个答案:

答案 0 :(得分:6)

似乎你可以使用它:

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();
    }
}

答案 1 :(得分:2)

您可以在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,即新类的backport(JSR 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

链接