Про непереносимость

Не переношу запаха (да и вкуса тоже) горчицы. А больше всего не переношу непереносимость. К счастью, программируя на java, об этом можно сильно не беспокоиться. К несчастью, когда об этом сильно не беспокоишься, получаешь то что больше всего не переносишь.

Задача: J2SE 1.4.x, необходим объект java.util.Date, представляющий дату текущего дня с точностью то числа.

Решение 1: Создать java.util.Calendar, выставить в нем значения необходимых полей, а остальные очистить. Делаем:

import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; public class TestClearCalendar { public static void main(String[] args) { final int[] fields = new int[] { Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, }; final Locale locale = new Locale("ru", "RU"); final Calendar cal = Calendar.getInstance(locale); final DateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss SSS ", locale); for (int i = 0; i < fields.length; i++) { cal.clear(fields[i]); } System.out.println(format.format(cal.getTime())); } }

Пускаем и получаем дату, но с точностью до часа:
10.01.2006 15:00:00 000.

После этого обнаруживаем, что проблема то давно известная, и по понятным/непонятным причинам, вовсе не является багом, а всего-лишь неясность в документации. Ок. Воспользуемся первой заплаткой, добавив Calendar.HOUR в массив обновляемых полей. Пускаем, смотрим, все хорошо:
10.01.2006 00:00:00 000.

Прошло n дней…

И мы перешли на Java SE 5.0. И вдруг замечаем что что-то в нашей системе творится неладное, и работает она как оборотень, только наоборот - днем с ней происходят странные вещи. После нескольких часов/дней в отладчике вдруг выясняется, что наш код в разное время суток (до и после полуночи) работает по-разному:

final Calendar cal = Calendar.getInstance(locale); final Calendar cal2 = (Calendar) cal.clone(); cal2.add(Calendar.HOUR_OF_DAY, 12); final DateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss SSS ", locale); for (int i = 0; i < fields.length; i++) { cal.clear(fields[i]); cal2.clear(fields[i]); } System.out.println(format.format(cal.getTime())); System.out.println(format.format(cal2.getTime()));

в итоге дает
10.01.2006 12:00:00 000
11.01.2006 00:00:00 000

Читаем баг-репорт внимательнее и находим, что оказывается час в календаре определяется тремя независимыми полями, и если хоть одно из них не очищено - час дня вычисляется исходя из его значения. Судя по всему инженеры из SUN не только поправили документацию, но и немного исправили реализацию календаря согласно ей, и теперь после полудня наше врямя сбрасывается в полудень. После правки по настоянию “солнцеподобных”, похоже все приходит в норму.

Итак, если необходимо получить дату без времени, необходимо вызвать clear для полей Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.HOUR и Calendar.AM_PM.

Даже если вас съели, у вас есть два выхода (© народное)

Конечно можно воспользоваться и второй заплаткой, установив значения полей Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE и Calendar.HOUR_OF_DAY в 0.

Однако если понадобится получить объект java.util.Date с точностью до месяца, то необходимо помнить, что минимальное значение поля Calendar.DATE и других полей, определяющих день недели/месяца/года - это 1, и использовать нужно именно его, иначе получим или последнее число предыдущего месяца или еще чего доброго исключение.

 

3 replies


  1. Спасибо.
    Очень информативно и довольно поэтично :)


  2. Как вариант можно просто создать новый Calendar и скопировать значения полей YEAR, MONTH и DAY_OF_MONTH :)

    А ещё можно использовать библиотеку Joda Time, которая содержит более внятные примитивы для работы с временем и временными интервалами, чем JDK.


  3. Нельзя по той простой причине, что новый календарь установлен в текущее время системы. Т.е. в любом случае надо некоторые поля календаря очистить.

    Про Joda Time слышал - неплохая вешь, но не всегда есть смысл тащить в проект еще одну зависимость, когда достаточно сделать пару утилитных классов/методов для достижения нужного результата.

Leave a reply