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?
Проект 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
- так кажется, работает как вам угодно. Похоже, что это может быть проблемой в другом месте, вам не нужно создавать собственный класс форматирования.