Java的SimpleDateFormat时区与冒号分隔符?

我有以下格式的date: 2010-03-01T00:00:00-08:00

我已经抛出了下面的SimpleDateFormats来parsing它:

 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但将date返回为Thu Dec 03 00:01:00 PST 2009Thu Dec 03 00:01:00 PST 2009

什么是parsing这个date的正确模式?

更新:我不需要时区parsing。 我不希望在区域之间移动时间敏感的问题,但我怎样才能得到“-08:00”区域格式来parsing?

unit testing:

 @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")); } 

unit testing输出:

 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 

JodaTime的DateTimeFormat拯救:

 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 

toString()时间和时区差异仅仅是因为我在GMT-4并且没有明确地设置区域设置)

如果你想结束使用java.util.Date只需使用DateTime#toDate()

 Date date = dateTime.toDate(); 

等待JDK7( JSR-310 ) JSR-310,如果你想要在标准的Java SE API中使用更好的格式化程序,那么这个引用实现被称为ThreeTen (希望它会成为Java 8)。 目前的SimpleDateFormat确实不会吃时区表示法中的冒号。

更新 :根据更新,你显然不需要时区。 这应该与SimpleDateFormat 。 只是省略它( Z )的模式。

 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 

(这是根据我的时区是正确的)

这里有一个我使用的代码片断 – 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())); } 

输出:

 - Usual Output.........: 2013-06-14T10:54:07-0200 - This snippet's Output: 2013-06-14T10:54:07-02:00 

如果你使用java 7,你可以使用下面的date时间模式。 好像这种模式在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); 

有关更多信息,请参阅SimpleDateFormat文档 。

试试这个,它对我的​​工作:

 Date date = javax.xml.bind.DatatypeConverter.parseDateTime("2013-06-01T12:45:01+04:00").getTime(); 

在Java 8中:

 OffsetDateTime dt = OffsetDateTime.parse("2010-03-01T00:00:00-08:00"); 

如果您可以使用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); } } } 

文档: https : //docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html支持新的时区格式“XXX”(例如-3:00)

虽然JDK 1.6只支持时区的其他格式,如“z”(例如NZST),“zzzz”(例如新西兰标准时间),“Z”(例如+1200)等。

感谢acdcjunior为您的解决scheme。 这里是格式化和parsing的一个小优化版本:

 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 }; }; 

BalusC的答案是正确的,但现在已经过时了Java 8。

java.time

java.time框架是Joda-Time库和Java最早版本(java.util.Date/.Calendar&java.text.SimpleDateFormat)绑定的旧麻烦date – 时间类的inheritance者。

ISO 8601

您的input数据string恰好符合ISO 8601标准。

在parsing/生成date时间值的文本表示时,java.time类默认使用ISO 8601格式。 所以不需要定义格式化模式。

OffsetDateTime

OffsetDateTime类表示时间线上的一个时刻,它被调整为某个特定的UTC偏移量 。 在你的input中,偏移量是UTC的8小时,通常在北美西海岸的大部分地区使用。

 OffsetDateTime odt = OffsetDateTime.parse( "2010-03-01T00:00:00-08:00" ); 

您似乎只想使用date,在这种情况下使用LocalDate类。 但请记住,您丢弃的数据,(一)时间,(二)时区。 真的, 如果没有时区的背景,date就没有意义了 。 对于任何特定的时刻,date在世界各地不同。 例如,在巴黎的午夜之后,在蒙特利尔还是“昨天”。 所以,当我build议坚持date时间值,你可以很容易地转换为LocalDate如果你坚持。

 LocalDate localDate = odt.toLocalDate(); 

时区

如果您知道预期的时区,请使用它。 时区是一个偏移量, 加上用于处理夏时制(DST)等exception的规则。 应用ZoneId让我们有一个ZonedDateTime对象。

 ZoneId zoneId = ZoneId.of( "America/Los_Angeles" ); ZonedDateTime zdt = odt.atZoneSameInstant( zoneId ); 

生成string

要以ISO 8601格式生成string,请调用toString

 String output = odt.toString(); 

如果您需要其他格式的string,请使用Stack Overflow来使用java.util.format包。

转换为java.util.Date

最好避免java.util.Date ,但是如果你必须的话,你可以转换。 调用添加到旧类的新方法,例如传递Instant java.util.Date.fromInstant是UTC时间线上的一个时刻。 我们可以从OffsetDateTime提取Instant OffsetDateTime

 java.util.Date utilDate = java.util.Date( odt.toInstant() ); 

试试setLenient(false)

附录:它看起来像你正在识别各种格式的Datestring。 如果你必须进入,你可能会喜欢看这个扩展了InputVerifier 例子 。

由于Apache FastDateFormat的一个例子(点击版本2.6和3.5的文档)在这里是缺less的,我为那些可能需要它的人添加了一个。 这里的关键是ZZ (2个大写ZZ 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)); } } 

这是代码的输出:

 Date formatted into String: 2016-11-22T14:52:17+05:30 String parsed into Date: Tue Nov 22 14:30:14 IST 2016 

注意:上面的代码是Apache Commons的lang3。 org.apache.commons.lang.time.FastDateFormat类不支持parsing,只支持格式化。 例如,以下代码的输出:

 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)); } } 

将是这样的:

 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) 

您可以在Java 7中使用X.

https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

 public class DateTest { public static final SimpleDateFormat JSON_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); private String date = "2016-12-01 22:05:30"; private String requireDate = "2016-12-01T22:05:30+03:00"; @Test public void parseDateToBinBankFormat() throws ParseException { String format = JSON_DATE_TIME_FORMAT.format(DATE_TIME_FORMAT.parse(date)); System.out.println(format); Assert.assertEquals(format, requireDate); } }