Клонированный календарик

Sep 18, 2013   #java  #што 

Продолжаю уже ставшей традиционной цепочку постов о календариках (уже второй пост!).
Сначала была загадка для детей. Теперь загадка для повзрослевших. Тех, кто просто пишет на 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() — зло.

comments powered by Disqus