日期格式中yyyy-MM-dd'T'HH:mm:ss与yyyy-MM-dd'T'HH:mm:ssXXX的区别。

10
我试图解析日期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。

2
你在哪里看到应该使用 XXX 表示毫秒?我在 SimpleDateFormat 的文档中没有看到这个。 - BalusC
4个回答

8

使用这种格式 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

不要使用那种格式。请阅读我对第一个答案的评论。 - Michael-O
@aMichael-O a) 实际上第一个答案是我的。b) 这段代码是有效的,请在这里检查一个工作演示c) 你能解释一下你所说的“示例无效,因为时区偏移量没有扩展”的意思吗?谢谢。 - Jordi Castilla
我并没有说它不起作用。格式无效。请在维基百科上阅读。你有两种表示方式,基本和扩展。如果你用扩展格式写日期和时间,时区偏移也必须写出来。否则输入是无效的。 - Michael-O
@Michael-O,抱歉我不明白你的意思,实际上我不在乎维基百科上说了什么......有数百万种日期格式,对于某些人来说都是有效的,这就是为什么存在像SimpleDateFormat这样的解析器。所以请更清楚地表达,加上一些链接或者添加你自己的规范答案,因为似乎你比我们更了解这个问题... - Jordi Castilla

6

以下是有效的格式:

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

编辑:
顺便说一下,“X”是指(ISO 8601时区)


请只翻译文本内容,不要进行解释。第一个示例是无效的,因为时区偏移没有被扩展。 - Michael-O
我刚在Eclipse上运行了“今天”的程序,它输出的是:2015-09-21T17:07:56.450+0300。 - Ghayth

0
当我使用yyyy-MM-dd'T'HH:mm:ss进行解析时,它可以正常工作,但是当我使用yyyy-MM-dd'T'HH:mm:ssXXX进行解析时,会抛出一个ParseException异常。那么正确的日期格式是什么,这两种格式之间到底有什么区别呢?
首先让我们看一下yyyy-MM-dd'T'HH:mm:ss
文档中可以看到以下内容(重点在于我):
“从给定字符串的开头解析文本以生成日期。该方法可能不使用给定字符串的整个文本。”
因此,基本上,格式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

随着Java SE 8于2014年3月发布,过时且容易出错的传统日期时间API(java.util日期时间类型及其格式化类型SimpleDateFormat等)被现代日期时间API* java.time所取代。强烈建议停止使用传统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());

了解更多关于java.time现代日期时间API*请参考教程:日期时间


* 如果由于任何原因,你必须坚持使用Java 6或Java 7,你可以使用ThreeTen-Backport ,它将大部分java.time功能移植到Java 6和7。如果你正在开发一个Android项目,你的Android API级别还不符合Java-8标准,请查看通过解糖使用Java 8+ APIs如何在Android项目中使用ThreeTenABP


0

我曾经遇到过类似的问题,无法直接在 Kotlin 中转换时间戳

所以我自己写了代码

首先创建一个数据类来存储

Data class TimeAndDate(
    val day : String,
    val month : String,
    val year : String,
    val hours : String,
    val minutes : String
)

现在来转换字符串

 //for the type of yyyy-MM-dd'T'HH:mm:ss.SSS
// Here timeStamp is a String in the above format
        fun timeAndDateConverter(timeStamp: String): TimeAndDate {
            val day = timeStamp.subSequence(8, 10).toString()
            val year = timeStamp.subSequence(2, 4).toString()
            var month = timeStamp.subSequence(5, 7).toString()
            when (month) {
                "01" -> month = "Jan"
                "02" -> month = "Feb"
                "03" -> month = "Mar"
                "04" -> month = "Apr"
                "05" -> month = "May"
                "06" -> month = "Jun"
                "07" -> month = "Jul"
                "08" -> month = "Aug"
                "09" -> month = "Sep"
                "10" -> month = "Oct"
                "11" -> month = "Nov"
                "12" -> month = "Dec"

            }
            val hours = timeStamp.subSequence(11, 13).toString()
            val minutes = timeStamp.subSequence(14, 16).toString()

            return TimeAndDate(
                day = day,
                month = month,
                year = year,
                hours = hours,
                minutes = minutes
            )

        }

这个函数将返回数据类,从中我们可以获取所有单独的元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接