带有冒号分隔符的时区的 Java SimpleDateFormat?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2375222/
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
Java SimpleDateFormat for time zone with a colon separator?
提问by Freiheit
I have a date in the following format: 2010-03-01T00:00:00-08:00
我有以下格式的日期: 2010-03-01T00:00:00-08:00
I have thrown the following SimpleDateFormats at it to parse it:
我在它上面抛出了以下 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
};
I have a convenience method that uses those formats like so:
我有一个使用这些格式的便捷方法,如下所示:
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;
}
It seems to hit on the pattern yyyyMMddHHmm
but returns the date as Thu Dec 03 00:01:00 PST 2009
.
它似乎符合模式,yyyyMMddHHmm
但将日期返回为Thu Dec 03 00:01:00 PST 2009
.
What is the correct pattern to parse this date?
解析此日期的正确模式是什么?
UPDATE: I don't NEED the time zone parsing. I don't anticipate having time sensitive issues moving between zones, but how would I get the "-08:00" zone format to parse????
更新:我不需要时区解析。我不希望在区域之间移动对时间敏感的问题,但是我将如何解析“-08:00”区域格式????
Unit test:
单元测试:
@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"));
}
Output from unit test:
单元测试的输出:
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
采纳答案by BalusC
JodaTime's DateTimeFormat
to rescue:
String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
DateTimeFormatter dtf = DateTimeFormat.forPattern(pattern);
DateTime dateTime = dtf.parseDateTime(dateString);
System.out.println(dateTime); // 2010-03-01T04:00:00.000-04:00
(time and timezone difference in toString()
is just because I'm at GMT-4 and didn't set locale explicitly)
(时间和时区差异toString()
只是因为我在 GMT-4 并且没有明确设置语言环境)
If you want to end up with java.util.Date
just use DateTime#toDate()
:
如果你想结束java.util.Date
只是使用DateTime#toDate()
:
Date date = dateTime.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 current SimpleDateFormat
indeed doesn't eat the colon in the timezone notation.
等待JDK7 ( JSR-310)JSR-310,如果您想在标准 Java SE API 中使用更好的格式化程序,则引用实现称为ThreeTen(希望它能够进入 Java 8)。当前SimpleDateFormat
确实不吃时区符号中的冒号。
Update: as per the update, you apparently don't need the timezone. This should work with SimpleDateFormat
. Just omit it (the Z
) in the pattern.
更新:根据更新,您显然不需要时区。这应该与SimpleDateFormat
. 只需Z
在模式中省略它 (the )。
String dateString = "2010-03-01T00:00:00-08:00";
String pattern = "yyyy-MM-dd'T'HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
Date date = sdf.parse(dateString);
System.out.println(date); // Mon Mar 01 00:00:00 BOT 2010
(which is correct as per my timezone)
(根据我的时区,这是正确的)
回答by trashgod
回答by acdcjunior
Here's a snippet I used - with plain SimpleDateFormat
. Hope somebody else may benefit from it:
这是我使用的一个片段 - 使用普通的SimpleDateFormat
. 希望其他人可以从中受益:
public static void main(String[] args) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") {
public StringBuffer format(Date date, StringBuffer toAppendTo, java.text.FieldPosition pos) {
StringBuffer toFix = super.format(date, toAppendTo, pos);
return toFix.insert(toFix.length()-2, ':');
};
};
// Usage:
System.out.println(dateFormat.format(new Date()));
}
Output:
输出:
- Usual Output.........: 2013-06-14T10:54:07-0200
- This snippet's Output: 2013-06-14T10:54:07-02:00
Or... better, use a simpler, different, pattern:
或者……更好的是,使用更简单、不同的模式:
SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
// Usage:
System.out.println(dateFormat2.format(new Date()));
Output:
输出:
- This pattern's output: 2013-06-14T10:54:07-02:00
See the docs for that.
请参阅文档。
回答by Bludwarf
Thanks acdcjuniorfor your solution. Here's a little optimized version for formatting and parsing:
感谢acdcjunior的解决方案。这是一个用于格式化和解析的优化版本:
public static final SimpleDateFormat XML_SDF = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.FRANCE)
{
private static final long serialVersionUID = -8275126788734707527L;
public StringBuffer format(Date date, StringBuffer toAppendTo, java.text.FieldPosition pos)
{
final StringBuffer buf = super.format(date, toAppendTo, pos);
buf.insert(buf.length() - 2, ':');
return buf;
};
public Date parse(String source) throws java.text.ParseException {
final int split = source.length() - 2;
return super.parse(source.substring(0, split - 1) + source.substring(split)); // replace ":" du TimeZone
};
};
回答by Rustam
Try this, its work for me:
试试这个,它对我有用:
Date date = javax.xml.bind.DatatypeConverter.parseDateTime("2013-06-01T12:45:01+04:00").getTime();
In Java 8:
在 Java 8 中:
OffsetDateTime dt = OffsetDateTime.parse("2010-03-01T00:00:00-08:00");
回答by YouEyeK
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.
如果您使用 java 7,则可以使用以下日期时间模式。早期版本的java似乎不支持这种模式。
String dateTimeString = "2010-03-01T00:00:00-08:00";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
Date date = df.parse(dateTimeString);
For More information refer to the SimpleDateFormat
documentation.
有关更多信息,请参阅SimpleDateFormat
文档。
回答by Willie Z
If you can use JDK 1.7 or higher, try this:
如果您可以使用 JDK 1.7 或更高版本,请尝试以下操作:
public class DateUtil {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
public static String format(Date date) {
return dateFormat.format(date);
}
public static Date parse(String dateString) throws AquariusException {
try {
return dateFormat.parse(dateString);
} catch (ParseException e) {
throw new AquariusException(e);
}
}
}
document: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.htmlwhich supports a new Time Zone format "XXX" (e.g. -3:00)
文档:https: //docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html支持新的时区格式“XXX”(例如 -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.
而 JDK 1.6 仅支持其他时区格式,即“z”(例如 NZST)、“zzzz”(例如新西兰标准时间)、“Z”(例如 +1200)等。
回答by Basil Bourque
tl;dr
tl;博士
OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" )
Details
细节
The answer by BalusCis correct, but now outdated as of Java 8.
BalusC的答案是正确的,但从 Java 8 开始已经过时了。
java.time
时间
The java.timeframework 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).
该java.time框架的继承者都乔达时库和与Java(java.util.Date/.Calendar&java.text.SimpleDateFormat中)的最早版本捆绑在一起的老麻烦的日期时间类。
ISO 8601
ISO 8601
Your input data string happens to comply with the ISO 8601standard.
您的输入数据字符串恰好符合ISO 8601标准。
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.
java.time 类在解析/生成日期时间值的文本表示时默认使用 ISO 8601 格式。所以不需要定义格式模式。
OffsetDateTime
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.
在OffsetDateTime
类表示调整到某些特定的时间线瞬间偏移从-UTC。在您的输入中,偏移量比 UTC 晚 8 小时,通常用于北美西海岸的大部分地区。
OffsetDateTime odt = OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" );
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 a LocalDate
if you insist.
您似乎只想要日期,在这种情况下使用LocalDate
该类。但请记住,您正在丢弃数据、(a) 时间和 (b) 时区。确实,如果没有时区的上下文,日期就没有意义。对于任何特定时刻,日期在世界各地都不同。例如,在巴黎午夜过后在蒙特利尔仍然是“昨天”。因此,虽然我建议坚持使用日期时间值,但LocalDate
如果您坚持,您可以轻松转换为 a 。
LocalDate localDate = odt.toLocalDate();
Time Zone
时区
If you know the intended time zone, apply it. A time zone is an offset plusthe rules to use for handling anomalies such as Daylight Saving Time (DST). Applying a ZoneId
gets us a ZonedDateTime
object.
如果您知道预期的时区,请应用它。时区是偏移量加上用于处理夏令时 (DST)等异常的规则。应用 aZoneId
给我们一个ZonedDateTime
对象。
ZoneId zoneId = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId );
Generating strings
生成字符串
To generate a string in ISO 8601 format, call toString
.
要生成 ISO 8601 格式的字符串,请调用toString
.
String output = odt.toString();
If you need strings in other formats, search Stack Overflow for use of the java.util.formatpackage.
如果您需要其他格式的字符串,请搜索 Stack Overflow 以使用java.util.format包。
Converting to java.util.Date
转换为 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 as java.util.Date.from
where you pass an Instant
. An Instant
is a moment on the timeline in UTC. We can extract an Instant
from our OffsetDateTime
.
最好避免java.util.Date
,但如果必须,您可以转换。调用添加到旧类的新方法,例如在java.util.Date.from
何处传递Instant
. AnInstant
是UTC时间线上的一个时刻。我们可以Instant
从我们的OffsetDateTime
.
java.util.Date utilDate = java.util.Date( odt.toInstant() );
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, Java SE 10, 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.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10及更高版本
- 内置。
- 具有捆绑实现的标准 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 Abhishek Oza
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 capital Z
s).
由于此处缺少Apache FastDateFormat 示例(单击以获取版本的文档:2.6和3.5),因此我为可能需要它的人添加了一个示例。这里的关键是模式ZZ
(2个大写Z
)。
import java.text.ParseException
import java.util.Date;
import org.apache.commons.lang3.time.FastDateFormat;
public class DateFormatTest throws ParseException {
public static void main(String[] args) {
String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
System.out.println("Date formatted into String:");
System.out.println(fastDateFormat.format(new Date()));
String stringFormattedDate = "2016-11-22T14:30:14+05:30";
System.out.println("String parsed into Date:");
System.out.println(fastDateFormat.parse(stringFormattedDate));
}
}
Here is the output of the code:
这是代码的输出:
Date formatted into String:
2016-11-22T14:52:17+05:30
String parsed into Date:
Tue Nov 22 14:30:14 IST 2016
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:
注意:以上代码来自 Apache Commons 的 lang3。该类org.apache.commons.lang.time.FastDateFormat
不支持解析,只支持格式化。例如,以下代码的输出:
import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.FastDateFormat;
public class DateFormatTest {
public static void main(String[] args) throws ParseException {
String stringDateFormat = "yyyy-MM-dd'T'HH:mm:ssZZ";
FastDateFormat fastDateFormat = FastDateFormat.getInstance(stringDateFormat);
System.out.println("Date formatted into String:");
System.out.println(fastDateFormat.format(new Date()));
String stringFormattedDate = "2016-11-22T14:30:14+05:30";
System.out.println("String parsed into Date:");
System.out.println(fastDateFormat.parseObject(stringFormattedDate));
}
}
will be this:
将是这样的:
Date formatted into String:
2016-11-22T14:55:56+05:30
String parsed into Date:
Exception in thread "main" java.text.ParseException: Format.parseObject(String) failed
at java.text.Format.parseObject(Format.java:228)
at DateFormatTest.main(DateFormatTest.java:12)
回答by bigspawn
You can use X in Java 7.
您可以在 Java 7 中使用 X。
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
static final SimpleDateFormat DATE_TIME_FORMAT =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
static final SimpleDateFormat JSON_DATE_TIME_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
private String stringDate = "2016-12-01 22:05:30";
private String requiredDate = "2016-12-01T22:05:30+03:00";
@Test
public void parseDateToBinBankFormat() throws ParseException {
Date date = DATE_TIME_FORMAT.parse(stringDate);
String jsonDate = JSON_DATE_TIME_FORMAT.format(date);
System.out.println(jsonDate);
Assert.assertEquals(jsonDate, requiredDate);
}