Ошибка часового пояса SimpleDateFormat на Android

Я пытаюсь изолировать ошибку в своем приложении. Мне удалось создать следующую "загадку":

SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
SimpleDateFormat f2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date d = f1.parse("2012-01-01T00:00:00+0700");
String s1 = f1.format(d); // 2011-12-31T18:00:00+0700
String s2 = f2.format(d); // 2011-12-31T18:00:00+0100

Я получаю значения в комментариях при запуске этого кода в Android API 7 (да, действительно). Это зависит от конкретной реализации Java.

Мои вопросы:

  • Почему s1 не равно s2?
  • И что еще более важно, почему s1 неверен? Пока s2 указывает на правильный момент времени, s1 нет. Кажется, что ошибка в реализации Android SimpleDateFormat.

ОТВЕТ НА ВОПРОС 1: См. ответ BalusC:

  • [После использования SimpleDateFormat#parse] любое другое значение TimeZone, которое ранее было установлено вызовом setTimeZone, возможно, потребуется восстановить для дальнейших операций.

ОТВЕТ НА ВОПРОС 2: См. ответ wrygiel (я).

  • Это связано с ошибкой в ​​Android 2.1 (API 7).

Ответ 1

Это упоминается в javadoc DateFormat#parse():

Разбирайте строку даты/времени в соответствии с заданной позицией анализа. Например, текст времени "07/10/96 4:5 PM, PDT" будет анализироваться в Дате, эквивалентной Date(837039900000L).

По умолчанию разбор является мягким: если вход не находится в форме, используемой этим методом объектного формата, но все равно может быть проанализирован как дата, тогда синтаксический анализ завершается успешно. Клиенты могут настаивать на строгом соблюдении формата, вызывая setLenient(false).

Эта операция синтаксического анализа использует calendar для создания Date. В результате поля calendar's даты и времени TimeZone могут быть перезаписаны в зависимости от реализаций подкласса. Любое значение TimeZone, которое ранее было установлено вызовом setTimeZone, возможно, потребуется восстановить для дальнейших операций.

Обратите внимание на последний абзац. К сожалению, это не объясняет, когда именно это произойдет. Чтобы исправить вашу конкретную проблему, вам нужно явно задать желаемый часовой пояс перед операцией форматирования.

Что касается изменчивости самого SimpleDateFormat, это известно уже много лет. Вы никогда не должны создавать и присваивать ему экземпляр как статическую или классную переменную, но всегда как переменную метода (threadlocal).

Ответ 3

Ваш вопрос заинтриговал меня, поэтому я пошел дальше и скомпилировал ваш код. Результат? Как и ожидалось...

2011-12-31T18:00:00+0100
2011-12-31T18:00:00+0100

Два значения одинаковы: используете ли вы concurrency? Возможно, переменная изменяется на другой поток прямо перед f2.format(d).

Ответ 4

Я попытался сравнить s1 и s2, запустив ту же программу. они равны мне. enter image description here