В веб-сервисе Java используется неверный часовой пояс - PullRequest
3 голосов
/ 01 октября 2009

У меня есть Java-веб-сервис JAX-B, который я использую для обновления базы данных. Каждая строка в таблице, которую я обновляю, представлена ​​объектом, подобным приведенному ниже: -

public class Item {
    private String id;
    private Date startDate;
    private Date endDate;

    public Item() { }

    ...

}

Этот класс создается в отдельной программе, а затем передается через SOAP в сообщении, аналогичном приведенному ниже: -

...

<item>
    <id>D001IAAC030</id>
    <startDate>2009-09-17T00:00:00.000+01:00</startDate>
    <endDate>2009-10-01T00:00:00.000+01:00</endDate>
</item>

...

Как видите, из-за BST время UTC имеет смещение +01: 00. Однако, когда объект маршалируется на сервере (который также находится на моем локальном компьютере), он возвращается к GMT и вычитает 1 час из дат.

Можете ли вы сказать мне, как я могу: -

  1. Установите для моего сервера Glassfish правильную локаль, чтобы даты распознавались как BST.
  2. Скажите, как я могу перехватить сортировку на конце веб-службы, чтобы я мог сам установить часовой пояс до того, как будет установлена ​​дата.

ТИА

Урф

Ответы [ 4 ]

5 голосов
/ 02 октября 2009

Вам просто нужно помнить, что объект Date (всегда) хранит дату / время в миллисекундах с начала эпохи в часовом поясе UTC / GMT. Что удивляет, так это то, что метод Date.toString () возвращает текстовое представление в часовом поясе JVM по умолчанию (через внутренний объект Calendar). (Взгляните на исходный код JDK.)

Так, например, на моей машине

Date now = new Date();
System.out.println(now.toString());
System.out.println(now.getTime())

даст

Fri Oct 02 06:56:24 EST 2009
1254430584531

Число миллисекунд, являющееся фактическими миллисекундами с момента времени в часовом поясе GMT ​​/ UTC.

Вы должны всегда использовать форматеры даты или экземпляры календаря при манипулировании / использовании объектов даты. Например:

Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:MM:ss zzz yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(now.toString());
System.out.println(sdf.format(now));

дает

Fri Oct 02 06:56:24 EST 2009
Thu Oct 01 20:56:24 UTC 2009

В итоге: всегда обрабатывайте объект Date только как данные, миллисекунды с начала эпохи. (Не используйте ни один из устаревших методов и не используйте toString (), если вы не понимаете, что он отображает.) Для отображения, форматирования, преобразования (добавления времени вычитания и т. Д.) Всегда используйте экземпляр Calendar или DateFormat реализация и трудно ошибиться.

Как говорит Javadoc для даты:

'До JDK 1.1 класс Date имел две дополнительные функции. Это позволило интерпретировать даты как значения года, месяца, дня, часа, минуты и секунды. Это также позволило форматировать и анализировать строки даты. К сожалению, API для этих функций не поддается интернационализации. Начиная с JDK 1.1, класс Calendar должен использоваться для преобразования полей даты и времени, а класс DateFormat должен использоваться для форматирования и анализа строк даты. Соответствующие методы в Date устарели. '

Поэкспериментируйте с датами, календарями и форматерами и прочитайте Javadoc, и это станет немного понятнее.

Для первой части вашего вопроса вам не нужно устанавливать часовой пояс вашего сервера Glassfish для размещения ваших данных. Если вы хотите сохранить данные часового пояса со своими значениями данных / времени, используйте Календарь, а не дату в ваших объектах. Или, как я обычно делаю, все хранится как время UTC (в экземплярах db и Date в объектах), а часовые пояса используются только тогда, когда данные отображаются / выводятся или анализируются. Поэтому, когда ваши данные получены, проанализируйте их с помощью DateFormat или эквивалента с часовым поясом, установленным на +01: 00 (он может выбрать это из строки времени автоматически, если к нему прикреплен часовой пояс, как показано в примере).

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

4 голосов
/ 09 мая 2014

Чтобы изменить время, использованное UTC на сервере Glassfish:

C: \ glassfish4 \ GlassFish \ Bin)

asadmin create-jvm-options -Duser.timezone=UTC
asadmin restart-domain
2 голосов
/ 28 августа 2013

Я решил свою проблему прямо сейчас и с целью помочь другим разработчикам, следуйте шаг за шагом

наберите в вашей стеклянной рыбе

c: \ glassfish3 \ bin \> asadmin list-jvm-options

посмотреть, появится ли список

<jvm-options>-Duser.timezone=UTC</jvm-options>

регистр не появляется, перейдите в файл domain.xml, найдите jvm-options и добавьте командную строку

<jvm-options>-Duser.timezone = Brazil / East </ jvm-options> substituting the Brazil / East timezone by country

затем перезагрузите сервер и будьте счастливы

1 голос
/ 10 июля 2016

Locale не имеет значения

Locale не имеет ничего общего с часовым поясом. Для работы с датой и временем Locale определяет две вещи: (а) человеческий язык, используемый при переводе названия дня, названия месяца и т. Д., И (б) культурные нормы для таких вопросов, как период против запятой, упорядочение элементы (месяц до / после даты и т. д.).

Не изменять часовой пояс по умолчанию

Не изменяйте текущий часовой пояс по умолчанию JVM, как предложено для другого ответа. Изменение влияет на весь код во всех потоках всех приложений в этой JVM и делает это немедленно во время выполнения .

java.time

Вы используете старые устаревшие классы. Старые классы даты и времени, включенные в ранние версии Java, оказались плохо спроектированными, запутанными и хлопотными. Избежать их. Теперь вытесняется инфраструктурой java.time , встроенной в Java 8 и более поздние версии. Эти классы вытесняют старые проблемные классы даты и времени, такие как java.util.Date. См. Oracle Tutorial . Большая часть функциональности была перенесена в Java 6 & 7 в ThreeTen-Backport и дополнительно адаптирована для Android в ThreeTenABP .

ISO 8601

Ваши строки даты и времени соответствуют стандарту ISO 8601 . Эти форматы, определенные этим стандартом, используются по умолчанию в классах java.time при разборе / генерации строк, представляющих значения даты и времени.

String input = "2009-09-17T00:00:00.000+01:00";
OffsetDateTime odt = OffsetDateTime.parse( input );

Если вам нужен тот же момент на временной шкале, но в UTC , извлеките объект Instant. Лучше всего придерживаться UTC и этого класса для большей части вашей бизнес-логики, обмена данными и хранения данных.

Instant instant = odt.toInstant();

Чтобы сгенерировать строку в формате ISO 8601, позвоните toString.

String output = instant.toString();  // 2009-09-16T23:00:00Z

Чтобы увидеть то же значение, скорректированное на время настенных часов некоторого часового пояса, примените ZoneId, чтобы получить объект ZonedDateTime , Часовой пояс - это смещение от UTC плюс правил обработки аномалий, таких как Летнее время (DST) .

ZoneId zoneId = ZoneId.of( "Europe/London" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Также, если вам нужно зафиксировать текущий момент в UTC:

Instant instant = Instant.now();

Адаптер для JAXB

Java Architecture для привязки XML (JAXB) * ​​1067 * может еще не поддерживать типы java.time напрямую.

До тех пор, пока не будет добавлена ​​прямая поддержка, вы можете использовать адаптер для типов java.time, как обсуждено в этого ответа Блейза Дафана на вопрос, Может ли JAXB обрабатывать объекты java.time . Вы можете использовать эту реализацию или написать свою собственную, смоделировав одну или эту аналогичную для библиотеки Joda-Time .

LocalDate

Эти значения времени дня 00:00:00 заставляют меня задуматься, действительно ли вы пытаетесь представлять значения только для даты. В значении только для даты вас не заботит ни время суток, ни часовой пояс. Если это так, рассмотрите возможность использования класса LocalDate.

...