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 2009
日Thu 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.from
。 Instant
是UTC时间线上的一个时刻。 我们可以从OffsetDateTime
提取Instant
OffsetDateTime
。
java.util.Date utilDate = java.util.Date( odt.toInstant() );
试试setLenient(false)
。
附录:它看起来像你正在识别各种格式的Date
string。 如果你必须进入,你可能会喜欢看这个扩展了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); } }