Java SimpleDateFormat 用于带有冒号分隔符的时区?
我有一个以下格式的日期: 2010-03-01T00:00:00-08:00
我已向其抛出以下 SimpleDateFormats 来解析它:
private static final SimpleDateFormat[] FORMATS = {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"), //ISO8601 long RFC822 zone
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"), //ISO8601 long long form zone
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"), //ignore timezone
new SimpleDateFormat("yyyyMMddHHmmssZ"), //ISO8601 short
new SimpleDateFormat("yyyyMMddHHmm"),
new SimpleDateFormat("yyyyMMdd"), //birthdate from NIST IHE C32 sample
new SimpleDateFormat("yyyyMM"),
new SimpleDateFormat("yyyy") //just the year
};
我有一个使用这些格式的便捷方法像这样:
public static Date figureOutTheDamnDate(String wtf) {
if (wtf == null) {
return null;
}
Date retval = null;
for (SimpleDateFormat sdf : FORMATS) {
try {
sdf.setLenient(false)
retval = sdf.parse(wtf);
System.out.println("Date:" + wtf + " hit on pattern:" + sdf.toPattern());
break;
} catch (ParseException ex) {
retval = null;
continue;
}
}
return retval;
}
它似乎符合模式yyyyMMddHHmm
,但返回日期为Thu Dec 03 00:01:00 PST 2009
。
解析该日期的正确模式是什么?
更新:我不需要时区解析。我预计在区域之间移动不会出现时间敏感问题,但是我如何获得“-08:00”区域格式进行解析???
单元测试:
@Test
public void test_date_parser() {
System.out.println("\ntest_date_parser");
//month is zero based, are you effing kidding me
Calendar d = new GregorianCalendar(2000, 3, 6, 13, 00, 00);
assertEquals(d.getTime(), MyClass.figureOutTheDamnDate("200004061300"));
assertEquals(new GregorianCalendar(1950, 0, 1).getTime(), MyClass.figureOutTheDamnDate("1950"));
assertEquals(new GregorianCalendar(1997, 0, 1).getTime(), MyClass.figureOutTheDamnDate("199701"));
assertEquals(new GregorianCalendar(2010, 1, 25, 15, 19, 44).getTime(), MyClass.figureOutTheDamnDate("20100225151944-0800"));
//my machine happens to be in GMT-0800
assertEquals(new GregorianCalendar(2010, 1, 15, 13, 15, 00).getTime(),MyClass.figureOutTheDamnDate("2010-02-15T13:15:00-05:00"));
assertEquals(new GregorianCalendar(2010, 1, 15, 18, 15, 00).getTime(), MyClass.figureOutTheDamnDate("2010-02-15T18:15:00-05:00"));
assertEquals(new GregorianCalendar(2010, 2, 1).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T00:00:00-08:00"));
assertEquals(new GregorianCalendar(2010, 2, 1, 17, 0, 0).getTime(), MyClass.figureOutTheDamnDate("2010-03-01T17:00:00-05:00"));
}
单元测试的输出:
test_date_parser
Date:200004061300 hit on pattern:yyyyMMddHHmm
Date:1950 hit on pattern:yyyy
Date:199701 hit on pattern:yyyyMM
Date:20100225151944-0800 hit on pattern:yyyyMMddHHmmssZ
Date:2010-02-15T13:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-02-15T18:15:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T00:00:00-08:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
Date:2010-03-01T17:00:00-05:00 hit on pattern:yyyy-MM-dd'T'HH:mm:ss
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
JodaTime 的
DateTimeFormat
来救援:(toString()
只是因为我在 GMT-4 并且没有显式设置区域设置)如果您想以
java.util.Date
结束,只需使用DateTime#toDate():
等待
JDK7 (JSR-310)JSR- 310,参考实现称为 ThreeTen (希望它能让如果您想在标准 Java SE API 中使用更好的格式化程序,请将其集成到 Java 8 中。当前的SimpleDateFormat
确实不会吃掉时区表示法中的冒号。更新:根据更新,您显然不需要时区。这应该与
SimpleDateFormat
一起使用。只需在模式中省略它(Z
)即可。(根据我的时区,这是正确的)
JodaTime's
DateTimeFormat
to rescue:(time and timezone difference in
toString()
is just because I'm at GMT-4 and didn't set locale explicitly)If you want to end up with
java.util.Date
just useDateTime#toDate()
:Wait for
JDK7 (JSR-310)JSR-310, the referrence implementation is called ThreeTen (hopefully it will make it into Java 8) if you want a better formatter in the standard Java SE API. The currentSimpleDateFormat
indeed doesn't eat the colon in the timezone notation.Update: as per the update, you apparently don't need the timezone. This should work with
SimpleDateFormat
. Just omit it (theZ
) in the pattern.(which is correct as per my timezone)
如果您使用 java 7,您可以使用以下日期时间模式。似乎早期版本的 java 不支持这种模式。
有关详细信息,请参阅
SimpleDateFormat
文档。if you used the java 7, you could have used the following Date Time Pattern. Seems like this pattern is not supported in the Earlier version of java.
For More information refer to the
SimpleDateFormat
documentation.这是我使用的一个片段 - 带有简单的
SimpleDateFormat
。希望其他人可以从中受益:输出:
或者...更好,使用更简单、不同的模式:
输出:
请参阅 相关文档。
Here's a snippet I used - with plain
SimpleDateFormat
. Hope somebody else may benefit from it:Output:
Or... better, use a simpler, different, pattern:
Output:
See the docs for that.
试试这个,它对我有用:
在 Java 8 中:
Try this, its work for me:
In Java 8:
如果您可以使用 JDK 1.7 或更高版本,请尝试以下操作:
document: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
它支持新的时区格式“XXX”(例如-3:00),
而JDK 1.6仅支持其他时区格式,即“z”(例如NZST)、“zzzz”(例如新西兰标准时间)、“ Z”(例如+1200)等
If you can use JDK 1.7 or higher, try this:
document: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
which supports a new Time Zone format "XXX" (e.g. -3:00)
While JDK 1.6 only support other formats for Time Zone, which are "z" (e.g. NZST), "zzzz" (e.g. New Zealand Standard Time), "Z" (e.g. +1200), etc.
tl;dr
详细信息
BalusC 的答案是正确的,但从 Java 8 开始已经过时了。
java.time
java.time 框架是两者的继承者Joda-Time 库和旧的麻烦的日期时间类与最早版本的 Java 捆绑在一起(java.util.Date/.Calendar 和 java.text.SimpleDateFormat)。
ISO 8601
您的输入数据字符串恰好符合 ISO 8601 标准。
在解析/生成日期时间值的文本表示形式时,java.time 类默认使用 ISO 8601 格式。所以不需要定义格式化模式。
OffsetDateTime
OffsetDateTime
类表示时间线上的某个时刻,调整为某个特定的 offset-from -UTC。在您的输入中,偏移量比 UTC 晚 8 小时,这在北美西海岸的大部分地区通常使用。您似乎只想要日期,在这种情况下使用
LocalDate
类。但请记住,您正在丢弃数据:(a) 时间和 (b) 时区。事实上,如果没有时区的背景,日期就没有意义。对于任何特定时刻,世界各地的日期都会有所不同。例如,巴黎午夜刚过,蒙特利尔仍然是“昨天”。因此,虽然我建议坚持使用日期时间值,但如果您坚持的话,也可以轻松转换为LocalDate
。时区
如果您知道所需的时区,请应用它。时区是一个偏移量加上用于处理异常的规则,例如日光节省时间(夏令时)。应用
ZoneId
为我们提供ZonedDateTime
对象。生成字符串
要生成 ISO 8601 格式的字符串,请调用
toString
。如果您需要其他格式的字符串,请搜索 Stack Overflow 以使用 java.util.format 包。
转换为
java.util.Date
最好避免
java.util.Date
,但如果必须的话,可以转换。调用添加到旧类的新方法,例如java.util.Date.from
您在其中传递Instant
。瞬间
是UTC时间线上的一个时刻。我们可以从OffsetDateTime
中提取一个Instant
。关于 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="nofollow noreferrer">JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类。
从哪里获取 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time 。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如
间隔
,YearWeek
,<代码>YearQuarter,以及更多 。tl;dr
Details
The answer by BalusC is correct, but now outdated as of Java 8.
java.time
The java.time framework is the successor to both Joda-Time library and the old troublesome date-time classes bundled with the earliest versions of Java (java.util.Date/.Calendar & java.text.SimpleDateFormat).
ISO 8601
Your input data string happens to comply with the ISO 8601 standard.
The java.time classes use ISO 8601 formats by default when parsing/generating textual representations of date-time values. So no need to define a formatting pattern.
OffsetDateTime
The
OffsetDateTime
class represents a moment on the time line adjusted to some particular offset-from-UTC. In your input, the offset is 8 hours behind UTC, commonly used on much of the west coast of North America.You seem to want the date-only, in which case use the
LocalDate
class. But keep in mind you are discarding data, (a) time-of-day, and (b) the time zone. Really, a date has no meaning without the context of a time zone. For any given moment the date varies around the world. For example, just after midnight in Paris is still “yesterday” in Montréal. So while I suggest sticking with date-time values, you can easily convert to aLocalDate
if you insist.Time Zone
If you know the intended time zone, apply it. A time zone is an offset plus the rules to use for handling anomalies such as Daylight Saving Time (DST). Applying a
ZoneId
gets us aZonedDateTime
object.Generating strings
To generate a string in ISO 8601 format, call
toString
.If you need strings in other formats, search Stack Overflow for use of the java.util.format package.
Converting to
java.util.Date
Best to avoid
java.util.Date
, but if you must, you can convert. Call the new methods added to the old classes such asjava.util.Date.from
where you pass anInstant
. AnInstant
is a moment on the timeline in UTC. We can extract anInstant
from ourOffsetDateTime
.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?
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.感谢acdcjunior提供的解决方案。这是格式化和解析的一个小优化版本:
Thanks acdcjunior for your solution. Here's a little optimized version for formatting and parsing :
您可以在 Java 7 中使用 X。
https:// docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
You can use X in Java 7.
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
尝试
setLenient(false)
。附录:看起来您正在识别各种格式的
Date
字符串。如果您必须输入,您可能需要查看这个示例扩展了InputVerifier
。Try
setLenient(false)
.Addendum: It looks like you're recognizing variously formatted
Date
strings. If you have to do entry, you might like looking at this example that extendsInputVerifier
.由于Apache FastDateFormat的示例(点击查看版本文档:2.6 和3.5) 这里缺失,我为那些可能需要它的人添加一个。这里的关键是模式
ZZ
(2 个大写的Z
)。下面是代码的输出:
注意:上面的代码是 Apache Commons 的 lang3 的。 org.apache.commons.lang.time.FastDateFormat 类不支持解析,仅支持格式化。例如,以下代码的输出
将是这样的:
Since an example of Apache FastDateFormat(click for the documentations of versions:2.6and3.5) is missing here, I am adding one for those who may need it. The key here is the pattern
ZZ
(2 capitalZ
s).Here is the output of the code:
Note: The above code is of Apache Commons' lang3. The class
org.apache.commons.lang.time.FastDateFormat
does not support parsing, and it supports only formatting. For example, the output of the following code:will be this:
如果日期字符串类似于 2018-07-20T12:18:29.802Z
用这个
If date string is like 2018-07-20T12:18:29.802Z
Use this