2015-07-07 4 views
0

Вот проблема, которую я пытаюсь решить: Чтение строки из базы данных А, преобразовать строку в объект Date, сохранить объект Date в базе данных B.Сохранения «фальшивая» метки времени в базу данных

EX) База данных A: читать строку даты «2015-03-08 02:00:00» из базы данных A, конвертировать в объект Date, хранить обратно в базу данных B.

Проблема здесь возникает из-за 2:00 утра является началом DST в центральное время США, поэтому объект Data преобразует 2:00 AM прямо в 3:00 AM, что означает, что 3:00 AM хранится в базе данных B.

Есть ли способ исправить это? Я не против использования Joda Time, если это необходимо.

Я пытаюсь сосредоточиться на вышеуказанную дату, 2015-03-08 02:00:00

Это код, я использую:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S"); 
    sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 
    String date = "2015-03-08 02:00:00.0"; 



    try 
    { 
     d = sdf.parse(date); 
     sdf.format(d); 

     //Insert into database here 
     // --- 
     // 
    } 
    catch (ParseException e) 
    { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
+0

Почему? Вы пытаетесь сохранить идею 2 AM в эту дату без учета какого-либо конкретного часового пояса? Примером этого может быть «Рождество начинается после инсульта в полночь 25 декабря», что означает, что всякий раз, когда полночь ударяет в любой часовой пояс. Позвольте мне сказать по-другому: какие базы данных вы используете и * точно * какие типы данных столбцов? –

+0

@BasilBourque Я читаю из DB оракула, выполняя процесс Java на недавно прочитанной информации и пытаясь сохранить его в базе данных Java в памяти. – Joshua

+0

И ваши * точные * типы данных столбцов даты и времени в обеих базах данных? –

ответ

1

У вас есть несколько вопросов, переплетающихся.

Вам не следует считывать строки из базы данных для значений даты и времени, вы должны читать объекты времени. Есть many Вопросы о StackOverflow о значениях даты и времени чтения/записи из/в базы данных, поэтому здесь не нужно повторять.

Если у вас есть строка, например, «2015-03-08 02:00:00», обратите внимание на отсутствие какого-либо индикатора часового пояса или смещения. Если вы хотите предположить, что строка представляет определенное по времени значение Центрального времени США, вы должны принять тот факт, что такой даты нет, потому что переход на летнее время (DST) определяет это как 3 часа ночи. При ударе в 2 часа метка времени переходит в 2 часа ночи. Поэтому нет смысла пытаться получить такое несуществующее время.

Использовать часовой пояс Имена

Большой наконечник для дата-время работы: Избегайте думать о часовых поясах, как «Central Time» и 3-4 буквенных кодов, таких как «ДКБ». Они не стандартизированы и не уникальны (много дубликатов), а также путают беспорядок, который является летним временем. Используйте proper time zone, в шаблоне «continent/majorCityOrRegion».

Local Date-Time

Возможно, что вы имеете в виду то, что мы называем "местное время", где дата-время не является специфической для какой-либо один часовой пояс. Например, «Рождество начинается в полночь 25 декабря 2015 года». Это означает другой момент в каждом конкретном часовом поясе. Рождественские рассветы ранее в Париже, чем Монреаль, например.

Joda времени

Давайте интерпретировать эту строку как LocalDateTime в Joda-Time. Во-первых, для удобства мы заменяем SPACE «Т», чтобы использовать встроенные парсеры Joda-Time для форматов ISO 8601.

String input = "2015-03-08 02:00:00"; 
String inputStandardized = input.replace(" ", "T"); // For convenience, convert input text to comply with ISO 8601 standard’s canonical format. Replace SPACE between date & time portions with "T". 

Далее мы проанализируем эту стандартизованную строку.

LocalDateTime localDateTime = LocalDateTime.parse(inputStandardized); 

Дамп для консоли.

System.out.println("inputStandardized: " + inputStandardized); 
System.out.println("localDateTime: " + localDateTime); 

При запуске.

inputStandardized: 2015-03-08T02:00:00 
localDateTime: 2015-03-08T02:00:00.000 

Эта локальная дата-время может храниться в базе данных SQL с помощью SQL typeTIMESTAMP WITHOUT TIME ZONE. Этот тип означает, что никакие корректировки в часовой пояс UTC не должны производиться в значениях базы данных (SELECT) или ввода (INSERT/UPDATE). См. Postgres doc для получения дополнительной информации об этих типах SQL.

зонного Date-Time

Если вы имели в виду, чтобы представить конкретный момент в определенном часовом поясе, такие как America/Chicago, когда нам необходимо назначить этот часовой пояс. Для таких значений времени-зоны в вашей базе данных вы должны использовать тип данных TIMESTAMP WITH TIME ZONE. Это имя типа вводит в заблуждение - это означает соблюдение часового пояса, так как он настраивает входящих данных в UTC. Исходный часовой пояс данных теряется.

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

Посмотрите сами ... Давайте добавим следующий код к приведенному выше примеру кода.

DateTimeZone zone = DateTimeZone.forID("America/Chicago"); 
DateTime dateTimeChicago = localDateTime.toDateTime(zone); // If the input lacks an offset, then Joda-Time *assigns* the value the specified time zone. If the input has an offset, Joda-Time *adjusts* the value to the specified zone. 

Дамп для консоли.

При запуске.

Exception in thread "main" org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-08T02:00:00.000 (America/Chicago 
… 

Похоже, что нет хорошего обобщенного обходного пути, просто хаки. В принципе, если вы ожидаете определенного часового пояса, вы сами корректируете настройку. См. Обсуждения, такие как this, this, this и the Joda-Time FAQ.

java.time

В Java 8, а затем, мы имеем новые рамки встроенной даты и времени в java.time package (Tutorial). Эта структура была вдохновлена ​​Joda-Time и имеет некоторые преимущества перед Joda-Time. Одним из таких преимуществ является обработка этой проблемы несуществующего значения DST.

String input = "2015-03-08 02:00:00"; 
String inputStandardized = input.replace(" ", "T"); 

LocalDateTime localDateTime = LocalDateTime.parse(inputStandardized); 

Давайте скорректируем это локальное время для назначения определенного часового пояса. Рамка java.time обнаруживает несуществующую дату-время и автоматически перемещает время вперед, чтобы уважать переход на летнее время.

ZoneId zone = ZoneId.of("America/Chicago"); 
ZonedDateTime zdt = ZonedDateTime.of(localDateTime, zone); 

Дамп для консоли.

System.out.println("inputStandardized: " + inputStandardized); 
System.out.println("localDateTime: " + localDateTime); 
System.out.println("zone: " + zone); 
System.out.println("zdt: " + zdt); 

При запуске.

inputStandardized: 2015-03-08T02:00:00 
localDateTime: 2015-03-08T02:00 
zone: America/Chicago 
zdt: 2015-03-08T03:00-05:00[America/Chicago] 

SQL

Как было сказано выше, вы можете искать StackOveflow для много информации о получении даты и времени в и из базы данных.

В идеале, с java.time, вы можете напрямую подать либо LocalDateTime, либо ZonedDateTime вашему драйверу JDBC. Но большинство драйверов еще не обновлены для обработки типов java.time. Пока ваш драйвер не будет обновлен, откиньтесь на java.sql.* classes. Удобные методы конвертации можно найти как в новых, так и в старых классах, связанных с Java.

java.sql.Timestamp ts = java.sql.Timestamp.valueOf(localDateTime); 

... или ...

Instant instant = zdt.toInstant(); 
java.sql.Timestamp ts = java.sql.Timestamp.from(instant); 
+0

Отличный ответ - особенно часть о java.time Java 8. –

0

Это, как правило, лучше хранить дата в миллисекундах с эпохи. Таким образом, вы можете использовать длинный, чтобы сохранить номер в своей базе данных, и когда вам нужно отформатировать дату, вы можете использовать конструктор DateTime(long) Joda Time или просто встроенный конструктор Date(long).

+0

Я бы не согласился. Если ваша база данных имеет типы данных даты, используйте их. Если ваше программирование имеет приличную фреймворк времени, используйте его. Попытка сделать работу с датой и временем отсчета с ошибкой подвержена ошибкам, трудно отлаживать и расстраивать. –

+0

Я думаю, что это действительно зависит от варианта использования, о котором мы не совсем уверены. OP требовала отметки времени и для сравнения между временами в разных часовых поясах, она не становится быстрее/проще, чем просто работать с целыми числами, и каждая используемая мной фреймворк дат поддерживает это как входной. Но опять же, это зависит от нескольких факторов: вам нужны даты до 1970 года, или, например, дата будет показана пользователю? Есть варианты использования для обоих, но вы, вероятно, правы, что высказывание «обычно лучше» может быть неправильным. –