Java SimpleDateFormat по-разному интерпретирует 'z' в разных ОС - PullRequest
0 голосов
/ 25 сентября 2018

У меня следующий код (упрощено, чтобы сосредоточиться на проблеме).При этом информация о часовом поясе печатается с использованием шаблона SimpleDateFormat.

Знаете ли вы, почему z обрабатывается по-разному на разных машинах?И если есть способ заставить Java обрабатывать его одинаково на всех машинах?

Этот класс используется в JavaMail , и это заставляет наши заголовки электронной почты включать время, которое несоответствует RFC 2822 .

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class DateFormatTest {
    String PATTERN = "z";
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(this.PATTERN);

    public static void main(final String[] args) {
        new DateFormatTest().printTimezone();
    }

    public void printTimezone() {
        System.out.println(this.simpleDateFormat.format(Calendar.getInstance().getTime()));
    }

}

Вывод: Windows / Mac

PDT

Вывод: Linux (CentOS Linux выпуск 7.5.1804 (Core)) / Ubuntu14/18

GMT-07:00

1 Ответ

0 голосов
/ 25 сентября 2018

tl; dr

Никогда не используйте Calendar.Вместо этого используйте java.time классов.

Для строк в формате RFC 1123 / RFC 822 :

OffsetDateTime
.now( ZoneOffset.UTC )
.format( DateTimeFormatter.RFC_1123_DATE_TIME )

Пн, 24 сентября 2018 23:45:21 GMT

Чтобы получить текущее смещение от UTC в определенном часовом поясе:

ZoneId
.systemDefault()
.getRules()
.getOffset(
    Instant.now() 
)
.toString()

-07: 00

Избегать Calendar

Вы используете ужасные старые классы даты и времени, которые были вытеснены несколько лет назад java.time .Никогда не используйте эти классы наследства;они ужасный беспорядок.

Ваша конкретная проблема с поведением Calendar спорна , так как больше нет необходимости использовать этот класс снова.Даже при взаимодействии со старым кодом, который еще не обновлен до java.time , вы можете легко преобразовывать устаревшие и современные классы с помощью новых методов, добавленных к старым классам.

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime() ;

… и…

GregorianCalendar gc = GregorianCalendar.from( zdt ) ; 

java.time

Очевидно, вы хотите текущее смещение от UTC для текущего часового пояса по умолчанию.

Получить текущий часовой пояс по умолчанию, aZoneId.

ZoneId z = ZoneId.systemDefault() ;  // Or specify ZoneId.of( "Pacific/Auckland" ) or so on.

Запросить правила в этом часовом поясе.

ZoneRules rules = z.getRules() ;

Получить смещение от UTC, действующее в этой зоне в определенный момент.Мы будем использовать текущий момент, Instant.

Instant now = Instant.now() ;
ZoneOffset offset = rules.getOffset( now ) ;

Создание текста, представляющего это смещение от UTC.

String output = "At " + now + " in zone " + z + " the offset is " + offset;

В 2018-09-24T23: 38: 44.192642Z в зоне America / Los_Angeles смещениеis -07: 00

RFC 1123 / RFC 822

Вы упомянули RFC, но не указали.Возможно, RFC 1123/822?

Форматер для этого встроен в java.time .

OffsetDateTime nowInUtc = OffsetDateTime.now( ZoneOffset.UTC ) ;
String output = nowInUtc.format( DateTimeFormatter.RFC_1123_DATE_TIME ) ;

Пн, 24Сентябрь 2018 23:45:21 GMT

ISO 8601

FYI, этот формат RFC 1123 / RFC 822 имеет формат ужасный .Предполагается английский.Это трудно для машин, чтобы разобрать, и людям трудно читать.Но я понимаю, что вам это может понадобиться для устаревших старых протоколов.

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


About java.time

Фреймворк java.time встроен в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздних версий - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии пакетов Android для реализации java.time классы.
    • Для более ранней версии Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и more .

...