Java DateFormat parse() не соблюдает часовой пояс
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/New_York"));
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("America/New_York"));
try {
System.out.println(df.format(cal.getTime()));
System.out.println(df.parse(df.format(cal.getTime())));
} catch (ParseException e) {
e.printStackTrace();
}
Вот результат:
2011-09-24 14:10:51 -0400
Сб Сен 24 20:10:51 CEST 2011
Почему при анализе даты, которую я получаю из формата(), она не соблюдает часовой пояс?
Ответы
Ответ 1
Вы печатаете результат вызова Date.toString()
, который всегда использует часовой пояс по умолчанию. В принципе, вы не должны использовать Date.toString()
для чего угодно, кроме отладки.
Не забывайте, что a Date
не имеет часового пояса - он представляет собой момент времени, измеренный как миллисекунды с эпохи Unix (полночь 1 января 1970 UTC).
Если вы форматируете дату с помощью своего форматирования, это должно совпадать с тем же ответом, что и раньше.
В стороне, я бы рекомендовал использовать Joda Time вместо Date
/Calendar
, если вы делаете какие-либо значительные время работы на Java; это гораздо более удобный API.
Ответ 2
DateFormat.parse()
НЕ является запросом (то, что возвращает значение и не изменяет состояние системы). Это команда, которая имеет побочный эффект обновления внутреннего объекта Calendar
. После вызова parse()
вам нужно получить доступ к часовому поясу либо путем доступа к DateFormat
Calendar
, либо вызова DateFormat.getTimeZone()
. Если вы не хотите выбросить исходный часовой пояс и использовать локальное время, не используйте возвращаемое значение Date
из parse()
. Вместо этого используйте объект календаря после разбора. И то же самое верно для метода формата. Если вы собираетесь отформатировать дату, передайте календарь с информацией о часовом поясе в объект DateFormat
перед вызовом format()
. Вот как вы можете конвертировать один формат в другой формат, сохраняя исходный часовой пояс:
DateFormat originalDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
DateFormat targetDateFormat = new SimpleDateFormat("EEE., MMM. dd, yyyy");
originalDateFormat.parse(origDateString);
targetDateFormat.setCalendar(originalDateFormat.getCalendar());
return targetDateFormat.format(targetDateFormat.getCalendar().getTime());
Это беспорядочно, но необходимо, так как parse()
не возвращает значение, которое сохраняет часовой пояс, а format()
не принимает значение, определяющее часовой пояс (класс Date
).
Ответ 3
DateFormat - это абстрактный класс для подклассов форматирования даты и времени который форматирует и анализирует даты или время в независимом от языка манера. Подкласс даты/времени, например SimpleDateFormat, позволяет форматировать (т.е. дата → текст), разбор (текст → дата), и нормализация. Дата представляется как объект Date или как миллисекунд с 1 января 1970 года, 00:00:00 GMT.
Из spec возвращается EPOCH время