Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
 JDBC (Postgres) & java.time.ZonedDateTime  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 8202
Столкнулся с бизнес задачей, где нам важен часовой пояс при дате. Можно, конечно, обойтись и без часового пояса, но это будет _жутко_ _коряво_ и не удобно.

В БД есть тип "timestamp with timezone", в Java 1.8 есть java,time.ZonedDateTime

Как записать java.time.ZonedDateTime в БД я разобрался, но как его прочитать? Декомпилировал классы от JDBC PostgreSQL и никаких методов кроме getTimestamp не нашел. Т.ч. риторический вопрос: Неужели все так плохо и Java такое г...?

Пока решил хранить все данные в виде даты + текст в ISO формате. При записи в БД пишу в два поля, при чтении из БД использую поле текст в ISO формате. Но как-то это кривовато выглядит.
30 ноя 15, 13:28    [18491781]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Alexander A. Sak
Member

Откуда: Омск
Сообщений: 1051
Конечно джава - г...
Можно пример того, что требуется, на не-г...? Я, честно говоря, не совсем понял задачу. Обычно даты без таймзоны не бывает. Если и бывает, то на самом деле неявно используется какая-то одна: UTC, локальная или еще какая-то фиксированная.
30 ноя 15, 14:30    [18492228]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
Leonid Kudryavtsev,

ResultSet.getDate() не работает разве?
30 ноя 15, 14:38    [18492284]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Leonid Kudryavtsev,
https://www.sql.ru/forum/afsearch.aspx?s=alter session set time_zone&submit=?????&bid=38
?
30 ноя 15, 14:51    [18492397]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 8202
Blazkowicz
ResultSet.getDate() не работает разве?


Там есть TimeZone ?

Мне нужно Date + TimeZone как оно было в ОРИГИНАЛЕ. Единственный класс, который вроде такое позволяет хранить без извращений, java.time.ZonedDateTime. При записи в БД, я могу "разделить" его на Timestamp (или DateTime) + Calendar и соответственно записать в БД (сохранив Timezone)

getDate, AFAIK (могу ошибаться) возвращает мне дату с текущей/системной TimeZone/Calendar или позволяет указать TimeZone/Calendar который я "хочу" использовать. Но мне нужна та TimeZone/Calendar которая сохранена в БД.

Беда в том, что не понятно, можно ли сохраненный TimeZone считать обратно. Точнее, понимаю, что ответ нет.

Это действительно настолько редкая потребность/желание хранить и обрабатывать даты ВМЕСТЕ с TimeZone с которыми они пришли? В БД поля такого типа есть (timestamp with timezone), а JDBC получается их обрабатывать вообще не умеет (((

+

Если говорить о PostgreSQL, то текущее драйвера () вроде (???) читают все даты через класс org.postgresql.jdbc2.TimestampUtils, через ниже приведенный код. Где видно, что если параметр TimeZone не указан, то он берется не из БД, как бы хотелось, а просто getDefaultTz() - что IMHO есть полное У.Г.:

    public Date convertToDate(long millis, TimeZone tz)
    {
        if(millis <= 0x8000000001556d80L || millis >= 0x7ffffffffe3cb580L)
            return new Date(millis);
        if(tz == null)
            tz = getDefaultTz();
        if(isSimpleTimeZone(tz.getID()))
        {
            int offset = tz.getRawOffset();
            millis += offset;
            millis = (millis / 0x5265c00L) * 0x5265c00L;
            millis -= offset;
            return new Date(millis);
        } else
        {
            Calendar cal = calendarWithUserTz;
            cal.setTimeZone(tz);
            cal.setTimeInMillis(millis);
            cal.set(11, 0);
            cal.set(12, 0);
            cal.set(13, 0);
            cal.set(14, 0);
            return new Date(cal.getTimeInMillis());
        }
    }



+

Если говорить о PostgreSQL, то даже PgAdmin мне сохраненные данные показывает приведенные к моей TimeZone (MSK +3), но в БД данные правильные (смотрел дампом команды copy) (((.
30 ноя 15, 16:49    [18493319]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
ivanra
Member

Откуда:
Сообщений: 878
Leonid Kudryavtsev,
postgre sql не хранит сведения о таймзоне, тип timestamp with timezone влияет только на работу с литералами.
В самой же базе всё хранится в utc (можно сказать, абсолютное значение времени), поэтому, если в java работа с базой реализована правильно, то все равно, какой timestamp в поле.
Вам же надо получить не значение времени, а его местное представление, для чего служит объект java.util.Calendar.
Calendar cln;
cln = Calendar.getInstance().setTime(resultset.getTimestamp()); // на клиенте
// или
cln = new GregorianCalendar(timezone).setTime(resultset.getTimestamp()); // на сервере

еще есть такой вариант
cln = Calendar.getInstance(timezone).setTime(resultset.getTimestamp());
, но это, по большому счету, неправильно, хотя результат будет аналогичен приведенному выше варианту для сервера
30 ноя 15, 16:59    [18493390]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 8202
ivanra
postgre sql не хранит сведения о таймзоне, тип timestamp with timezone влияет только на работу с литералами.

Неправда ваша. Достаточно сделать дамп таблицы через COPY, что бы увидит, что все замечательно сохраняется.


ivanra
а его местное представление, для чего служит объект java.util.Calendar.


Я хочу его местное представление, в том виде, как оно БЫЛО у пользователя в момент сохранения в БД. Пользователь за время между сохранением и просмотром мог уже 100 раз успеть в другую точку мира перелететь. Мне же хочется, время хранить в том виде "как было".

Пока, наверное, придется хранить в тексте. Т.к. работа с новым (с 1.8) типом java.time.ZonedDateTime в java.sql похоже пока не поддерживает (((. Чуть меньше, чем полностью ((( Что лично меня расстроило (((
30 ноя 15, 17:15    [18493446]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Leonid Kudryavtsev,
там ссылка была.
Тайм зона зависит от сессии. И работают совместно не только при записи, но и при чтении
alter session set time_zone
30 ноя 15, 18:01    [18493639]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
ivanra
Member

Откуда:
Сообщений: 878
Postgre SQL не хранит и не умеет извлекать исходную таймзону из timestamp поля. Всё зависит от настроек сервера/сессии. Так что в любом случае, надо либо сохранять локальное время, либо таймзону в виде строки, в отдельное поле
30 ноя 15, 18:06    [18493667]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Alexander A. Sak
Member

Откуда: Омск
Сообщений: 1051
Leonid Kudryavtsev
ivanra
postgre sql не хранит сведения о таймзоне, тип timestamp with timezone влияет только на работу с литералами.

Неправда ваша. Достаточно сделать дамп таблицы через COPY, что бы увидит, что все замечательно сохраняется.


ivanra
а его местное представление, для чего служит объект java.util.Calendar.


Я хочу его местное представление, в том виде, как оно БЫЛО у пользователя в момент сохранения в БД. Пользователь за время между сохранением и просмотром мог уже 100 раз успеть в другую точку мира перелететь. Мне же хочется, время хранить в том виде "как было".

Пока, наверное, придется хранить в тексте. Т.к. работа с новым (с 1.8) типом java.time.ZonedDateTime в java.sql похоже пока не поддерживает (((. Чуть меньше, чем полностью ((( Что лично меня расстроило (((


Какой версией PG пользуетесь? У меня 9.3.10

postgres=# create table www (tz timestamp with time zone);
CREATE TABLE
postgres=# insert into www values(current_timestamp);
INSERT 0 1
postgres=# set timezone TO 'UTC';
SET
postgres=# insert into www values(current_timestamp);
INSERT 0 1
postgres=# copy www to stdout;
2015-11-30 15:21:09.001305+00
2015-11-30 15:21:21.656228+00
postgres=# set timezone TO 'Asia/Omsk';
SET
postgres=# copy www to stdout;
2015-11-30 21:21:09.001305+06
2015-11-30 21:21:21.656228+06
postgres=# 

Что-то не замечаю, что "замечательно сохраняется".
30 ноя 15, 18:24    [18493738]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 8202
Alexander A. Sak
Что-то не замечаю, что "замечательно сохраняется".

Да, не прав ((( не туда посмотрел. Извиняюсь.

Значит вообще в жизни счастья нет (((
30 ноя 15, 19:29    [18494095]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 8202
Alexander A. Sak,

Спасибо. По крайне мере не буду городить в БД падеж типов, а тупо все в timestamp (для возможно последующей сортировки) + копия в text. Раз что timestamp, что timestamp with timezone одно и то же (((
30 ноя 15, 19:36    [18494124]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Nebo
Member

Откуда:
Сообщений: 2793
Leonid Kudryavtsev,

http://www.joda.org/joda-time/userguide.html
30 ноя 15, 20:09    [18494264]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
pavel_nv
Member

Откуда: NV -> SpB
Сообщений: 261
Leonid Kudryavtsev,

Так может быть проще сделать что пользователь указывает свою тайм зону у себя в настройках? Ведь если пользователь перелетел в другой часовой пояс и он хочет видеть время в старом поясе, то и вводить время лучше в этом же поясе.
Хранить timestamp, а при выводе и вводе информации - учитывать заданный пояс.

Timestamp date = rs.getTimestamp(...);
LocalDateTime ldt = date.toLocalDateTime();
ZonedDateTime zdt = ldt.atZone(user.getZoneId());
1 дек 15, 07:59    [18495073]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
ivanra
Member

Откуда:
Сообщений: 878
По идее, совместное хранение в одном поле времени и таймзоны противоречит требованиям 1-й нормальной формы. Так что в стандарте sql, а значит и в jdbc api такого не будет.
Хотя, не исключено, что какие-то сервера поддерживают такую экзотику
1 дек 15, 09:27    [18495306]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
ivanra
По идее, совместное хранение в одном поле времени и таймзоны противоречит требованиям 1-й нормальной формы.

нет. Нормальные формы для выделения сущностей при проектировании.
Тут простой тип поля напр. в оракле
  CREATE TABLE TTT  
  (ID NUMBER NOT NULL,  
  ....  
   DATE_REC TIMESTAMP(6) WITH LOCAL TIME ZONE DEFAULT (SYSTIMESTAMP) NOT NULL,  
   DATE_REC1 DATE  
  );
1 дек 15, 10:10    [18495542]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
ivanra
Member

Откуда:
Сообщений: 878
Petro123,
тогда уж правильнее TIMESTAMP WITH TIME ZONE, с LOCAL время просто нормализуется, и таймзона тоже не сохраняется.
Но в принципе, странный тип данных, поскольку в нем хранятся 2 значения (измерения). Вот как их сравнивать? В ORACLE сделали так:
Two TIMESTAMP WITH TIME ZONE values are considered identical if they represent the same instant in UTC, regardless of the TIME ZONE offsets stored in the data.
1 дек 15, 10:49    [18495766]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
Leonid Kudryavtsev
Blazkowicz
ResultSet.getDate() не работает разве?

Там есть TimeZone ?

Гоню. Он ведь просто трансформируется в текущую, а это не совсем то что надо. Тогда, возможно, действительно проще хранить строкой. Зависит от отго как оно вообще используется.
1 дек 15, 10:56    [18495817]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
ivanra,
ты прав наерно, я не вникал. У меня работодатель тоже фиксированно просит (по московскому времени смотрят).
Хотя ослик присылает в заголовках смещение.
1 дек 15, 11:04    [18495869]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
Leonid Kudryavtsev
В БД есть тип "timestamp with timezone"

Вроде, пишут, что этот тип не хранит часового пояса. Просто приводит к UTC, в то время как обычный - оставляет тот timestamp что ты прислал. То есть пояс вообще нигде не хранится. Тип влияет только на то есть ли смещения при записи и чтении.
1 дек 15, 11:10    [18495913]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Сергей Арсеньев
Member

Откуда:
Сообщений: 4113
ivanra,

Никакой идеи первой нормальной формы тут не нарушается, ибо требование атомарности, в нее не входит. Иначе хранить надо только биты - остальное не атомарно.

Требование 1 нормальной формы нарушалось бы, если б он в одном поле хранил две разные даты.

По сути вопроса, если СУБД не позволяет хранить дату с зоной в одном поле, храните все в UTC и рядом в поле TZ в которой был сделан ввод, если это так важно.
1 дек 15, 11:22    [18496004]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Blazkowicz,
ну, называется же "дата с таймзоной".
Вообще в оракле там дофига чего. Есть таймзона ораклаБД, есть свойство коннекта, есть тип поля....
аффтару!
http://stswoon.blogspot.ru/2014/02/time-zones.html
http://rsdn.ru/forum/db/6069403.hot
1 дек 15, 11:22    [18496012]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Leonid Kudryavtsev
Member

Откуда:
Сообщений: 8202
Всем спасибо.

Особого прояснения не наступило ))), но на досуге почитаю для общего развития.

Blazkowicz
Leonid Kudryavtsev
пропущено...

Там есть TimeZone ?

Гоню. Он ведь просто трансформируется в текущую, а это не совсем то что надо. Тогда, возможно, действительно проще хранить строкой. Зависит от отго как оно вообще используется.


Мне надо просто сохранить и извлечь. Текст подходит на 100%, но как человеку ранее работавшему с БД, подход "все в текст" не очень нравится.

Ну и с бизнес задачей, когда значим timezone сталкиваюсь в первый раз.

Сергей Арсеньев
...По сути вопроса, если СУБД не позволяет хранить дату с зоной в одном поле, храните все в UTC и рядом в поле TZ в которой был сделан ввод, если это так важно.


Для меня это криво. Т.к. для отладки/анализа тоже надо видеть "правильную дату" (с исходной таймзоной). UTC дата вообще даром не нужна, только для возможности корректного сравнения/сортировок.

Т.ч. "пока решил хранить все данные в виде даты + текст в ISO формате. При записи в БД пишу в два поля, при чтении из БД использую поле текст в ISO формате"
1 дек 15, 14:03    [18497315]     Ответить | Цитировать Сообщить модератору
 Re: JDBC (Postgres) & java.time.ZonedDateTime  [new]
Сергей Арсеньев
Member

Откуда:
Сообщений: 4113
Leonid Kudryavtsev
Ну и с бизнес задачей, когда значим timezone сталкиваюсь в первый раз.

Сергей Арсеньев
...По сути вопроса, если СУБД не позволяет хранить дату с зоной в одном поле, храните все в UTC и рядом в поле TZ в которой был сделан ввод, если это так важно.


Для меня это криво.

Криво наоборот. Если тебе нужна зона то и храни ее отдельно.
Таким образом тебе проще будет с ней оперировать и когда надо отображать время в единой шкале, а когда не надо в оригинальной. Да и сгруппировать пользователей по зонам будет проще. Но все зависит от задачи. Если же нужно только показывать оригинальное время - то строка.
2 дек 15, 10:35    [18501342]     Ответить | Цитировать Сообщить модератору
Все форумы / Java Ответить