Обработка даты и времени сложная задача. В Java, по всей видимости, не удалось сразу сделать нормальные классы для этого.
Самым первым классом был класс java.util.Date. Первоначально он имел конструкторы для создания экземпляров по указанному году, месяцу, числу, часам и минутам. У него были методы для установки и получения значений отдельных полей даты и времени. Но теперь все эти методы помечены как устаревшие. Сейчас экземпляры java.util.Date можно создавать только с текущим значением даты и времени, либо по указанному количеству миллисекунд, прошедших с 1 января 1970 года по GMT. Все методы для работы с отдельными полями помечены устаревшими. Фактически, можно пользоваться только методами long getTime() и setTime(long time), которые позволяют получить количество миллисекунд, прошедших с того же 1 января 1970 года по GMT. Более подробно работу с датой и временем в Java я уже описывал.
На некоторых сайтах можно найти информацию о том, что java.util.Date содержит только количество миллисекунд с 1 января 1970 года по GMT, что у него нет значения часового пояса, но это ошибочно (по ссылке даже в конце тоже сказали, что это утверждение ошибочно). Экземпляры java.util.Date хранят часовой пояс. Вы не можете указать или получить эту часовой пояс, но они её хранят. Посмотрите исходные коды java.util.Date, обратите особое внимание на поле private transient BaseCalendar.Date cdate;. Я, правда, не нашёл ни одного более менее нормального метода, где бы это поле устанавливалось, но тем не менее оно есть. Думаю, что какие-то из методов, отмеченные как устаревшие, использовали их раньше. Они и сейчас его используют, но во всех методах, которые устанавливают cdate во что-либо, в конце есть строчка cdate = null;.
На текущий момент java.util.Date можно рассматривать лишь как класс, который хранит количество миллисекунд, прошедших с 1 января 1970 года 00:00:00 по GMT. Можно использовать только конструктор по умолчанию, конструктор с аргументом long date, метод long getTime() и метод setTime(long time). Для создания более сложных экземпляров java.util.Date следует использовать класс java.util.Calendar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/** * https://urvanov.ru * Вам разрешено делать с этим кодом всё, что хотите. */ import java.util.Date; import java.util.Calendar; import java.util.TimeZone; import java.text.DateFormat; public class DateFromCalendar1 { public static void main(String[] args) { Calendar calendar = Calendar.getInstance(); calendar.set(2017, 1, 10, 20, 10, 33); calendar.set(Calendar.MILLISECOND, 100); // date1 хранит количество миллисекунд, // прошедших с 1 января 1970 00:00:00.000 GMT, // по 10 февраля 2017 20:10:33.100 // по чикагскому времени calendar.setTimeZone(TimeZone.getTimeZone("America/Chicago")); Date date1 = calendar.getTime(); // date2 хранит количество миллисекунд, // прошедших с 1 января 1970 00:00:00.000 GMT, // по 10 февраля 2017 20:10:33.100 // в Кубе calendar.setTimeZone(TimeZone.getTimeZone("Cuba")); Date date2 = calendar.getTime(); // date3 хранит количество миллисекунд, // прошедших с 1 января 1970 00:00:00.000 GMT, // по 10 февраля 2017 20:10:33.100 // по московскому времени calendar.setTimeZone(TimeZone.getTimeZone("Europe/Moscow")); Date date3 = calendar.getTime(); // dateFormat по умолчанию использует системную локаль. DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); // Выводим на экран, сколько времени было у нас в каждой из этих // трёх дат System.out.println("formatted date1=" + dateFormat.format(date1)); System.out.println("formatted date2=" + dateFormat.format(date2)); System.out.println("formatted date3=" + dateFormat.format(date3)); } } |
Результат работы программы (для моего часового пояса):
1 2 3 |
formatted date1=11 февраля 2017 г. 5:10:33 GMT+03:00 formatted date2=11 февраля 2017 г. 5:10:33 GMT+03:00 formatted date3=11 февраля 2017 г. 5:10:33 GMT+03:00 |
Классы java.sql.Date, java.sql.Time и java.sql.Timestamp наследуются от java.util.Date. Они являются небольшими хаками-обёртками. Их единственное назначение — работа с JDBC драйверами, которым нужно отобразить поля типа DATE, TIMESTAMP и TIME из базы данных на объект в Java. Избегайте их использования во всех других случаях, иначе получите огромное количество проблем.
Обработка даты и времени довольно сложная штука, как я уже говорил, и ошибиться тут довольно таки легко, особенно если части вашего приложения распределены по нескольким часовым поясам.