SimpleDateFormat без смещения Timezone в Java (GMT + 00: 00) для пользовательского часового пояса

Можно ли отформатировать дату и время в Java с помощью класса SimpleDateFormat, чтобы задать часть даты в часовом поясе, не имея после него +0000.

Изменить

Мы меняем часовой пояс по умолчанию в Java следующим образом:

SimpleTimeZone tz = new SimpleTimeZone(0, "Out Timezone");        
TimeZone.setDefault(tz);

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

Имея это в виду, я хочу отформатировать дату как:

2011-12-27 09:00 GMT

или

2011-12-27 09:00 BST

Я могу только заставить SimpleDateFormat выводить как:

2011-12-27 09:00:00 GMT + 00: 00

который использует строку формата гггг-мм-дд чч: мм: сс z

Я не вижу нигде, где в простом часовом поясе есть какая-либо ссылка на идентификатор зимнего времени (GMT) или идентификатор летнего времени (BST).

Ответ 1

Не очень элегантное решение, но оно работает для нас. Мне пришлось создать пользовательскую реализацию для DateFormat/SimpleDateFormat. Это выглядит следующим образом:

static {
    // this would be initialized like something as follows when the application starts
    // which causes the headaches of SimpleDateFormat not to work...
    SimpleTimeZone tz = new SimpleTimeZone(0, "Out Timezone");             
    TimeZone.setDefault(tz);  
}

// therefore this class will workaround the issue, 

public class OurOwnCustomDateFormat
    extends SimpleDateFormat {

    /** The pattern to use as the format string. */
    protected String pattern;

    public OurOwnCustomDateFormat(String pattern) {
         super(pattern);
         // store the pattern
         this.pattern = pattern;
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {

         // custom implementation to format the date and time based on our TimeZone            
         toAppendTo.insert(pos.getBeginIndex(), "the date with our custom format calculated here");
         return toAppendTo; 
    }

Ответ 2

Этот вопрос и ответы теперь устарели. Они используют старые классы даты и времени, устаревшие с помощью инфраструктуры java.time, встроенной в Java 8 и более поздние версии. Старые классы плохо спроектированы, запутаны и хлопотны; Избегайте их.

Избегайте 3-4 буквенных зонных кодов

Избегайте 3-4-буквенных кодов, таких как BST. Они не стандартизированы и не уникальны. Они на самом деле не представляют часовые пояса. И они добавляют еще больше путаницы к проблеме перехода на летнее время (DST).

Вместо этого используйте надлежащие часовые пояса. Большинство из них имеют формат continent/region, например Europe/London.

Избегайте установки часового пояса по умолчанию

Вызов java.util.TimeZone.setDefault следует выполнять только в самых крайних случаях. Этот вызов влияет на весь код, выполняемый во всех потоках всех приложений в JVM, непосредственно во время выполнения.

Вместо этого во всем вашем коде даты и времени укажите желаемый/ожидаемый часовой пояс. Если опущено, Java отступает, неявно полагаясь на текущий часовой пояс по умолчанию JVM. Как отмечено выше, это значение по умолчанию может измениться в любой момент во время выполнения! Вместо этого укажите явно. Если вы обычно указываете желаемый/ожидаемый часовой пояс в качестве переданного аргумента, то текущий часовой пояс по умолчанию является спорным, не имеет значения.

java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Смотрите учебник. Определено JSR 310. Вдохновлено очень успешной библиотекой Joda-Time.

Instant

Instant - это момент времени на UTC.

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

Instant instant = Instant.parse( "2011-12-27T09:00:00Z" );

ZonedDateTime

Примените часовой пояс по мере необходимости, создавая ZonedDateTime.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );

Генерация строк

Вы можете создавать текстовые представления объекта ZonedDateTime, используя DateTimeFormatter. Вы можете указать пользовательские шаблоны. Или, как я рекомендую, пусть java.time локализуется для вас.

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM );

Лучше всего указать желаемый/ожидаемый Locale по той же причине, что и часовой пояс... Текущее значение по умолчанию для JVM может быть изменено в любой момент с помощью любого кода в любом потоке любого приложения, работающего в JVM, Locale определяет (а) человеческий язык, используемый для названий дня & месяц, и (b) культурные нормы, такие как запятые в зависимости от периодов, и порядок частей, таких как месяц, день или год, который наступит первым.

formatter = formatter.withLocale( Locale.CANADA_FRENCH );
String output = zdt.format( formatter );

О java.time

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

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

Чтобы узнать больше, см. Учебное пособие по Oracle. И поищите в Кару множество примеров и объяснений. Спецификация: 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 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 & 7 в ThreeTen-Backport.
  • Android

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

Ответ 3

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

Когда я форматирую дату с помощью шаблона, я получаю "GMT" для части часового пояса.

Что дает TimeZone.getDefault().getDisplayName()? Для меня я получаю "среднее время по Гринвичу".

Ответ 4

Так как я не могу воспроизвести эту проблему на своем компьютере. Думаю, это будет связано с локализацией. Попробуйте это

System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z",Locale.US).format(new Date()));

Надеюсь, что это поможет.

Ответ 5

System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date())); для меня просто возвращает 2011-11-22 13:42:16 GMT - так кажется, работает как вам угодно. Похоже, что это может быть проблемой в другом месте, вам не нужно создавать собственный класс форматирования.