SimpleDateFormat без смещения часового пояса в Java (GMT + 00: 00) для пользовательского часового пояса - PullRequest
9 голосов
/ 22 ноября 2011

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

Редактировать

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

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

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

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

2011-12-27 09:00 по Гринвичу

или

2011-12-27 09:00 BST

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

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

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

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

Есть мысли?

Спасибо

Andez

Ответы [ 5 ]

5 голосов
/ 09 марта 2016

Этот вопрос и ответы теперь устарели. Они используют старые классы даты и времени, устаревшие с помощью инфраструктуры 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 определяет (а) человеческий язык, используемый для названий дня и месяца, и (б) культурные нормы, такие как запятые по сравнению с периодами, и порядок частей, таких как месяц или день или год, который идет первым.

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 Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

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

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

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

3 голосов
/ 22 ноября 2011

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

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

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

1 голос
/ 22 ноября 2011

Не совсем элегантное решение, но оно работает для нас. Мне пришлось создать собственную реализацию для 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; 
    }
1 голос
/ 22 ноября 2011

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

1 голос
/ 22 ноября 2011

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

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

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

...