将日期字符串解析为 java.util.Date 时出现非法模式字符“T”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2597083/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Illegal pattern character 'T' when parsing a date string to java.util.Date
提问by hguser
I have a date string and I want to parse it to normal date use the java Date API,the following is my code:
我有一个日期字符串,我想使用 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();
}
}
However I got an exception: java.lang.IllegalArgumentException: Illegal pattern character 'T'
但是我有一个例外: 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:
顺便说一句,我试图在 T 的任一侧添加一个单引号字符:
String pattern="yyyy-MM-dd'T'hh:mm:ssZ";
It also does not work.
它也不起作用。
采纳答案by hguser
Update for Java 8 and higher
Java 8 及更高版本的更新
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.
您现在可以简单地做Instant.parse("2015-04-28T14:23:38.521Z")
并得到正确的东西,特别是因为您应该使用最新版本的 JavaInstant
而不是损坏java.util.Date
的。
You should be using DateTimeFormatter
instead of SimpleDateFormatter
as well.
你应该使用DateTimeFormatter
而不是SimpleDateFormatter
。
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.
下面的解释作为格式所代表的内容仍然有效。但它是在 Java 8 普及之前编写的,因此它使用了旧类,如果您使用的是 Java 8 或更高版本,则不应使用这些类。
This works with the input with the trailing Z
as demonstrated:
这适用于带有尾随的输入,Z
如下所示:
In the pattern the
T
is escaped with'
on either side.The pattern for the
Z
at the end is actuallyXXX
as documented in the JavaDoc forSimpleDateFormat
, it is just not very clear on actually how to use it sinceZ
is the marker for the oldTimeZone
information as well.
在模式中, 两边
T
都转义了'
。最后的模式
Z
实际上XXX
是在 JavaDoc for 中记录的SimpleDateFormat
,实际上如何使用它并不是很清楚,因为它Z
也是旧TimeZone
信息的标记 。
Q2597083.java
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
回答by Basil Bourque
tl;dr
tl;博士
Use java.time.Instant
class to parse text in standard ISO 8601 format, representing a moment in UTC.
使用java.time.Instant
class 解析标准 ISO 8601 格式的文本,表示 UTC 中的一个时刻。
Instant.parse( "2010-10-02T12:23:23Z" )
ISO 8601
ISO 8601
That format is defined by the ISO 8601standard for date-time string formats.
该格式由日期时间字符串格式的ISO 8601标准定义。
Both:
两个都:
- java.time frameworkbuilt into Java 8 and later (Tutorial)
- Joda-Timelibrary
- 内置于 Java 8 及更高版本中的java.time 框架(教程)
- Joda-Time库
…use ISO 8601 formats by default for parsing and generating strings.
...默认使用 ISO 8601 格式来解析和生成字符串。
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.util.Date/.Calendar 和 java.text.SimpleDateFormat 类,因为它们是出了名的麻烦、混乱和有缺陷。如果需要互操作,您可以来回转换。
java.time
时间
Built into Java 8 and later is the new java.timeframework. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extraproject.
Java 8 及更高版本中内置了新的java.time框架。受Joda-Time 的启发,由JSR 310定义,并由ThreeTen-Extra项目扩展。
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.timeclasses.
更新:Joda-Time 项目现在处于维护模式。该团队建议迁移到java.time类。
Here is some example code in Joda-Time 2.8.
这是 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.
转换为旧类。请注意,分配的时区在转换中丢失,因为无法为 juDate 分配时区。
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 );
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*
classes.
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9及更高版本
- 内置。
- 具有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- 更高版本的 Android 捆绑实现 java.time 类。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
The ThreeTen-Extraproject 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.
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by Alexei Martianov
There are two answers above up-to-now and they are both long (and tl;drtoo short IMHO), so I write summary from my experience starting to use new java.timelibrary (applicable as noted in other answers to Java version 8+). ISO 8601sets 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:
到目前为止,上面有两个答案,它们都很长(而且tl;dr太短恕我直言),所以我根据我开始使用新java.time库的经验写了总结(适用于 Java 版本的其他答案8+)。ISO 8601设置了写日期的标准方式: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();
}
}
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 Javaand Converting java.time to Calendarbut IMHO as format is fixed substring is more simple to use:
我不需要它,但是由于从问题的代码中获取年份,那么:
它更棘手,不能直接完成Instant
,可以通过Calendar
问题的方式完成获取当前年份的整数值在 Java 中并转换 java。日历的时间,但恕我直言,因为格式是固定的,子字符串使用起来更简单:
myDate.toString().substring(0,4);