解析字符串到日期:非法模式字符'T'。

Posted

技术标签:

【中文标题】解析字符串到日期:非法模式字符\'T\'。【英文标题】:Parsing string to date: Illegal pattern character 'T'.解析字符串到日期:非法模式字符'T'。 【发布时间】:2014-12-11 11:32:39 【问题描述】:

我需要在 java 中解析一个字符串到日期。我的字符串格式如下:

2014-09-17T12:00:44.0000000Z

但是 java 在尝试解析这种格式时会抛出以下异常...java.lang.IllegalArgumentException: Illegal pattern character 'T'

关于如何解析它的任何想法?

谢谢!

【问题讨论】:

current_date=formatter.parse(date) 将格式化程序对象也添加到此处 是的,当然,抱歉:SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-ddTHH:mm:ss.SSS"); 使用 'T' 而不是只使用 T 【参考方案1】:

java.time

现在是现代答案的时候了:始终使用现代 Java 日期和时间 API java.time 来处理日期和时间工作。当被问到这个问题时,java.time 已经使用 Java 8 7 个月了。今天(2020 年)没有人应该使用 SimpleDateFormat 类,这似乎是问题中的麻烦。它出了名的麻烦和过时。

使用 java.time 我们不需要显式格式化程序:

    String str = "2014-09-17T12:00:44.0000000Z";
    Instant i = Instant.parse(str);
    System.out.println("As Instant: " + i);

输出是:

即时:2014-09-17T12:00:44Z

您的格式是 ISO 8601(链接在底部)。 java.time 的类通常将 ISO 8601 解析为其默认值,并从其toString 方法中打印回 ISO 8601。在 ISO 8601 中,秒的小数部分是可选的。

如果您需要 Date 对象用于尚未升级到 java.time 的旧版 API:

    Date oldfashionedDate = Date.from(i);
    System.out.println("As old-fashioned Date: " + oldfashionedDate);

在我的时区输出:

作为老式日期:2014 年 9 月 17 日星期三 14:00:44 CEST

输出会因时区而异,因为 Date.toString() 容易混淆地采用 JVM 的默认时区并将其用于呈现字符串。

你出了什么问题?

您没有向我们展示您的代码,但我们已经可以看出有几处是错误的:

    SimpleDateFormat 无法正确解析秒上有 7 个小数的字符串。它仅支持毫秒,精确到小数点后三位。 在您的格式模式字符串中,您需要通过将文字 T 括在单引号中来转义它,'T'SimpleDateFormat 会将其理解为模式字母,并且没有格式模式字母 T .这就是您的异常消息的含义。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。 Wikipedia article: ISO 8601。 Related question: Date object SimpleDateFormat not parsing timestamp string correctly in Java (android) environment 关于解析超过三位小数的秒数。 Related question: ISO 8601 String to Date/Time object in Android。

【讨论】:

【参考方案2】:

试试这个。

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

public class DateClass 
    public static void main(String[] args) throws ParseException 
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        Date d = sdf.parse("2014-09-17T12:00:44.0000000Z");
        System.out.println(d); //output Wed Sep 17 12:00:44 IST 2014
    

【讨论】:

【参考方案3】:

鉴于您输入的2014-09-17T12:00:44.0000000Z,仅转义字母T 是不够的。您还必须处理尾随的Z。但请注意,这个Z 不是文字,而是根据ISO-8601-standard 具有UTC+00:00 时区偏移量的含义。所以转义Z 是不正确的。

SimpleDateFormat 通过模式符号 X 处理这个特殊字符 Z。所以最终的解决方案是这样的:

 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSX");
 Date d = sdf.parse("2014-09-17T12:00:44.0000000Z");
 System.out.println(d); // output: Wed Sep 17 14:00:44 CEST 2014

请注意,不同的时钟时间适用于时区CESTtoString() 使用系统时区),结果等价于UTC-time 12:00:44。此外,我必须插入七个符号 S 才能正确处理您的输入,该输入假装精度低至 100ns(尽管 Java pre 8 只能处理毫秒)。

【讨论】:

但有一条评论,您需要在构造函数 SimpleDateFormat 中将最后一个 X 字符替换为“Z”。很好的解决方案,对我有用 @VictorPonomarenko 符号字母 X 是在 Java 7 中引入的。对于 Java 6,如果解析的文字“Z”将被识别为 UTC+00,我不确定 Z 是否可以作为替换含义!也许最好使用 Java 6 的解决方法来转义 Z(仅将其解释为文字)并将SimpleDateFormat-object 上的区域设置为“GMT”。 在 android 上我得到运行时异常,当离开 X 字符时,但在替换为 'Z' 后效果很好(android 现在可以在 java 7 上运行) @VictorPonomarenko Z 似乎是Android 的正确符号,虽然文档不是很详细,但请记住:Android != Java(和SimpleDateFormat-API 确实不同在两个世界中)。【参考方案4】:

您必须转义“T”字符:

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
    format.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date parse = format.parse("2014-09-17T12:00:44.0000000Z");

使用答案:What is this date format? 2011-08-12T20:17:46.384Z

【讨论】:

感谢您的回答,现在我没有得到同样的异常,但是这个:“java.text.ParseException: Unparseable date: "Date"”。我认为日期格式还没有很好的定义......

以上是关于解析字符串到日期:非法模式字符'T'。的主要内容,如果未能解决你的问题,请参考以下文章

使用 moment.js 解析字符串到日期

无法解析ISO 8601格式的字符串,缺少冒号的冒号,到Java 8 Date

如何在java中获取给定的日期字符串格式(模式)?

如何将RFC 3339日期字符串解析为ZonedDateTime?

如何解析日期字符串

Java - LocalDateTime解析日期字符串值时丢弃秒值“00“,如“2021-07-01 15:33:00“ 转换为“2021-07-01T15:33“