Продолжаю уже ставшей традиционной цепочку постов о календариках (уже второй пост!).
Сначала была загадка для детей. Теперь загадка для повзрослевших. Тех, кто просто пишет на Java (или хотя бы в глаза видел хоть раз строчку import java.util.*) и не интересуется внутренностями какого-то там андроида и дальвика.
Возьмём такой простенький код. Считаем, что текущая таймзона — Москва. Хотя сработает для любых других, кроме UTC.
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance();
calendar.set(2013, Calendar.AUGUST, 14, 0, 0, 0);
Calendar when1 = (Calendar) calendar.clone();
when1.setTimeZone(utc);
System.out.println(calendar.getTime());
System.out.println(when1.getTime());
Calendar when2 = (Calendar) calendar.clone();
when2.setTimeZone(utc);
System.out.println(calendar.getTime());
System.out.println(when2.getTime());
Краткое описание: создаём объект календаря с 14 августа 2013 года, дважды его клонируем, в двух клонах меняем таймзону на UTC и выводим полученное.
Что же он выведет на экран?
Вот что:
Wed Aug 14 00:00:00 MSK 2013
Wed Aug 14 04:00:00 MSK 2013
Wed Aug 14 00:00:00 MSK 2013
Wed Aug 14 00:00:00 MSK 2013
Необычна вторая строка. Почему-то время не такое, как везде.
Причина следующая (пруф):
set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar’s time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made.
Кратко по-русски: изменение полей в календаре ленивое и сразу не пересчитывает внутреннее состояние (миллисекунды с ~ начала 1970 года) до тех пор, пока не произойдёт попытка что-то из него прочитать.
А вот то, что из-за вызова clone() потерялась некоторая информация о том, что было изменено и не пересчиталось — баг :)
Вывод. Использование Calendar.clone() — зло.