Использование Joda-Time для получения UTC-коррекции для заданной даты и часового пояса
У меня есть даты в формате 20Jan2013, 08Aug2012 и т.д. со своими конкретными часовыми поясами. Так, например, 20Jan2013 может иметь идентификатор часовой пояс Австралии/Мельбурна, а 08Aug2012 может иметь идентификатор Европы/Лондона. То, что я хочу сделать, основано на этих часовых поясах и датах, вычислить смещение UTC для этого часового пояса на данную дату. Я придумал это до сих пор:
DateTimeFormatter dtf = DateTimeFormat.forPattern("ZZ");
DateTimeFormatter dtf1 = DateTimeFormat.forPattern("ddMMMYYYY");
DateTimeZone zone = DateTimeZone.forID("Australia/Melbourne");
DateTime thisDate = dtf1.parseDateTime("30Jul2013");
System.out.println("\nZone: " + thisDate.withZone(zone));
Это дает мне результат:
Zone: 2013-07-30T00:00:00.000+10:00
Это правильно, но я хотел бы извлечь только смещение UTC от этого, которое в этом случае равно +10: 00. Я искал способы сделать это, но ничего не могу найти. Есть ли способ сделать это? Единственный вариант, который я вижу, это преобразовать вывод в String и использовать метод подстроки для получения смещения UTC.
В приведенном выше коде учитывается DST (летнее время). Так, например, если бы у меня было:
DateTime thisDate = dtf1.parseDateTime( "30Jan2013" );
Выход будет: 2013-01-30T00: 00: 00.000 + 11: 00
(+ 11:00 в конце вместо +10: 00)
Так что в основном все, что мне нужно сделать, это найти способ извлечь +11: 00 с 2013-07-30T00: 00: 00.000 + 11: 00. Пожалуйста, помогите!
Ответы
Ответ 1
Простой способ получения названия часового пояса и смещения в часы
public static String getCurrentTimeZoneOffset() {
DateTimeZone tz = DateTimeZone.getDefault();
Long instant = DateTime.now().getMillis();
String name = tz.getName(instant);
long offsetInMilliseconds = tz.getOffset(instant);
long hours = TimeUnit.MILLISECONDS.toHours( offsetInMilliseconds );
String offset = Long.toString( hours );
return name + " (" + offset + " Hours)";
// Example: "Mountain Standard Time (-7 Hours)"
}
Пара предупреждений:
- Это получает значение по умолчанию
DateTimeZone
от JodaTime. Вы можете изменить его, чтобы принять определенный DateTimeZone, который передается в метод.
- Это возвращает его в формате " Mountain Standard Time (-7 Hours)", но вы можете отформатировать его, как видите, довольно легко.
Надеюсь, что это поможет.
В JP
Ответ 2
Если вам просто требуется смещение часового пояса, используйте DateTimeZone.forID()
, чтобы получить часовой пояс, а затем tz.getOffset(instant)
, чтобы получить смещение по UTC в миллисекундах.
Может показаться странным, что вам нужно мгновенное вычисление смещения в UTC, но это необходимо учитывать с учетом летнего сбережения, а также изменения в часовом поясе. Да, страны время от времени меняют свои временные интервалы:
Почему изменения в часовом поясе?
Настройки часового пояса принимаются локально, и нет авторитета в мировом часовом поясе.
EDIT. Это дает правильный результат:
DateTimeFormatter dtf1 = DateTimeFormat.forPattern("ddMMMYYYY");
DateTimeZone zone = DateTimeZone.forID("Australia/Melbourne");
DateTime thisDate = dtf1.parseDateTime("30Jul2013").withZone(zone);
assertEquals( 10 * CommonConstants.MILLISECONDS_PER_HOUR,
zone.getOffset( thisDate ) );
thisDate.get
Ответ 3
Чтобы Joda дала правильное смещение, вы должны предоставить мгновенное мгновение. Без мгновенного времени невозможно вычислить смещение, так как у нас есть разные смещения (переход на летнее время). Так я бы использовал Joda для смещения в формате + HH: mm:
int offsetInMillis = DateTimeZone.forID(zoneId).getOffset(new DateTime().getMillis());
String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000),
Math.abs((offsetInMillis / 60000) % 60));
offset = (offsetInMillis >= 0 ? "+" : "-") + offset;
Ответ 4
Java 8 улучшил обработку даты и времени, чтобы решить некоторые из предыдущих ограничений языка в этой области. Некоторые из моих проектов начали использовать его, а не Джоду.
Использование пакета java.time:
ZonedDateTime dateTime = LocalDate.of(2013 , 1 , 20).atStartOfDay( ZoneId.of("Australia/Melbourne"));
ZoneOffset zo = dateTime.getOffset();
int offset = zo.getTotalSeconds();
long hours = TimeUnit.SECONDS.toHours(offset);
long minutes = TimeUnit.SECONDS.toMinutes(offset % 3600);
В переменной часов установлено значение 11, а минуты - 0.
Он также вычисляет смещение минут, для часовых поясов, которые являются частичными часами, такими как Ньюфаундленд и Лабрадор в восточной Канаде:
ZonedDateTime dateTime = LocalDate.of(2013, 1, 20).atStartOfDay( ZoneId.of("Canada/Newfoundland"));
В этом случае смещение -03:30
(три с половиной часа позади UTC), hours
равно -3 и minutes
равно -30.
Для представления String, а не целого числа часов и минут, используйте метод ZoneOffset toString(). Итак, для примера выше, используйте:
String offsetString = zo.toString();
Ответ 5
Когда вы знаете смещение и временную метку, поэтому, чтобы получить текущее время, вы можете использовать
public static String formatMonthDayMinuteByGivenUtcOffset(long timestamp, int offset) {
return JODA_FORMATTER.print(createDateTime(timestamp, offset));
}