【问题标题】:Date formats difference between yyyy-MM-dd'T'HH:mm:ss and yyyy-MM-dd'T'HH:mm:ssXXXyyyy-MM-dd'T'HH:mm:ss 和 yyyy-MM-dd'T'HH:mm:ssXXX 之间的日期格式差异
【发布时间】:2015-09-21 11:58:08
【问题描述】:

我正在尝试使用这两种格式解析日期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 :(

【问题讨论】:

  • 您在哪里读到应该使用XXX 来表示毫秒?我在SimpleDateFormat javadoc 的任何地方都没有看到它。

标签: java date-format simpledateformat date-formatting


【解决方案1】:

使用这种格式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 a) 实际上第一个答案是我的。 b) 这段代码有效,please check here a working demo c) 你能解释一下你的意思吗 example is not valid because the tz offset is not extended我> ??谢谢
  • 我没有说这不起作用。格式无效。在维基百科上阅读。您必须进行表示,基本的和扩展的。如果您以扩展格式写入日期和时间,则也必须写入 tz offset。否则输入无效。
  • @Michael-O 对不起,我不明白你的意思,实际上我不在乎 wiki 说什么......有 数百万 种日期格式,并且所有人都对某人有效,这就是为什么存在像SimpleDateFormat 这样的解析器。因此,请更清楚一点,添加一些链接或添加您自己的规范答案,只要您似乎比我们对此了解更多......
【解决方案2】:

这些是有效的格式:

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 时区)

【讨论】:

  • 第一个例子是not有效的,因为 tz 偏移量没有被扩展。
  • 我刚刚在 Eclipse 上为“今天”运行了它,它产生了:2015-09-21T17:07:56.450+0300
【解决方案3】:

当我使用 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.time 取代,modern 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());

Trail: Date Time了解更多关于java.timemodern Date-Time API*


* 出于任何原因,如果您必须坚持使用 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

【讨论】:

    【解决方案4】:

    我遇到了类似的问题,无法直接在 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
                )
    
            }
    
    

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

    【讨论】:

      猜你喜欢
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2020-04-16
      • 1970-01-01
      相关资源
      最近更新 更多