yyyy-MM-dd'T'HH:mm:ss和yyyy-MM-dd'T'HH之间的日期格式差异:mm:ssXXX

时间:2015-09-21 11:58:08

标签: java date-format simpledateformat date-formatting

我正在尝试使用以下两种格式解析日期2014-12-03T10:05:59.5646+08:00

  • yyyy-MM-dd'T'HH:mm:ss
  • yyyy-MM-dd'T'HH:mm:ssXXX

当我使用yyyy-MM-dd'T'HH:mm:ss进行解析时效果很好,但是当我解析yyyy-MM-dd'T'HH:mm:ssXXX时,会抛出ParseException

解析日期的正确格式是什么,以及这两种格式之间究竟有什么区别?

注意:我不能使用Joda :(

3 个答案:

答案 0 :(得分:6)

使用此格式yyyy-MM-dd'T'HH:mm:ss.SSSSX

来自SimpleDateFormat API

//Letter    Date or Time Component  Presentation        Example
  S         Millisecond             Number              978
  X         Time zone               ISO 8601 time zone  -08; -0800; -08:00

使用:

DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSX");
String date = "2014-12-03T10:05:59.5646+08:00";
System.out.println(format.parse(date));

输出:

Wed Dec 03 03:06:04 CET 2014

答案 1 :(得分:3)

这些是有效的格式:

yyyy-MM-dd'T'HH:mm:ss.SSSZ       >>>  e.g.: 2001-07-04T12:08:56.235-0700

yyyy-MM-dd'T'HH:mm:ss.SSSXXX     >>>  e.g.: 2001-07-04T12:08:56.235-07:00

修改
BTW," X"参考(ISO 8601时区)

答案 2 :(得分:0)

<块引用>

当我使用 yyyy-MM-dd'T'HH:mm:ss 解析时它工作正常,但是当我 解析 yyyy-MM-dd'T'HH:mm:ssXXX 抛出 ParseException

解析日期的正确格式是什么? 这两种格式有什么区别?

让我们先看看yyyy-MM-dd'T'HH:mm:ss

检查 documentation 中的以下行(重点是我的):

<块引用>

从给定字符串的开头解析文本以生成日期。 该方法可能不会使用给定字符串的整个文本

因此,基本上,格式 yyyy-MM-dd'T'HH:mm:ss 只考虑最多 2014-12-03T10:05:59 并忽略秒和时区偏移信息的分数。

yyyy-MM-dd'T'HH:mm:ssXXX 有什么问题?

在这种格式中,您正确放置了时区偏移的符号,但在几分之一秒内错过了符号。

使用 SimpleDateFormat 解析它的正确格式是什么?

简短的回答:

长答案: SimpleDateFormat 无法正确处理超过毫秒的精度(即 . 后的 3 位数字),因此没有任何格式可以正确解析它。使其正确的唯一方法是将 . 之后的数字保持为最多三位数,例如2014-12-03T10:05:59.564+08:002014-12-03T10:05:59.56+08:00 等。让我们看看 SimpleDateFormat 将如何错误地解析 2014-12-03T10:05:59.5646+08:00

SimpleDateFormat. 之后的数字视为毫秒数(而不是现代日期时间 API 考虑的几分之一秒)。因此,计算过程如下:

5646 milliseconds = 5 seconds + 646 milliseconds
2014-12-03T10:05:59 + 5 seconds + 646 milliseconds = 2014-12-03T10:06:04.646

让我们使用代码验证它:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) throws ParseException {
        String strDateTime = "2014-12-03T10:05:59.5646+08:00";
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
        Date date = sdf.parse(strDateTime);

        sdf.setTimeZone(TimeZone.getTimeZone("GMT+08:00"));
        System.out.println(sdf.format(date));
    }
}

输出:

2014-12-03T10:06:04.646+08:00

java.time

随着 2014 年 3 月 Java SE 8 的发布,过时且容易出错的旧 Date-Time API(java.util Date-Time 类型及其格式类型 SimpleDateFormat 等)被取代通过 java.timemodern Date-Time API*。强烈建议停止使用旧 API 并改用这个新 API。

使用现代 API java.time 的解决方案:

import java.time.OffsetDateTime;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odt = OffsetDateTime.parse("2014-12-03T10:05:59.5646+08:00");
        System.out.println(odt);
    }
}

输出:

2014-12-03T10:05:59.564600+08:00

是不是很酷?

现代日期时间 API 基于 ISO 8601,只要日期时间字符串符合 ISO 8601 标准,就不需要明确使用 DateTimeFormatter 对象。

顺便说一下,如果您需要将 OffsetDateTime 的这个对象转换为 java.util.Date 的对象,您可以这样做:

Date date = Date.from(odt.toInstant());

modern Date-Time API 中详细了解 java.timeTrail: Date Time*


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project