Шаблон даты Java для даты SQL (ISO 9075) - PullRequest
0 голосов
/ 23 ноября 2011

Я пытаюсь проанализировать строку даты SQL (ISO 9075), и вместо миллисекунд используются микросекунды (!), Например

2010-11-22 08:08:08.123456

Однако SimpleDateFormat отказывается распознавать шаблон типа "гггг-ММ-дд ЧЧ: мм: сс.СССССС "и" гггг-ММ-дд ЧЧ: мм: сс.ССС "тоже не работает.

Используемый код выглядит примерно так:

String dateString = "2010-11-22 08:08:08.123456";
String pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS";

try
{
    format = new SimpleDateFormat(pattern);
    format.setLenient(false);
    position.setIndex(0);
    Date date1 = format.parse(dateString, position);
    System.out.println("Date 1: " + date1);
    Date date2 = format.parse(dateString);
    System.out.println("Date 2: " + date1);
}
catch (Exception e) // Should not happen
{
    e.printStackTrace();
}

Какой бы из двух шаблонов («.SSS» или «.SSSSSS») я не использовал, date1 - это принтер как null, тогда как date2 вызывает исключение при разборе (java.text.ParseException: Unparseable date).

Ответы [ 6 ]

1 голос
/ 06 июля 2014

tl; dr

Вставка / обновление.

myPreparedStatement.setObject( 
    … , 
    Instant.parse( "2010-11-22 08:08:08.123456".replace( " " , "T" ) + "Z" ) 
) ;

Извлечение.

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
String output = ldt.toString().replace( "T" , " " ) ;  // Remove the standard ISO 8601 format’s use of `T` in the middle with the SQL-style SPACE.

java.time

Java 8 приносит новый пакет java.time , чтобы заменить печально известные старые классы java.util.Date, .Calendar и SimpleDateFormat.Эти старые унаследованные классы ограничены разрешением в миллисекундах, в то время как ваша входная строка имеет микросекунды.Вы не можете втиснуть шесть десятичных знаков в тип данных, ограниченный тремя.

Значения даты и времени в java.time имеют разрешение наносекунда , что более чем достаточно для вашегомикросекунд.Это означает, что до девять десятичных знаков в течение доли секунды.

В JDBC 4.2 и более поздних версиях используйте класс Instant напрямую.

Разбор входной строки.Для соответствия формату ISO 8601 , используемому по умолчанию в классах java.time, замените ПРОБЕЛ в середине на T.Ваш приведенный пример должен исходить из столбца типа TIMESTAMP WITHOUT TIME ZONE, что означает не определенный момент, не точку на временной шкале.

String input = "2010-11-22 08:08:08.123456".replace( " " , "T" ) ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;

И еслиэтот ввод должен был быть моментом в UTC, добавьте Z.Тогда у вас do есть момент, конкретная точка на временной шкале.Для использования с типом столбца TIMESTAMP WITH TIME ZONE.

String input = "2010-11-22 08:08:08.123456".replace( " " , "T" ) + "Z" ;
Instant instant = Instant.parse( input ) ;

Отправьте в свою базу данных.

myPreparedStatement.setObject( … , instant ) ;

… и…

Instant instant = myResultSet.getObject( … , Instant.class ) ;

О программе java.time

Фреймворк java.time встроен в Java 8 и более поздние версии.Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами непосредственно с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 и более поздних версий
    • Встроенный-в.
    • Часть стандартного Java API с встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации связки Android классов java.time.
    • Для более ранних версий Android проект ThreeTenABP адаптируется ThreeTen-Бэкпорт (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .


ОБНОВЛЕНИЕ: Проект Joda-Time теперь находится в режиме обслуживания , с командой, советующей перейти на классы java.time .Оставив этот раздел нетронутым, как историю.

Joda-Time

Как отмечалось выше, вам следует избегать использования классов java.util.Date, .Calendar и SimpleDateFormat.Начиная с Java 8 у вас есть выбор использования java.time или Joda-Time или обоих, поскольку у каждого из них есть свои сильные и слабые стороны.Joda-Time также работает в более ранних версиях Java.

Вы можете проанализировать эту строку, используя Joda-Time.

В качестве альтернативы, если у вас есть доступ к java.sql.Timestamp, который сгенерировал вашу строку, вы можете просто передать объект Timestamp в конструктор DateTime.Я предлагаю также передавать часовой пояс, поскольку объекты DateTime знают свой собственный назначенный часовой пояс.

DateTime dateTime = new DateTime( mySqlTimestamp, DateTimeZone.UTC );

или

DateTime dateTime = new DateTime( mySqlTimestamp, DateTimeZone.forID( "Europe/Paris" ) );

Joda-Time имеет разрешение миллисекунд.Таким образом, в любом случае, сгенерировав DateTime (разбор или прохождение), вы потеряете более мелкую долю секунды (игнорируется / усекается, не округляется).

1 голос
/ 23 ноября 2011

Может быть, вырезать оставшуюся часть дроби из dateString, прежде чем анализировать дату? У меня есть следующее

    String dateString = "2010-11-22 08:08:08.123456";
    String fraction = dateString.substring(dateString.length() - 3);
    String formatString = dateString.substring(0, dateString.length() - 3);
    String pattern = "yyyy-MM-dd HH:mm:ss.SSS";
    ParsePosition position = new ParsePosition(0);

    try
    {

        SimpleDateFormat format = new SimpleDateFormat(pattern);
        format.setLenient(false);
        position.setIndex(0);
        Date date1 = format.parse(formatString, position);          
        System.out.println("Date 1: " + date1);
        System.out.println("Date 1 fraction: " + fraction);
        Date date2 = format.parse(formatString);
        System.out.println("Date 2: " + date2);
        System.out.println("Date 2 fraction: " + fraction);
    }
    catch (Exception e) // Should not happen
    {
        e.printStackTrace();
    }

Это позволяет анализировать дату с точностью до миллисекунды, в то же время сохраняя микрочастицу дроби.

1 голос
/ 23 ноября 2011

Возможно, вы захотите вызвать синтаксический анализ DateFormat, потому что я думаю, что он обрезает строку.Попробуйте:

Date date1 = format.parse(dateString);

Плюс, не используйте "SSSSS".Согласно спецификациям, только «SSS» является допустимым для форматирования даты.

Кроме этого, я согласен с его обрезкой или синтаксическим анализом в SQL.

Плюс, вы установили false для параметра false, поэтомустроги.Таким образом, длинная строка приведет к ее провалу.Может быть, поэтому он возвращает ноль.Не уверен, придется проверять.

1 голос
/ 23 ноября 2011

Возможно, вы захотите взглянуть на DATE4J , который специально пытается работать с базой данных дат с точностью до наносекунды.

1 голос
/ 23 ноября 2011

Хм.Учитывая, что Date не имеет разрешения в микросекундах, , если , вы знаете, что все строки даты SQL имеют полные шесть цифр после десятичной точки в секундах (например, 2010-11-22 08:08:08.000000), почему бы просто не отрубитьпоследние три цифры и используйте SimpleDateFormat на остатке?

0 голосов
/ 23 ноября 2011

Если у вас есть контроль над датой SQL, которая является вводом в код Java, вы можете попытаться извлечь дату из SQL в формате, который будет работать («гггг-ММ-дд ЧЧ: мм: сс.ССС» ).

...