Чтобы идти дальше, давайте разберемся как хранится дата и время в java и базе данных Oracle.
java.util.Date
Данный клас абсолютно не хранит никакой информации о временной зоне. Данные в нем представлены в виде количества миллисекунд с начала UNIX эпохи (January 1, 1970, 00:00:00 GMT). Кстати, GMT и UTC, если вы еще не запомнили, это одно и то же. Таким образом передача данного объекта между распределенными компонентами вполне удобна и безопасна, с точки зрения опасности потерять временную зону. Т.е. если вы хотите получить текущее время и передать куда-то, то смело вызывайте new Date(), передавайте объект куда угодно и не партесь по поводу временной зоны. Но помните, что метод toString() вернет вам представление даты со временем в локальной временной зоне. Поэтому для отображения или конструирования этого объекта используйте java.text.DateFormat (или скорее SimpleDateFormat), с выставленной временной зоной. Подробнее об этом немного ниже.java.util.Calendar.getInstance()
Данный объект помимо миллисекунд от UNIX эпохи хранит еще временную зону. По умолчанию - локальную. Для получения объекта определенной временной зоны используйте Calendar.getInstance(TimeZone.getTimeZone("UTC")). Но так как миллисекунды опять же хранятся в виде абсолютного значения от UNIX эпохи, то они как бы существуют независимо от временной зоны. Например, Calendar.getInstance(TimeZone.getTimeZone("MSD")).getTime() и Calendar.getInstance(TimeZone.getTimeZone("UTC")).getTime() вернут одинаковые объеты java.util.Date.java.sql.Timestamp
Как и java.util.Date он хранит количество миллисекунд начиная с UNIX эпохи. Кстати, будьте осторожны с java.sql.Date, потому что этот класс хранит округленное количество миллисекунд до целого количества дней в локальной временной зоне. Так что, если вы зачитаете из ResultSet этот тип данных, то окажетесь с датой без времени.Сохранение времени в базу данных Oracle
В оракл Timestamp хранится в виде набора чисел: год, месяц, день, час, минута, секунда, миллисекунд. Таким образом thin jdbc oracle driver при передачи и чтения даты нужно конвертировать миллисекунды в числовое представление, что он делает используя по умолчанию локальную временную зону. Чтобы попросить его сохранять все в UTC необходимо так же передавать Calendar.getInstance(TimeZone.getTimeZone("UTC")). Если же вы просто просматриваете данные в БД с помощью slqplus или какого-то визуального инструмента, то тут можно не парится - он всегда будет показывать то, что действительно лежит в базе данных, так как конвертировать внутренне представление в визуальное не нужно, ведь мы тоже читаем дату как год, месяц и т.д. Если вы используете хибернейт, то этот трюк уже реализован, надо только в мапинге указать поле специального кастомного типа.Таблицы аудита в БД с использованием триггеров.
Если в своем приложении вы используете таблицы аудитов, в которых хранятся все предыдущие данные, то будьте внимательны с их реализацией. Обычно это делается, с помощью триггеров. Кроме предыдущих данных обычно еще хранят время изменения. Данное время легко можно сгенерить на лету при помощи встроенной процедуры оракла:Но она вернет вам локальное текущее время. Если же вы хотите сохранить время в UTС, то нужно использовать
Логирование.
Если ваше приложение деплоится в различных временных зонах, то удобно писать логи в UTC, так как не надо будет мучится с переводом времени. Для этого в log4j можно использовать следующий паттерн.Правда в этом случае вам еще понадобиться дополнительный jar файл apache-log4j-extras.jar. К сожалению, стандартный org.apache.log4j.DailyRollingFileAppender appender будет продолжать роллить файлы все еще основываясь на локальной временной зоне. Хотя его конечно можно самому допилить напильником.
Форматирование
Для форматирования дат в java можно использовать стандартный java.text.DateFormat (java.text.SimpleDateFormat). Для того, чтобы все было как и везде в вашем приложение в UTC необходимо выставить временную зонуНо, будьте внимательны, SimpleDateFormat не threadsafe, поэтому исползовать статическую переменную без синхронизации нельзя. Как более эффективно форматировать дату в многопоточном приложении очень хоршо описано тут.
Кстати, GMT и UTC, если вы еще не запомнили, это одно и то же.
ОтветитьУдалитьНа самом деле разница есть: GMT переводиться на зимнее и летнее время, а UTC нет.
Леша, поправь тогда википедию, а то там написано, что GMT это то же самое, что и UTC, только неравномерное. Так же там написано, что летом британцы используют BST, вместо GMT. Не знаешь, зачем они это делают, если GMT тоже летом меняется?
Удалить