Java: DateTimeFormatter и синтаксический анализ подсетей [дубликат]

хорошо, есть новые возможности HTML5 для доступа к собственной камере устройства - «API-интерфейс getUserMedia»

ПРИМЕЧАНИЕ. HTML5 может обрабатывать захват фотографий с веб-страницы на устройствах Android (по крайней мере, в последних версиях, управляемый ОС Honeycomb, но он не может обрабатывать его на iPhone, но iOS 6).

30
задан calvinf 20 April 2016 в 00:03
поделиться

2 ответа

Ошибка - исправлено в 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» см. эту документацию :

Фракция: Выводит поле nano-of-second как долю секунды. Значение nano-of-second имеет девять цифр, поэтому количество букв шаблона составляет от 1 до 9. Если оно меньше 9, то значение nano-of-second усекается, и выводятся только самые значащие цифры. При синтаксическом анализе в строгом режиме количество проанализированных цифр должно соответствовать количеству букв шаблонов. При разборе в режиме смягчения количество проанализированных цифр должно быть не менее, чем число букв шаблонов, до 9 цифр.

Таким образом, мы видим, что S обозначает любую долю секунды (в том числе наносекунды), а не только миллисекунды. К сожалению, дробная часть в данный момент не очень хорошо воспринимается при смежном разборе значений.

EDIT:

В качестве фона здесь приведены некоторые замечания о смежном анализе значений. До тех пор, пока поля разделяются литералами, такими как десятичные точки или разделители временной части (двоеточие), интерпретация полей в анализируемом тексте не является сложной задачей, потому что синтаксический анализатор тогда легко знает, когда останавливаться, т.е. когда часть поля заканчивается и когда начинается следующее поле. Поэтому парсер JSR-310 может обрабатывать текстовую последовательность, если вы указываете десятичную точку.

Но если у вас есть последовательность смежных цифр, охватывающих несколько полей, возникают некоторые трудности с реализацией. Чтобы позволить парсеру знать, когда поле останавливается в тексте, необходимо заранее проинструктировать парсер, что данное поле представлено фиксированной шириной символов цифр. Это работает со всеми appendValue(...) -методами, которые принимают численные представления.

К сожалению, JSR-310 не сумел сделать это также с дробной частью (appendFraction(...)). Если вы ищете ключевое слово «смежное» в javadoc класса DateTimeFormatterBuilder, вы обнаружите, что эта функция ТОЛЬКО реализована с помощью методов appendValue(...). Обратите внимание, что спецификация для буквы шаблона S немного отличается, но внутренне делегирует appendFraction() -метод. Я предполагаю, что мы, по крайней мере, должны будем связываться до Java 9 (как сообщается в JDK-журнале ошибок или позже) до тех пор, пока фракционные части не смогут управлять парсингами смежных значений.


Update от 2015-11-25:

Следующий код с использованием двух цифр разряда не работает и выдает DateTimeParseException.

DateTimeFormatter dtf = 
  new DateTimeFormatterBuilder()
  .appendPattern("yyyyMMddHHmmssSS")
  .appendValue(ChronoField.MILLI_OF_SECOND, 2)
  .toFormatter();
String input = "2011120312345655"; 
LocalDateTime.parse(input, dtf); // abort

Обходной путь

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 мс вместо 550 мс).

То, что остается в качестве решения, либо ждет долгое время, дольше, чем 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.

28
ответ дан Basil Bourque 16 August 2018 в 11:53
поделиться

Вот алгоритм, который корректирует порядок конечных нулей, которые обычно возвращаются из форматированной даты String.

/**
 * Takes a Date and provides the format whilst compensating for the mistaken representation of sub-second values.
 * i.e. 2017-04-03-22:46:19.000991 -> 2017-04-03-22:46:19.991000
 * @param pDate Defines the Date object to format.
 * @param pPrecision Defines number of valid subsecond characters contained in the system's response.
 * */
private static final String subFormat(final Date pDate, final SimpleDateFormat pSimpleDateFormat, final int pPrecision) throws ParseException {
    // Format as usual.
    final String lString        = pSimpleDateFormat.format(pDate);
    // Count the number of characters.
    final String lPattern       = pSimpleDateFormat.toLocalizedPattern();
    // Find where the SubSeconds are.
    final int    lStart         = lPattern.indexOf('S');
    final int    lEnd           = lPattern.lastIndexOf('S');
    // Ensure they're in the expected format.
    for(int i = lStart; i <= lEnd; i++) { if(lPattern.charAt(i) != 'S') {
        // Throw an Exception; the date has been provided in the wrong format.
       throw new ParseException("Unable to process subseconds in the provided form. (" + lPattern + ").", i);
    } }
    // Calculate the number of Subseconds. (Account for zero indexing.)
    final int lNumSubSeconds = (lEnd - lStart) + 1;
    // Fetch the original quantity.
    String lReplaceString = lString.substring(lStart + (lNumSubSeconds - pPrecision), lStart + lNumSubSeconds);
    // Append trailing zeros.
    for(int i = 0; i < lNumSubSeconds - pPrecision; i++) { lReplaceString += "0"; }
    // Return the String.
    return lString.substring(0, lStart) + lReplaceString;
}
0
ответ дан Cawfree 16 August 2018 в 11:53
поделиться
  • 1
    Ответы на переполнение стека лучше, когда они включают обсуждение или объяснение. – Basil Bourque 4 April 2017 в 10:46
  • 2
    @BasilBourque Ты абсолютно прав. Я надеялся, что комментарии будут говорить сами за себя, но вы правы, что это, по крайней мере, заслуживает некоторого контекста. – Cawfree 4 April 2017 в 10:50
Другие вопросы по тегам:

Похожие вопросы: