非法模式字符 'T'将日期字符串解析为 java.util.Date 时

发布于 2024-08-28 18:57:15 字数 681 浏览 7 评论 0 原文

我有一个日期字符串,我想使用 java Date API 将其解析为正常日期,以下是我的代码:

public static void main(String[] args) {
    String date="2010-10-02T12:23:23Z";
    String pattern="yyyy-MM-ddThh:mm:ssZ";
    SimpleDateFormat sdf=new SimpleDateFormat(pattern);
    try {
        Date d=sdf.parse(date);
        System.out.println(d.getYear());
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

但是我遇到了异常: java.lang.IllegalArgumentException: 非法模式字符 'T'

所以我想知道是否必须拆分字符串并手动解析它?

顺便说一句,我尝试在 T 的两侧添加单引号字符:

String pattern="yyyy-MM-dd'T'hh:mm:ssZ";

它也不起作用。

I have a date string and I want to parse it to normal date use the java Date API,the following is my code:

public static void main(String[] args) {
    String date="2010-10-02T12:23:23Z";
    String pattern="yyyy-MM-ddThh:mm:ssZ";
    SimpleDateFormat sdf=new SimpleDateFormat(pattern);
    try {
        Date d=sdf.parse(date);
        System.out.println(d.getYear());
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

However I got an exception: java.lang.IllegalArgumentException: Illegal pattern character 'T'

So I wonder if I have to split the string and parse it manually?

BTW, I have tried to add a single quote character on either side of the T:

String pattern="yyyy-MM-dd'T'hh:mm:ssZ";

It also does not work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

阿楠 2024-09-04 18:57:15

Java 8 及更高版本的更新

您现在可以简单地执行 Instant.parse("2015-04-28T14:23:38.521Z") 并立即获得正确的结果,特别是因为您应该使用 Instant 而不是最新版本 Java 中损坏的 java.util.Date

您还应该使用 DateTimeFormatter 而不是 SimpleDateFormatter

原答案:

下面的解释与格式所代表的内容一样仍然有效。
但它是在 Java 8 普及之前编写的,所以它使用旧的
如果您使用 Java 8 或
更高。

这适用于带有尾随 Z 的输入,如下所示:

在该模式中,T 在两侧均使用 ' 进行转义。

末尾的 Z 模式实际上是文档中的 XXX
SimpleDateFormat 的 JavaDoc 中,它不是很清楚
实际上如何使用它,因为 Z 是旧版本的标记
还有时区信息。

Q2597083.java

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class Q2597083
{
    /**
     * All Dates are normalized to UTC, it is up the client code to convert to the appropriate TimeZone.
     */
    public static final TimeZone UTC;

    /**
     * @see <a href="http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations">Combined Date and Time Representations</a>
     */
    public static final String ISO_8601_24H_FULL_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

    /**
     * 0001-01-01T00:00:00.000Z
     */
    public static final Date BEGINNING_OF_TIME;

    /**
     * 292278994-08-17T07:12:55.807Z
     */
    public static final Date END_OF_TIME;

    static
    {
        UTC = TimeZone.getTimeZone("UTC");
        TimeZone.setDefault(UTC);
        final Calendar c = new GregorianCalendar(UTC);
        c.set(1, 0, 1, 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);
        BEGINNING_OF_TIME = c.getTime();
        c.setTime(new Date(Long.MAX_VALUE));
        END_OF_TIME = c.getTime();
    }

    public static void main(String[] args) throws Exception
    {

        final SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_24H_FULL_FORMAT);
        sdf.setTimeZone(UTC);
        System.out.println("sdf.format(BEGINNING_OF_TIME) = " + sdf.format(BEGINNING_OF_TIME));
        System.out.println("sdf.format(END_OF_TIME) = " + sdf.format(END_OF_TIME));
        System.out.println("sdf.format(new Date()) = " + sdf.format(new Date()));
        System.out.println("sdf.parse(\"2015-04-28T14:23:38.521Z\") = " + sdf.parse("2015-04-28T14:23:38.521Z"));
        System.out.println("sdf.parse(\"0001-01-01T00:00:00.000Z\") = " + sdf.parse("0001-01-01T00:00:00.000Z"));
        System.out.println("sdf.parse(\"292278994-08-17T07:12:55.807Z\") = " + sdf.parse("292278994-08-17T07:12:55.807Z"));
    }
}

产生以下输出:

sdf.format(BEGINNING_OF_TIME) = 0001-01-01T00:00:00.000Z
sdf.format(END_OF_TIME) = 292278994-08-17T07:12:55.807Z
sdf.format(new Date()) = 2015-04-28T14:38:25.956Z
sdf.parse("2015-04-28T14:23:38.521Z") = Tue Apr 28 14:23:38 UTC 2015
sdf.parse("0001-01-01T00:00:00.000Z") = Sat Jan 01 00:00:00 UTC 1
sdf.parse("292278994-08-17T07:12:55.807Z") = Sun Aug 17 07:12:55 UTC 292278994

Update for Java 8 and higher

You can now simply do Instant.parse("2015-04-28T14:23:38.521Z") and get the correct thing now, especially since you should be using Instant instead of the broken java.util.Date with the most recent versions of Java.

You should be using DateTimeFormatter instead of SimpleDateFormatter as well.

Original Answer:

The explanation below is still valid as as what the format represents.
But it was written before Java 8 was ubiquitous so it uses the old
classes that you should not be using if you are using Java 8 or
higher.

This works with the input with the trailing Z as demonstrated:

In the pattern the T is escaped with ' on either side.

The pattern for the Z at the end is actually XXX as documented
in the JavaDoc for SimpleDateFormat, it is just not very clear
on actually how to use it since Z is the marker for the old
TimeZone information as well.

Q2597083.java

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class Q2597083
{
    /**
     * All Dates are normalized to UTC, it is up the client code to convert to the appropriate TimeZone.
     */
    public static final TimeZone UTC;

    /**
     * @see <a href="http://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations">Combined Date and Time Representations</a>
     */
    public static final String ISO_8601_24H_FULL_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

    /**
     * 0001-01-01T00:00:00.000Z
     */
    public static final Date BEGINNING_OF_TIME;

    /**
     * 292278994-08-17T07:12:55.807Z
     */
    public static final Date END_OF_TIME;

    static
    {
        UTC = TimeZone.getTimeZone("UTC");
        TimeZone.setDefault(UTC);
        final Calendar c = new GregorianCalendar(UTC);
        c.set(1, 0, 1, 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);
        BEGINNING_OF_TIME = c.getTime();
        c.setTime(new Date(Long.MAX_VALUE));
        END_OF_TIME = c.getTime();
    }

    public static void main(String[] args) throws Exception
    {

        final SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_24H_FULL_FORMAT);
        sdf.setTimeZone(UTC);
        System.out.println("sdf.format(BEGINNING_OF_TIME) = " + sdf.format(BEGINNING_OF_TIME));
        System.out.println("sdf.format(END_OF_TIME) = " + sdf.format(END_OF_TIME));
        System.out.println("sdf.format(new Date()) = " + sdf.format(new Date()));
        System.out.println("sdf.parse(\"2015-04-28T14:23:38.521Z\") = " + sdf.parse("2015-04-28T14:23:38.521Z"));
        System.out.println("sdf.parse(\"0001-01-01T00:00:00.000Z\") = " + sdf.parse("0001-01-01T00:00:00.000Z"));
        System.out.println("sdf.parse(\"292278994-08-17T07:12:55.807Z\") = " + sdf.parse("292278994-08-17T07:12:55.807Z"));
    }
}

Produces the following output:

sdf.format(BEGINNING_OF_TIME) = 0001-01-01T00:00:00.000Z
sdf.format(END_OF_TIME) = 292278994-08-17T07:12:55.807Z
sdf.format(new Date()) = 2015-04-28T14:38:25.956Z
sdf.parse("2015-04-28T14:23:38.521Z") = Tue Apr 28 14:23:38 UTC 2015
sdf.parse("0001-01-01T00:00:00.000Z") = Sat Jan 01 00:00:00 UTC 1
sdf.parse("292278994-08-17T07:12:55.807Z") = Sun Aug 17 07:12:55 UTC 292278994
小傻瓜 2024-09-04 18:57:15

tl;dr

使用 java.time.Instant 类解析标准 ISO 8601 格式的文本,表示 UTC 中的某个时刻。

Instant.parse( "2010-10-02T12:23:23Z" )

ISO 8601

该格式由日期时间字符串格式的 ISO 8601 标准定义。

两者:

...默认使用 ISO 8601 格式来解析和生成字符串。

通常,您应该避免使用旧的 java.util.Date/.Calendar & java.text.SimpleDateFormat 类是出了名的麻烦、混乱且有缺陷。如果需要互操作,可以来回转换。

java.time

内置于 Java 8 及更高版本中,是新的 java.time 框架。灵感来自 Joda-Time,由 JSR 310,并由 三十额外项目。

Instant instant = Instant.parse( "2010-10-02T12:23:23Z" );  // `Instant` is always in UTC.

转换为旧类。

java.util.Date date = java.util.Date.from( instant );  // Pass an `Instant` to the `from` method.

时区

如果需要,您可以指定时区。

ZoneId zoneId = ZoneId.of( "America/Montreal" ); // Define a time zone rather than rely implicitly on JVM’s current default time zone.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );  // Assign a time zone adjustment from UTC.

转变。

java.util.Date date = java.util.Date.from( zdt.toInstant() );  // Extract an `Instant` from the `ZonedDateTime` to pass to the `from` method.

Joda-Time

更新:Joda-Time 项目现在处于维护模式。该团队建议迁移到 java.time 类。

这是 Joda-Time 2.8 中的一些示例代码。

org.joda.time.DateTime dateTime_Utc = new DateTime( "2010-10-02T12:23:23Z" , DateTimeZone.UTC );  // Specifying a time zone to apply, rather than implicitly assigning the JVM’s current default.

转换为旧类。请注意,分配的时区在转换过程中会丢失,因为 juDate 无法分配时区。

java.util.Date date = dateTime_Utc.toDate(); // The `toDate` method converts to old class.

时区

如果需要,您可以指定时区。

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTime_Montreal = dateTime_Utc.withZone ( zone );

日期表Java 中的 -time 类型,包括现代的和传统的。


关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧遗留日期时间类,例如java.util.Date日历,& SimpleDateFormat

Joda-Time 项目,现已在 维护模式,建议迁移到 java.time 类。

要了解更多信息,请参阅 Oracle 教程 。并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310

您可以直接与数据库交换java.time对象。使用符合 JDBC 驱动程序 jeps/170" rel="noreferrer">JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类。

从哪里获取 java.time 类?

其中的表格java.time 库与哪个版本的 Java 或 Android 一起使用。

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如 Interval YearWeek YearQuarter ,以及更多

tl;dr

Use java.time.Instant class to parse text in standard ISO 8601 format, representing a moment in UTC.

Instant.parse( "2010-10-02T12:23:23Z" )

ISO 8601

That format is defined by the ISO 8601 standard for date-time string formats.

Both:

…use ISO 8601 formats by default for parsing and generating strings.

You should generally avoid using the old java.util.Date/.Calendar & java.text.SimpleDateFormat classes as they are notoriously troublesome, confusing, and flawed. If required for interoperating, you can convert to and fro.

java.time

Built into Java 8 and later is the new java.time framework. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.

Instant instant = Instant.parse( "2010-10-02T12:23:23Z" );  // `Instant` is always in UTC.

Convert to the old class.

java.util.Date date = java.util.Date.from( instant );  // Pass an `Instant` to the `from` method.

Time Zone

If needed, you can assign a time zone.

ZoneId zoneId = ZoneId.of( "America/Montreal" ); // Define a time zone rather than rely implicitly on JVM’s current default time zone.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );  // Assign a time zone adjustment from UTC.

Convert.

java.util.Date date = java.util.Date.from( zdt.toInstant() );  // Extract an `Instant` from the `ZonedDateTime` to pass to the `from` method.

Joda-Time

UPDATE: The Joda-Time project is now in maintenance mode. The team advises migration to the java.time classes.

Here is some example code in Joda-Time 2.8.

org.joda.time.DateTime dateTime_Utc = new DateTime( "2010-10-02T12:23:23Z" , DateTimeZone.UTC );  // Specifying a time zone to apply, rather than implicitly assigning the JVM’s current default.

Convert to old class. Note that the assigned time zone is lost in conversion, as j.u.Date cannot be assigned a time zone.

java.util.Date date = dateTime_Utc.toDate(); // The `toDate` method converts to old class.

Time Zone

If needed, you can assign a time zone.

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTime_Montreal = dateTime_Utc.withZone ( zone );

Table of date-time types in Java, both modern and legacy.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

Table of which java.time library to use with which version of Java or Android.

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

探春 2024-09-04 18:57:15

您可以使用以下方法将字符串解析为时间戳:

public static void main(String[] args) {

    String timeStr = "2021-11-11T10:25:35+00:00";
    System.out.println(convertStringToTimestamp(timeStr));

}

static Timestamp convertStringToTimestamp(String dateAsString) {
    OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateAsString);
    final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
    return Optional.ofNullable(offsetDateTime.toString())
            .map(value -> LocalDateTime.parse(value, dateTimeFormatter))
            .map(Timestamp::valueOf)
            .orElse(null);
}

You can parse string to Timestamp with the following method:

public static void main(String[] args) {

    String timeStr = "2021-11-11T10:25:35+00:00";
    System.out.println(convertStringToTimestamp(timeStr));

}

static Timestamp convertStringToTimestamp(String dateAsString) {
    OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateAsString);
    final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
    return Optional.ofNullable(offsetDateTime.toString())
            .map(value -> LocalDateTime.parse(value, dateTimeFormatter))
            .map(Timestamp::valueOf)
            .orElse(null);
}
极度宠爱 2024-09-04 18:57:15

到目前为止,上面有两个答案,它们都很长(恕我直言,tl;dr太短了),所以我根据我开始使用新的java.time 库(适用于 Java 的其他答案中所述版本 8+)。 ISO 8601 设置了书写日期的标准方式:< code>YYYY-MM-DD 因此日期时间的格式仅如下(可以是 0、3、6 或 9 位数字表示毫秒)并且不需要格式化字符串:

import java.time.Instant;
public static void main(String[] args) {
    String date="2010-10-02T12:23:23Z";
    try {
        Instant myDate = Instant.parse(date);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

我不需要它,但作为获取年份是问题的代码,然后:
它比较棘手,不能直接从Instant完成,可以通过Calendar以问题的方式完成在 Java 中获取当前年份的整数值将 java.time 转换为 Calendar 但恕我直言,因为格式是固定子字符串,使用起来更简单:

myDate.toString().substring(0,4);

There are two answers above up-to-now and they are both long (and tl;dr too short IMHO), so I write summary from my experience starting to use new java.time library (applicable as noted in other answers to Java version 8+). ISO 8601 sets standard way to write dates: YYYY-MM-DD so the format of date-time is only as below (could be 0, 3, 6 or 9 digits for milliseconds) and no formatting string necessary:

import java.time.Instant;
public static void main(String[] args) {
    String date="2010-10-02T12:23:23Z";
    try {
        Instant myDate = Instant.parse(date);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

I did not need it, but as getting year is in code from the question, then:
it is trickier, cannot be done from Instant directly, can be done via Calendar in way of questions Get integer value of the current year in Java and Converting java.time to Calendar but IMHO as format is fixed substring is more simple to use:

myDate.toString().substring(0,4);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文