Если я позвоню в свое приложение:
System.currentTimeMillis()
результат будет, скажем: 1536842771599, то есть: GMT: четверг, 13 сентября 2018 г. 12: 46: 11.599 PM ИЛИ в моем местном офисе: четверг, 13 сентября 2018 г. 3: 46: 11.599 PM GMT + 03: 00 DST
Если я сделаю следующий выбор в базе данных Oracle, установленной локально:
select CAST(sys_extract_utc(SYSTIMESTAMP) AS DATE) from dual;
Я получаю через следующий код JdbcTemplate:
jdbc.queryForObject(sqlCommand, new Object[0], Timestamp.class);
следующий результат:
Что, на мой взгляд, уже неверно, потому что Timestamp обычно представляет собой локализованное время. Кроме того, если я позвоню:
myResult.getTime()
чтобы получить длинную стоимость, это изменит мое время, которое было около 12.46 вечера, до значения 1536831971599, что на самом деле: GMT: четверг, 13 сентября 2018 года, 9: 46: 11.599.
Очевидно, что это плохо, потому что за моим фактическим местным временем это 2 * GMT + 03: 00 (6 часов), а GMT + 03: 00 (3 часа) за временем UTC базы данных.
Что я делаю неправильно? Мой единственный вывод до сих пор заключается в том, чтобы избежать использования sys_extract_utc в базе данных и позволить базе данных вернуть мне локальное время, которое будет преобразовано в UTC, когда я вызову getTime в экземпляре Timestamp.
Любое объяснение этому?
PS Основа на ответе, что java.sql.Timestamp - это UTC, я добавляю скриншот того, что показывает отладчик, и что неправильно, потому что он считает, что результат UTC - GMT + 03: 00. Таким образом, это показывает мое время как 8.26 + 03:00. Мое время - 11.26. Если я вызову getTime в этом экземпляре Timestamp, я получу длинное значение, которое, если я положу https://www.epochconverter.com/, тогда я получу пятницу, 14 сентября 2018 г. 8:26:06 GMT + 03: 00 DST или пятница, 14 сентября 2018 года 5:26:06, что составляет ровно 3 часа позади того, что у меня на самом деле есть как UTC!
PS2 Я использую Spring JDBC 4.2.5-RELEASE. Невозможно использовать Instant с ним, он выдает исключение, которое не может преобразовать Timestamp в Instant, потому что оно ожидает что-то, что происходит от Number. К сожалению, я не могу изменить этот JDBC, даже версия.
Вы не понимаете класс java.sql.Timestamp
.
java.sql.Timestamp
всегда представляет момент в UTC.java.time.Instant
лет назад заменил Timestamp
. Используйте только Instant
, никогда не Timestamp
.
Instant
Страшный класс java.sql.Timestamp
теперь устарел с помощью классов java.time, в частности Instant
.
Instant.now() // Capture the current moment in UTC.
Начиная с JDBC 4.2, мы можем напрямую обменивать объекты java.time с базой данных. Не нужно снова использовать ужасные классы Date
, Calendar
или java.sql.
Загрузить.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Вставить.
myPreparedStatement.setObject( … , instant ) ;
Временная метка обычно представляет собой локализованное время.
Неправильно. java.sql.Timestamp
представляет момент в UTC, всегда UTC, по определению. Аналогично, Instant
также представляет момент в UTC. Оба класса представляют собой счет с первого момента 1970 года в UTC.
Рамка java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют неприятные старые устаревшие классы времени, такие как java.util.Date
, Calendar
и SimpleDateFormat
.
Проект Joda-Time, теперь в режиме обслуживания, советует перейти на классы java.time.
Чтобы узнать больше, ознакомьтесь с учебным пособием Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация - JSR 310.
Вы можете обменивать объекты java.time непосредственно с вашей базой данных. Используйте JDBC-драйвер, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*
.
Где можно получить классы java.time?
Проект ThreeTen-Extra расширяет java.time с дополнительными классами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval
, YearWeek
, YearQuarter
и другие.