Грешка – коригирана в Java 9
Този проблем вече беше докладван в JDK-bug-log. Стивън Колборн споменава като заобиколно решение следното:
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 3)
.toFormatter();
Забележка: Това заобиколно решение не обхваща вашия случай на употреба само на два шаблона символа SS. Една корекция може да бъде само използването на други полета като MICRO_OF_SECOND (6 пъти SSSSSS) или NANO_OF_SECOND (9 пъти SSSSSSSSS). За две дробни цифри вижте моята актуализация по-долу.
@PeterLawrey За значението на шаблонен символ S вижте тази документация:
Фракция: Извежда полето нано-от секунда като част от секундата. Стойността на нано-от секундата има девет цифри, така че броят на буквите на модела е от 1 до 9. Ако е по-малко от 9, тогава стойността на нано-от секундата се съкращава, като се извеждат само най-значимите цифри. Когато анализирате в строг режим, броят на анализираните цифри трябва да съвпада с броя на буквите в шаблона. При синтаксичен анализ в снизходителен режим броят на анализираните цифри трябва да бъде най-малко броят на буквите на модела, до 9 цифри.
Така че виждаме, че S означава всяка част от секундата (включително наносекунда), а не само милисекунди. Освен това, за съжаление, дробната част в момента не се приема добре при анализиране на съседна стойност.
РЕДАКТИРАНЕ:
Като фон тук има някои забележки относно анализирането на съседни стойности. Докато полетата са разделени от литерали като десетична запетая или разделители на част от времето (двоеточие), интерпретацията на полетата в текст, който трябва да се анализира, не е трудна, тъй като след това анализаторът знае лесно кога да спре, т.е. когато частта от полето приключи и когато започне следващото поле. Следователно JSR-310 анализаторът може да обработи текстовата последователност, ако посочите десетична точка.
Но ако имате поредица от съседни цифри, обхващащи множество полета, тогава възникват някои трудности при изпълнението. За да уведомите анализатора, когато едно поле спира в текст, е необходимо предварително да инструктирате анализатора, че дадено поле е представено от цифри с фиксирана ширина. Това работи с всички appendValue(...)
-методи, които приемат числени представяния.
За съжаление JSR-310 не успя да направи това и с дробната част (appendFraction(...)
). Ако потърсите съседната ключова дума в javadoc на клас DateTimeFormatterBuilder
, ще откриете, че тази функция се реализира САМО от appendValue(...)
-методи. Обърнете внимание, че спецификацията за шаблонна буква S е малко по-различна, но вътрешно се делегира на appendFraction()
-method. Предполагам, че поне ще трябва да изчакаме до Java 9 (както е съобщено в JDK-bug-log или по-късно???), докато дробните части не могат да управляват и анализирането на съседни стойности.
Актуализация от 2015-11-25:
Следният код, използващ само две дробни цифри, не работи и тълкува неправилно частта от милисекунди:
DateTimeFormatter dtf =
new DateTimeFormatterBuilder()
.appendPattern("yyyyMMddHHmmss")
.appendValue(ChronoField.MILLI_OF_SECOND, 2)
.toFormatter();
String input = "2011120312345655";
LocalDateTime ldt = LocalDateTime.parse(input, dtf);
System.out.println(ldt); // 2011-12-03T12:34:56.055
Заобиколното решение
String input = "2011120312345655";
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSS");
Date d = sdf.parse(input);
System.out.println(d.toInstant()); // 2011-12-03T12:34:56.055Z
не работи, защото SimpleDateFormat
също интерпретира дробта по грешен начин, подобно на съвременния пример (вижте изхода, 55 ms вместо 550 ms).
Това, което остава като решение, е или да изчакате дълго време до Java 9 (или по-късно?), или да напишете свой собствен хак или да използвате библиотеки на трети страни като решение.
Решение, базирано на мръсен хак:
String input = "2011120312345655";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
int len = input.length();
LocalDateTime ldt = LocalDateTime.parse(input.substring(0, len - 2), dtf);
int millis = Integer.parseInt(input.substring(len - 2)) * 10;
ldt = ldt.plus(millis, ChronoUnit.MILLIS);
System.out.println(ldt); // 2011-12-03T12:34:56.550
Решение с помощта на Joda-Time:
String input = "2011120312345655";
DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyyMMddHHmmssSS");
System.out.println(dtf.parseLocalDateTime(input)); // 2011-12-03T12:34:56.550
Решение, използващо моята библиотека Time4J:
String input = "2011120312345655";
ChronoFormatter<PlainTimestamp> f =
ChronoFormatter.ofTimestampPattern("yyyyMMddHHmmssSS", PatternType.CLDR, Locale.ROOT);
System.out.println(f.parse(input)); // 2011-12-03T12:34:56.550
Актуализация от 2016-04-29:
Както хората могат да видят чрез JDK-проблема, споменат по-горе, той вече е маркиран като разрешен - за Java 9.
person
Meno Hochschild
schedule
24.03.2014
java-time
, няма да видятjava.time
и има ужасна комбинация от етикети на различни места, които използват един вместо друг. Ако смятате, че тагът с точката ще бъде по-полезен, тогава нека напълно заличим другия таг, за да премахнем неяснотата. - person Charles   schedule 25.03.2014