Joda Time анализирует дату с часовым поясом и сохраняет этот часовой пояс
Я хочу проанализировать дату, созданную с определенным часовым поясом, преобразовать ее в формат и вернуть ее. Преобразование работает, но смещение часового пояса всегда установлено на +0000, когда разница во времени добавляется/вычитается по мере необходимости. Как я могу получить его для форматирования и правильной коррекции?
Я ожидаю этого: 2012-11-30T12: 08: 56.23 + 07: 00
Но получите это: 2012-11-30T05: 08: 56.23 + 00: 00
Реализация:
public static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSZZ";
public static String formatDateToISO8601Standard(Date date) {
DateTime dateTime = new DateTime(date);
DateTimeFormatter df = DateTimeFormat.forPattern(ISO_8601_DATE_FORMAT);
return dateTime.toString(df);
}
Класс тестирования:
private static final String DATE_WITH_TIMEZONE = "30 11 2012 12:08:56.235 +0700";
private static final String EXPECTED_DATE_WITH_TIMEZONE = "2012-11-30T12:08:56.23+07:00";
@Test public void testFormattingDateWithSpecificTimezone() throws Exception {
String result = JodaDateUtil.formatDateToISO8601Standard(createDate(DATE_WITH_TIMEZONE));
assertEquals("The date was not converted correctly", EXPECTED_DATE_WITH_TIMEZONE, result); }
private Date createDate(String dateToParse) throws ParseException {
DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z");
DateTime temp = df.parseDateTime(dateToParse);
Date date = temp.toDate();
return date; }
Ответы
Ответ 1
В принципе, как только вы проанализируете строку даты [в методе createDate()], вы потеряли исходную зону. Joda-Time позволит вам форматировать дату в любой зоне, но вам нужно сохранить исходную зону.
В вашем методе createDate() DateTimeFormatter "df" может вернуть зону, которая была в строке. Вам нужно будет использовать метод withOffsetParsed(). Затем, когда у вас есть DateTime, вызовите getZone(). Если вы сохраните эту зону где-нибудь или каким-то образом передадите ее в свою процедуру форматирования, вы можете использовать ее там, создав DateTimeFormatter "withZone" и указав, что зона как таковая вы хотите в формате.
Как демонстрационный пример, здесь приведен пример кода в одном методе. Надеюсь, это поможет изменить код так, как вы хотите его запустить.
public static void testDate()
{
DateTimeFormatter df = DateTimeFormat.forPattern("dd MM yyyy HH:mm:ss.SSS Z");
DateTime temp = df.withOffsetParsed().parseDateTime("30 11 2012 12:08:56.235 +0700");
DateTimeZone theZone = temp.getZone();
Date date = temp.toDate();
DateTime dateTime = new DateTime(date);
DateTimeFormatter df2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSZZ");
DateTimeFormatter df3 = df2.withZone(theZone);
System.out.println(dateTime.toString(df2));
System.out.println(dateTime.toString(df3));
}
Ответ 2
Попробуйте это.
ISODateTimeFormat.dateTimeParser().parseDateTime(dateString),
затем преобразуйте его в желаемый формат.
Ответ 3
Принятый ответ правильный. Как только вы конвертируете в объект java.util.Date
, вы теряете информацию о часовом поясе. Это осложняется тем фактом, что java.util.Date::toString
смешивает текущий часовой пояс по умолчанию при создании строки.
Не используйте эти старые классы времени, например java.util.Date
. Они плохо разработаны, запутываются и хлопотны. Теперь наследие, вытесненное проектом java.time. Так же проект Joda-Time теперь вытесняется классами java.time.
java.time
Разберите эту входную строку как объект OffsetDateTime
, поскольку она включает в себя смещение-от-UTC, но не имеет часового пояса. Вызовите DateTimeFormatter.ofPattern
, чтобы указать собственный формат, соответствующий вашей входной строке. Передайте этот объект форматирования OffsetDateTime.parse
.
String input = "30 11 2012 12:08:56.235 +0700";
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd MM uuuu HH:mm:ss.SSS X" , Locale.US );
OffsetDateTime odt = OffsetDateTime.parse ( input , f );
odt: toString(): 2012-11-30T12: 08: 56.235 + 07: 00
Чтобы увидеть тот же самый момент в UTC, извлеките Instant
. Класс Instant
представляет момент на временной шкале в UTC с разрешением наносекунды (до девяти (9) цифр десятичной дроби).
Instant instant = odt.toInstant();
instant.toString(): 2012-11-30T05: 08: 56.235Z
Вы можете применить любой часовой пояс, через который вы хотите просмотреть тот же момент, ту же точку на временной шкале.
ZonedDateTime zdtKolkata = odt.toInstant ().atZone ( ZoneId.of ( "Asia/Kolkata" ) );
zdtKolkata.toString(): 2012-11-30T10: 38: 56.235 + 05: 30 [Азия/Калькутта]
Не нужно смешивать старые классы времени. Придерживайтесь java.time. Если вы должны использовать какой-то старый код, еще не обновленный до типов java.time, посмотрите на новые методы, добавленные к старым классам для преобразования в/из java.time.
Эквивалент java.util.Date
равен Instant
, оба являются точкой отсчета с 1970-01-01T00:00:00Z
в UTC. Но остерегайтесь потери данных, поскольку классы java.time поддерживают наносекундное разрешение, но старые классы ограничены миллисекундами.
java.util.Date utilDate = java.util.Date.from( instant );
Живой код
Смотрите живой рабочий код в IdeOne.com.
О java.time
Структура java.time встроена в Java 8 и более поздних версий. Эти классы вытесняют неприятные старые legacy классы времени, такие как java.util.Date
, .Calendar
и java.text.SimpleDateFormat
.
Проект Joda-Time, теперь режим обслуживания, советует перейти на java.time.
Чтобы узнать больше, см. Учебник Oracle. И поиск Qaru для многих примеров и объяснений. Спецификация JSR 310.
Где получить классы java.time?
- Java SE 8 и SE 9 и позже
- Встроенный.
- Часть стандартного Java API с объединенной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и SE 7
- Большая часть функциональных возможностей java.time портирована на Java 6 и 7 в ThreeTen-Backport.
- Android
Проект ThreeTen-Extra расширяет java.time с помощью дополнительных классов. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные классы, такие как Interval
, YearWeek
, YearQuarter
и больше.