【问题标题】:Java SimpleDateFormat pattern for W3C XML dates with timezone [duplicate]带有时区的 W3C XML 日期的 Java SimpleDateFormat 模式 [重复]
【发布时间】:2012-05-23 19:02:20
【问题描述】:

我正在尝试解析 W3C XML Schema 日期,如下所示

"2012-05-15T07:08:09+03:00"

符合 ISO 8601 版本的W3C XML Schema dateTime 规范。

在上述日期中,时区标识符为"+03:00",但显然不存在SimpleDateFormat 模式来表示它。

如果时区为"+0300",则Z(大写)适用,SimpleDateFormat 模式为

yyyy-MM-dd'T'HH:mm:ssZ

同样,如果时区为"GMT+03:00",则z(小写)将适用,SimpleDateFormat 模式将适用

yyyy-MM-dd'T'HH:mm:ssz

(顺便说一句,大写 'Z' 也可以)。

那么,是否有 SimpleDateFormat 模式或解决方法来表示上述日期而不对日期字符串进行预处理?

【问题讨论】:

  • 实际上,输入字符串的格式符合ISO 8601 标准(日期时间格式系列)。

标签: java date simpledateformat iso8601


【解决方案1】:

如果您使用 Java 7+,则此模式应该可以工作(X 用于 ISO 8601 时区):

SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");

【讨论】:

  • 很高兴知道这一点。我仍然坚持使用 java 1.6- :(
  • Java 6 也是如此,但感谢您注意到这一点。
  • 这个问题的日期示例的正确模式应该是“yyyy-MM-dd'T'HH:mm:ssX”(即只有一个“X”)。
  • @PNS 你是对的 - 已修改。
  • 如果只使用一个X,您将获得一个截断的时区,例如2014-03-03-T16:00:00-08。根据我对docs.oracle.com/javase/7/docs/api/java/text/…(和测试)的阅读,您需要XXX 以获得格式正确的时区(至少就OP 指向的内容而言,特别是第3.2.7.3 节),例如"yyyy-MM-dd'T'HH:mm:ssXXX" ,这会给你2014-03-03-T16:00:00-08:00。请注意以冒号分隔的时区信息。
【解决方案2】:

怎么样:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"){ 
    public Date parse(String source,ParsePosition pos) {    
        return super.parse(source.replaceFirst(":(?=[0-9]{2}$)",""),pos);
    }
};

【讨论】:

  • 聪明、优雅、实用。谢谢!
  • 无论谁需要在 parse() 返回后使用 ParsePosition,您可能需要在 parse() 内将索引调整 1,因为源实际上长 1,即执行类似 pos.setIndex( pos.getIndex()+1).
  • 更改为 yyyy-MM-dd'T'HH:mm:ss.SSSZ 并且它在毫秒内也像魅力一样工作
  • 太好了,感谢分享和 +1。 :-)
【解决方案3】:

嗯,日期格式看起来像 XML 日期时间数据类型格式?如果是 XML datetime 数据类型格式可以使用javax.xml.datatype.DatatypeFactory 创建XMLGregorianCalendar

DatatypeFactory
  .newInstance()
  .newXMLGregorianCalendar("2012-05-15T07:08:09+03:00");

上述调用返回XMLGregorianCalendar 的实例,您可以使用该对象转换为其他Java 日期时间对象,如GregorianCalendar

【讨论】:

    【解决方案4】:

    不,没有解决方法可以让SimpleDateFormat 在不预处理字符串的情况下理解这种格式(例如,从字符串中删除:)。 (编辑:除非您使用的是 assylias 指出的 Java 7 或更新版本)。

    您似乎正在尝试以标准 XML 格式解析日期和时间 (ISO 8601) 的字符串。我建议使用具有support for this formatJoda Time 库。

    如果由于某种原因您不能或不想使用 Joda Time,那么您可以使用包 javax.xml.datatype 中的类来解析和格式化这种格式的时间戳。例如:

    DatatypeFactory factory = DatatypeFactory.newInstance();
    
    // Parses a string in ISO 8601 format to an XMLGregorianCalendar
    XMLGregorianCalendar xmlCal = factory.newXMLGregorianCalendar("2012-05-16T10:39:00+03:00");
    
    // Convert it to a regular java.util.Calendar
    Calendar cal = xmlCal.toGregorianCalendar();
    

    【讨论】:

    • JodaTime 不支持 Java SimpleDateFormat 类支持的所有模式。
    • @PNS 是的,但您具体询问的是 ISO 8601 格式。
    • 当然,我只是指出了限制。否则,JodaTime 可能是要走的路。
    【解决方案5】:

    使用具有可能模式的 Apache commons DateUtils。 例如:

    private static final String[] DATE_FORMATS = new String[] {
                "yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ssz",
                "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-ddz", "yyyy-MM-ddZ" };
    
    
        public Date parse(String date) {
    
            Date parsedDate = null;
            try {
                parsedDate = DateUtils.parseDate(date, DATE_FORMATS);
            } catch (ParseException e) {
                logger.error("dates should be in valid format" + e);
                return null;
            }
                   return parsedDate;
                  }
    

    【讨论】:

      【解决方案6】:

      最好的方法是使用 Joda 的

      org.joda.time.format.ISODateTimeFormat
      

      问候,

      【讨论】:

        【解决方案7】:

        关于 SimpleDateFormat,您已经提到了可用的格式模式,它们定义在:http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

        如果您想对 Date 做更多事情,那么 GregorianCalendar 会为您提供更多选择,例如:

        TimeZone zone = TimeZone.getTimeZone(TimeZone.getTimeZone("GMT-8").getID());
        GregorianCalendar calendar = new GregorianCalendar(zone);
        calendar.setTime(new Date(SomeDate));
        

        【讨论】:

          【解决方案8】:

          你可以试试这样的:

          DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
          Date date = df.parse(stringDate.replaceAll("\\+", "GMT+"));
          

          【讨论】:

          • 当然可以,但我想知道是否可以不进行预处理。
          【解决方案9】:

          我不太确定这是否适合您。 但是这里是我在将日期从一个时区转换为另一个时区时尝试过的代码。 愿部分代码对您有所帮助。

          public Date convertToUserTimezone(long dateToConvert, String timezoneOffset){
                  java.text.DateFormat format = SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);/*new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");*/
                  // java.util.Calendar cal = Calendar.getInstance(new
                  // SimpleTimeZone(0, "GMT+05:30"));
                  TimeZone gmtTime = TimeZone.getTimeZone("GMT"+timezoneOffset);
          
          
                  format.setTimeZone(gmtTime);
                  java.util.Date date1 = new Date(format.format(new Date(dateToConvert)));
          
                  return date1;
              }
          

          希望这对您有所帮助。 干杯。 :)

          【讨论】:

          • 我想要一些更简单的东西,但感谢您的努力。 :-)
          猜你喜欢
          • 1970-01-01
          • 2015-11-19
          • 2014-07-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多