Получение смещения +/- часа из SQL datetimeoffset

Я пытаюсь проанализировать datetimeoffset. Это из столбца таблицы базы данных SQL Server, который был создан как datetimeoffset, длина = 10, точность = 34, масштаб = 7.

Пример из одной из записей: 2024-07-16 22:30:00.0000000 -04:00

В этом случае я хотел бы вернуть -4 часа, а также преобразовать его в местное время пользователя.

К сожалению, я не могу использовать для этого T-SQL. нравится (datename(tz, value)

У меня есть следующее:

import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) throws Exception {
        DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS z");

        //Date string with zone information
        //String dateString = "08/03/2019T16:20:17:717 UTC+05:30";
        String dateString = "2024-07-16 22:30:00.0000000 -04:00";

        //Instance with given zone
        ZonedDateTime zdtInstanceAtOffset = ZonedDateTime.parse(dateString, DATE_TIME_FORMATTER);

        //Instance in UTC
        ZonedDateTime zdtInstanceAtUTC = zdtInstanceAtOffset.withZoneSameInstant(ZoneOffset.UTC);

        //Formatting to string
        String dateStringInUTC = zdtInstanceAtUTC.format(DATE_TIME_FORMATTER);

        System.out.println("Hello world!");

        System.out.println(zdtInstanceAtOffset);
        System.out.println(zdtInstanceAtUTC);
        System.out.println(dateStringInUTC);

        //Convert ZonedDateTime to instant which is in UTC
        System.out.println(zdtInstanceAtOffset.toInstant());
    }
}

Я получаю эту ошибку:

Исключение в потоке "main" java.time.format.DateTimeParseException: текст '2024-09-17 00:00:00.0000000 -04:00' не удалось проанализировать по индексу 2

Какие-либо предложения?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш вопрос предполагает план. Предполагаемый план таков:

  • Давайте запросим у базы данных это значение времени смещения, но сначала попросим ее преобразовать его в строку.
  • Затем давайте возьмем эту строку из Java и проведем необычный анализ, чтобы преобразовать эту информацию о правом обратном смещении.
  • Этот второй шаг меня сбивает с толку, я задам ТАКОЙ вопрос.

Вы поступили неправильно. Вышеупомянутый план — плохой план. Следовательно, ваш вопрос неактуален. Это вопрос о части плохого плана.

Я также собираюсь предположить кое-что: что где-то в этой строке у вас есть resultSet.getTimestamp или что-то подобное (где resultSet — это экземпляр JDBC ResultSet), и вы обнаружили (правильно), что это значение проблематично.

Правильный план состоит в том, чтобы вместо этого сделать следующее:

OffsetDateTime odt = resultSet.getObject(colIdxOrName, OffsetDateTime.class);

И возьмите все необходимое из этого одта. Вы можете просто запросить смещение напрямую. Таким образом, преобразование строк не происходит вообще, вы не зависите от определений tzdata ни вашего механизма базы данных, ни вашего экземпляра JDK, а работа с API значительно улучшается.

ZoneOffset offset = odt.getOffset() ;

JDBC 4.2+ требует, чтобы драйверы JDBC поддерживали .getObject(colIdxOrName, OffsetDateTime.class) (наряду с ODT, а также Instant и LocalDate). Они верны, а getDate и getTimestamp неверны. Никогда не следует использовать getDate и getTimestamp, поскольку возвращаемые ими типы SQL расширяются java.util.Date, а j.u.Date не работает. В том смысле, что j.u.Date делает именно то, что говорит его спецификация, но его спецификация является чистым и абсолютным безумием. Начнем с того, что название — полная ложь; j.u.Date экземпляры явно не представляют даты. Они представляют мгновения; это старый API-эквивалент java.time.Instant. Вот почему все методы, связанные с датой (например, .getYear()), устарели.

Исправление состоит в том, чтобы никогда не использовать j.u.Date, что вы делаете, используя вместо этого соответствующие типы в java.time (есть причина, по которой Java поставляется с новым API даты/времени: потому что старый очень плохой, сломанный и, конечно, очень неожиданный) .

По... причинам у JDBC нет метода .getLocalDateTime() и никогда не будет. .getObject(X, LocalDateTime.class) это так. Официально. В обоих смыслах: базы данных должны поддерживать это, и JDBC считает, что это канонический способ получить LDT из базы данных (то же самое относится к ODT, Instant и LD). Наверное потому, что иначе количество .getX() методов никогда бы не закончилось.

100% согласен с вашим комментарием. Для тех, кто сталкивается с той же проблемой, но из вопроса «а как мне это сделать в базе данных?», подход тот же, если не подробности. В частности, используйте datepart(tzoffset, @yourValue), чтобы получить смещение напрямую, а не пытаться проанализировать его из строкового представления.

Ben Thul 12.07.2024 21:56

Это исходит из API. Я должен использовать API. Неуместные/бесполезные комментарии не нужны!

Kung Fu Ninja 13.07.2024 00:07
Ответ принят как подходящий

g00se опубликовал этот ответ в качестве комментария:

 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.n z");
        OffsetDateTime odt = OffsetDateTime.parse("2024-09-17 00:00:00.0000000 -04:00", dtf);

        System.out.println(odt);

        ZoneOffset o = odt.getOffset();
        System.out.printf("Offset is %s%n", o);

        OffsetDateTime odtLocal = odt.withOffsetSameInstant(ZonedDateTime.now().getOffset());

        System.out.printf("As local OffsetDateTime is %s%n", odtLocal);

Это работает отлично. Но мне, вероятно, не следует это поощрять, поскольку я не верю, что вас заставляют работать со строками.

Я рад, что вы сохранили мой комментарий, но публикация его в качестве ответа просто поощряет неправильный подход. Если вы хотите использовать мои комментарии в качестве ответов, хотя бы сделайте правильное форматирование;)

g00se 13.07.2024 11:50

Другие вопросы по теме