Время на прочтение
5 мин
Количество просмотров 18K
Не так давно у меня возникла необходимость парсинга и последующего вывода нужной информации из iCalendar. После упорных поисков я наткнулся на библиотеку iCal4J. Присмотревшись к её функционалу, я понял — это то, что мне нужно. Давайте же попробуем её применить на практике.
Подготовка календаря
В Google Calendar я создал маленький календарь, состоящий из нескольких различных мероприятий длительностью от 30 минут до 6 часов. Затем я скачал календарь в формате iCal к себе на ноутбук. Если кто не знает — делается это так: заходим в настройки календаря Google и в разделе «Закрытый адрес календаря» жмём на зеленую кнопочку «ICAL». Всё, календарь загружен на устройство.
Подготовка Java
Следующим этапом стала загрузка библиотеки и подключение ее к проекту. Распаковал и указал среде разработки папку с файлами библиотек *.jar. Также в папку с проектом был скопирован мой скачанный файл календаря. Все готово к написанию кода!
Загрузка календаря
Существует два варианта загрузки календаря — из файла и парсинг строки с содержимым календаря. Мы выберем первый способ (второй существенно не отличается от него).
// Открываем входной поток из файла
FileInputStream fin = new FileInputStream("calendar.ics");
// И на основе этого потока парсим календарь в объект Calendar
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(fin);
Вывод всех мероприятий
Давайте теперь попробуем вывести куда — нибудь (ну хотя бы в консоль) все мероприятия из нашего календаря.
// Получаем список мероприятий
ComponentList listEvent = calendar.getComponents(Component.VEVENT);
for (Object elem : listEvent) {
// Нам придется явно привести элемент списка к нужному типу, так как listEvent хранит элементы Object
VEvent event = (VEvent) elem;
// Получаем описание
// getValue() делаем для того, чтобы извлечь только значение. Доступные методы getName() и toString() вернут в себе еще значение тега DESCRIPTION
String description = event.getDescription().getValue();
// Получаем заголовок мероприятия
String title = event.getSummary().getValue();
System.out.println(title + " : " + description);
}
Стоит обратить внимание на первую строчку, а именно Component.VEVENT. Так мы указываем, что хотим получить именно мероприятия календаря. Если не указать явно, что мы хотим извлечь из календаря, то мы получим список, в котором также окажутся To-Do компоненты (VTODO), заметки (VJOURNAL), и прочие компоненты типа VFREEBUSY, VALARM и VTIMEZONE.
Применение фильтров
Для того, чтобы вывести элементы, в моем случае мероприятия, в определенный период времени, можно применить фильтры.
java.util.Calendar today = java.util.Calendar.getInstance();
today.set(java.util.Calendar.HOUR_OF_DAY, 0);
today.clear(java.util.Calendar.MINUTE);
today.clear(java.util.Calendar.SECOND);
// Создаем период времени в 1 день
Period period = new Period(new DateTime(today.getTime()), new Dur(1, 0, 0, 0));
// На его основе создаем фильтр
Filter filter = new Filter(new PeriodRule(period));
// Применяем фильтр к календарю
List eventsToday = filter.filter(calendar.getComponents(Component.VEVENT));
// Всё, в eventsToday хранятся все мероприятия, запланированные именно на сегодня
На момент написания в моем календаре хранились такие записи (в формате «Заголовок»: «Описание» [«Время начала»]):
Event 1: Event 1 — November 1 [7 Nov 2013 13:00:00 GMT]
Event 5: Event 5 — November 12 [12 Nov 2013 12:00:00 GMT]
Event 3: Event 3 — November 10 [10 Nov 2013 19:30:00 GMT]
Event 2: Event 2 — November 9 [9 Nov 2013 08:30:00 GMT]
Event 4: Event 4 — November 11 [11 Nov 2013 08:00:00 GMT]
Event 6: Event 6 — November 13 [13 Nov 2013 09:30:00 GMT]
После применения фильтра на вывод запланированных мероприятий (на 11 ноября) я получил только одно мероприятие — Event 4:
Event 4: Event 4 — November 11 [11 Nov 2013 08:00:00 GMT]
Увеличив период до трёх дней…
Period period = new Period(new DateTime(today.getTime()), new Dur(3, 0, 0, 0));
… я получил такую картину:
Event 5: Event 5 — November 12 [12 Nov 2013 12:00:00 GMT]
Event 4: Event 4 — November 11 [11 Nov 2013 08:00:00 GMT]
Event 6: Event 6 — November 13 [13 Nov 2013 09:30:00 GMT]
Создание пустого календаря
iCal4j поддерживает также создание календаря с нуля. Здесь всё просто. Создаем объект календаря, добавляем в него необходимые поля.
Calendar calendar = new Calendar();
calendar.getProperties().add(new ProdId("-//habrahabr"));
calendar.getProperties().add(Version.VERSION_2_0);
calendar.getProperties().add(CalScale.GREGORIAN);
Добавление нового мероприятия в календарь
Вот с созданием мероприятия все не так просто, но если разобраться, то все пойдет достаточно быстро.
// Устанавливаем часовой пояс
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
TimeZone timezone = registry.getTimeZone("Europe/Minsk");
VTimeZone tz = timezone.getVTimeZone();
// Начало 10 ноября в 18:00
java.util.Calendar startDate = new GregorianCalendar();
startDate.setTimeZone(timezone);
startDate.set(java.util.Calendar.MONTH, java.util.Calendar.NOVEMBER);
startDate.set(java.util.Calendar.DAY_OF_MONTH, 10);
startDate.set(java.util.Calendar.YEAR, 2013);
startDate.set(java.util.Calendar.HOUR_OF_DAY, 18);
startDate.set(java.util.Calendar.MINUTE, 0);
startDate.set(java.util.Calendar.SECOND, 0);
// Конец в этот же день в 20:00
java.util.Calendar endDate = new GregorianCalendar();
endDate.setTimeZone(timezone);
endDate.set(java.util.Calendar.MONTH, java.util.Calendar.NOVEMBER);
endDate.set(java.util.Calendar.DAY_OF_MONTH, 10);
endDate.set(java.util.Calendar.YEAR, 2013);
endDate.set(java.util.Calendar.HOUR_OF_DAY, 20);
endDate.set(java.util.Calendar.MINUTE, 0);
endDate.set(java.util.Calendar.SECOND, 0);
// Создаем событие
String eventName = "Какое-то мероприятие";
DateTime start = new DateTime(startDate.getTime());
DateTime end = new DateTime(endDate.getTime());
VEvent meeting = new VEvent(start, end, eventName);
// Добавляем к нему информацию о часовом поясе
meeting.getProperties().add(tz.getTimeZoneId());
// Создаем сам календарь
Calendar icsCalendar = new Calendar();
icsCalendar.getProperties().add(new ProdId("-//habrahabr"));
icsCalendar.getProperties().add(CalScale.GREGORIAN);
// Добавляем к нему созданное событие
icsCalendar.getComponents().add(meeting);
Сохранение календаря в файл
Поработав с календарем, нам конечно же нужно его сохранить. Лучше всего сохранить обратно в файл.
FileOutputStream fout = new FileOutputStream("calendar.ics");
CalendarOutputter out = new CalendarOutputter();
out.output(calendar, fout);
Заключение
Мы рассмотрели базовые возможности библиотеки iCal4j. Конечно, её возможности не ограничиваются просто парсингом календаря и созданием событий. Библиотека позволяет также прикреплять файлы к событиям, создавать мероприятия с указанием места проведения в координатах, создавать списки приглашенных и многое другое. Помимо этого библиотека может использоваться в разработке Android приложений.
Ссылки:
- Описание iCalendar
- Документация по iCal4j
- iCal4j Wiki (здесь же можно и загрузить библиотеку)
Думаю это то что вам нужно.
/************************************************************************
* Compilation: javac Calendar.java
* Execution: java Calendar M Y
*
* This program takes the month M and year Y and prints a
* calendar for that month.
*
* % java Calendar 7 2005
* July 2005
* S M T W Th F S
* 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
*
************************************************************************/
public class Calendar {
/***************************************************************************
* Given the month (M), day (D), and year (Y), return which day
* of the week it falls on according to the Gregorian calendar.
* For M use 1 for January, 2 for February, and so forth. Outputs
* 0 for Sunday, 1 for Monday, and so forth.
***************************************************************************/
public static int day(int M, int D, int Y) {
int y = Y - (14 - M) / 12;
int x = y + y/4 - y/100 + y/400;
int m = M + 12 * ((14 - M) / 12) - 2;
int d = (D + x + (31*m)/12) % 7;
return d;
}
// return true if the given year is a leap year
public static boolean isLeapYear(int year) {
if ((year % 4 == 0) && (year % 100 != 0)) return true;
if (year % 400 == 0) return true;
return false;
}
public static void main(String[] args) {
int M = Integer.parseInt(args[0]); // month (Jan = 1, Dec = 12)
int Y = Integer.parseInt(args[1]); // year
// months[i] = name of month i
String[] months = {
"", // leave empty so that months[1] = "January"
"January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December"
};
// days[i] = number of days in month i
int[] days = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
// check for leap year
if (M == 2 && isLeapYear(Y)) days[M] = 29;
// print calendar header
StdOut.println(" " + months[M] + " " + Y);
StdOut.println(" S M Tu W Th F S");
// starting day
int d = day(M, 1, Y);
// print the calendar
for (int i = 0; i < d; i++)
StdOut.print(" ");
for (int i = 1; i <= days[M]; i++) {
StdOut.printf("%2d ", i);
if (((i + d) % 7 == 0) || (i == days[M])) StdOut.println();
}
}
}
Программирование – это не только написание сложных кодовых структур. Рано или поздно каждый разработчик сталкивается с форматированием даты, а также времени. За реализацию подобных операций отвечают специализированные классы. Их довольно много, но на практике используются преимущественно два варианта.
При помощи соответствующих классов в Java можно вычислять текущее время. Дополнительно программеры смогут задействовать для форматирования отдельный class в Джаве. В данной статье будет рассказано об этих нюансах, а также об основах работы с календарем при создании приложений на Java.
Но перед этим стоит понять, нужно ли вообще разбираться в целых классах Джавы. Это не всегда простая задача, особенно для новичков.
Java – перспективный и современный язык программирования. Он предусматривает:
- простой для понимания и интерпретации синтаксис;
- многофункциональность;
- разнообразные инструменты для быстрого коддинга и создания крупных проектов;
- наличие ООП.
Писать на этом языке можно совершенно разные программы – и для работы, и для развлечений. Основное предназначение Java – работа с веб-утилитами. В них вопросы, связанные с датой и временем, иногда обостряются.
Отличительной особенностью Java является то, что это – универсальный кроссплатформенный язык. Перенести программу с одной платформы на другую не составит никакого труда. Данный вариант – отличный выбор как для новичка, так и для опытного программиста.
Внимание: большинство движков для создания игр поддерживают Джава-семейство.
Терминологический вопрос – что запомнить перед началом работы
Для того, чтобы работать с текстом, а также объектами в программном коде, разработчик должен понимать, с чем он имеет дело. В программировании есть термины, без осознания которых создать собственное приложение и понять, как оно работает, невозможно.
Чтобы не запутаться в понятиях, рекомендуется запомнить следующие понятия:
- алгоритмы – свод правил и инструкций, предназначенных для решения определенных задач;
- аргументы – значения, передаваемые в функции и команды;
- переменные – элементарные «хранилища» информации;
- объекты – сочетания связанных переменных, констант, а также иных сведений структурного характера, способные выбираться и обрабатываться совместно;
- класс – набор связанных объектов с общими свойствами;
- методы – список правил, определяющих возможности того или иного элемента кода;
- цикл – неоднократное повторение одних и тех же манипуляций (части кодификации);
- константа – неизменяемое в ходе выполнения утилиты значение;
- массив – перечень/группы схожих типов информации, подлежащий группировке;
- операнд – элемент, которым удается манипулировать через так называемые операторы;
- оператор – объект в программном коде, позволяющий управлять операндами (пример – сложение или вычитание).
Непосредственно с датой и часами перечисленные термины ничего общего не имеют, но предложенная вниманию информация будет полезна в процессе создания собственных приложений. Как тех, кто работают с часами, так и примитивных утилит. Это – база, которая пригодится любому программисту перед началом работы.
Разбор календаря – с чем предстоит иметь дело
Каждый современный человек знает, что такое календарь. Можно использовать форматирование calendar в своих приложениях при программировании. Это – весьма полезные опции, которые довольно легко реализовать на практике.
Пользователю предстоит работать со следующими элементами:
- какое сейчас/было число (день недели, конкретная дата (включая месяц));
- часовой пояс;
- время (час, минута, секунда).
Для того, чтобы понять, какие объекты будут корректироваться и определяться, достаточно посмотреть на «часы» в операционной системе. Там отображается текущая дата, а также конкретное время.
Внимание: на компьютере соответствующая «часовая» информация – это определенное количество миллисекунд. При программировании подобные данные будут храниться в отдельном классе/файле.
Классы в Java для работы с часами
Для того, чтобы работать с форматом даты в Java, предстоит изучить несколько отдельных классов. Джава предусматривает их для того, чтобы использовать в приложениях и играх calendar.
На данный момент известны следующие варианты классов:
- Date;
- Calendar;
- TimeZone.
Первый два – самостоятельные составляющие, которые относятся к библиотеке java.utill. Последний обособлено не задействуется.
Класс Date
С января 1970 года хранит часы в миллисекундах. Класс обладает собственным конструктором по умолчанию. Он отвечает за конкретную операцию – возвращает текущее время.
Разработчики могут заняться созданием объекта Date при помощи конструктора, принимающего количество миллисекунд, начиная с 1970 года. Для того, чтобы уточнить внутреннее время, принято использовать методы класса Date под «названиями» setTime и getTime.
При применении класса Date осуществляется инициализация объекта. Дата и часы будут зависеть от задействованного конструктора. Всего их несколько:
- Date() — отвечает за часы и дату объекта на данный момент, «здесь и сейчас»;
- Date(long millisec) – принятие аргумента, равного количеству миллисекунд, прошедших с начала 1.01.1970 года.
В основном на практике встречается первый вариант. Чуть позже будет приведен наглядный пример того, как использовать дату и часы с соответствующим «элементом» программного кода.
О методах
Date имеет множество разнообразных методов. Они отвечают за те или иные манипуляции. Ориентироваться можно на следующую информацию:
- Int compareTo(дата дата) – производит сравнение дат. Если они совпадают, значение возвращается к 0, отрицательным оно будет, если вызывающая дата более ранняя. В противном случае – значение положительное.
- Boolean equals(object object) – при совпадении дат происходит возврат true.
- Long GetTime() – указывает, сколько миллисекунд на момент отправки запроса прошло с 1 января 1970 года.
- Void setTime(long milliseconds) – установка часов и даты в количестве миллисекунд, которые прошли с 1970-го.
- Boolean after(date date) – когда объект содержит более позднюю дату, нежели прописано в параметре date, возвращается значение «истина».
- Boolean before – аналогично предыдущему варианту, но true выходит, если объект включает в себя более ранее «значение».
Все это помогает взаимодействовать с часами, а также с тем, какое сегодня/было когда-то число.
Вот пример вывода даты в консоль:
И наглядный образец применения GetTime():
У рассматриваемого class есть подкласс, который тоже весьма активно применяется на практике. Он пригодится при непосредственном форматировании.
Подкласс SimpleDateFormat
SimpleDateFormat – это отдельный и удобный класс, который является своеобразным подклассом DateFormat. Позволяет отображать месяц, число и часы в том формате, который кажется пользователю наиболее удобным.
Чтобы лучше понимать принцип его работы, стоит рассмотреть наглядный пример кода:
package ru.test;
import java.util.Date;
import java.text.SimpleDateFormat;
public class Test
{
public void test()
{
Date d = new Date();
SimpleDateFormat format1;
SimpleDateFormat format2;
format1 = new SimpleDateFormat(
"dd.MM.yyyy hh:mm");
format2 = new SimpleDateFormat(
"День dd Месяц MM Год yyyy Время hh:mm");
System.out.println(
format1.format(d) // 25.02.2013 09:03
);
System.out.println(
format2.format(d)
// День 25 Месяц 02 Год 2013 Время 09:03
);
}
}
Для того, чтобы создать такой шаблон, пришлось использовать подобные параметры:
- dd – day;
- MM – название месяца;
- yyyy – год;
- hh – часы;
- mm – минуты.
Под видом разделителя можно применять современно разный текст. Тот, что разработчику приходится по вкусу больше всего.
Символика форматирования строк
SimpleDateFormat – это подкласс DateFormat, который дает возможность определять собственные шаблоны для вывода на экран даты и времени. Для реализации поставленной задачи принято использовать определенные символьные записи.
К ним относят:
- A – AM или PM (актуально для часов в 12-часовом «формате»);
- d – день месяца;
- D – день года;
- H – часы, которые работают в формате день/ночь;
- K – «суточные» часы;
- S – секунды;
- M – минуты;
- W – week of year;
- y – год;
- z – часовой пояс.
То, сколько раз повторяется конкретный символ, указывает на способ представления календарной информации. Так можно использовать записи yyyy-mm-dd и hh:mm:ss или yy-mm-dd и h:m:s. В первом случае будет запись типа 1994-01-15 и 20:45:15. Во втором, если требуется, перед соответствующей цифрой будет выводиться дополнительный 0.
Класс Calendar
Для того, чтобы работать с календарной информацией, разработчику предоставляют разнообразные методы. Есть абстрактный класс Calendar, которые умеет работать в пределах календаря с датами. Он может прибавлять дни, а также принимать во внимание високосные года. Дополнительно преобразовывает время (миллисекунды) в более удобном пользователю формате.
Реализация Calendar производится классом GregorianCalendar. Как и у Data конструктор будет возвращать календарь на текущий день. Но здесь допустимо задавать его явным образом. Достаточно прописать все параметры оного:
Здесь:
- areFieldsSet – указатель на то, были ли заданы компоненты времени;
- fields – массив целочисленных значений временных элементов;
- isSet – массив вида Boolean, который указывает на наличие специфического компонента «часов»;
- time (типа long) – текущее время элемента;
- isTimeSet – указатель на установку текущих «часов».
Данный вариант является весьма мощным, особенно если нужно вывести на экран полное название месяца или недели.
Методы
Для того, чтобы задействовать Calendar, необходимо запомнить следующие методы:
Формат даты можно менять при помощи соответствующего класса и различных типов данных. К ним относят следующие варианты:
- day_of_week – день недели;
- day_of_year – день года;
- day_of_month – месяц (день);
- week_of_month – неделя месяца;
- week_of_year – годовая неделя;
- Year – год;
- Calendar.ERA – эра.
С Day_of_week предстоит взаимодействовать, если хочется на календаре или в приложении вывести название конкретного дня недели.
Это – наглядный пример того, как можно использовать перечисленные типы информации на практике.
О классе GregorianCalendar
Используя текущую дату в Java, можно столкнуться с подклассом Calendar, который носит название GregorianCalendar. Он представляет Григорианский календарь. При помощи метода getInstance() происходит возврат объекта GregorianCalendar, инициированный нынешней датой и часами согласно региональным параметрам.
Класс имеет поля AD и BC. Первый вариант – до нашей эры, второй – наша эра. И дополнительно здесь предусматривается метод isLeapYear(). Отвечает за проверку високосности года. Выглядит так:
При применении подобной «операции», происходит проверка. Когда год является високосным, программа возвращает значение true.
Промежутки времени, которые нужны программисту, могут быть получены через метод get(). Вот пример того, каким образом удается уточнить месяц, содержащийся в заданной дате:
Корректировку объекта производят через set(). Данный пример помогает разобраться в принципах установки новой даты:
Сдвиг даты на тот или иной период производится через add():
А вот пример преобразований:
Здесь весьма полезными будут методы setTime() и getTime().
Класс TimeZone
TimeZone не позволяет «просто так» корректировать часы. Этот class используется только совместно с Calendar или DateFormat. Обладает следующими особенностями:
- относится к абстрактным – от него нельзя порождать объекты;
- для «порождения» применяется метод getDefault() – он возвращает экземпляр наследника с параметрами, скопированными из ОС;
- обладает статистическим методом getTimeZone, который отвечает за указание имени конкретного временного пояса;
- поля, отвечающие за параметризацию getTimeZone нигде не прописаны;
- присутствует статистический метод getAvailableIds(), который возвращает перечень возможных значений наименований временных зон типа string[];
- набор для параметризации может быть определен относительно Гринвича: string[] getAvailableIds(int offset).
Далее будет приведен образец программного кода, который последовательно поможет вывести на экран не часы, а временную зону по умолчанию, все варианты оного, а также те «территории», которые совпадают со временем «по Москве».
Выглядит этот код так:
import java.util.Arrays;
import java.util.TimeZone;
public class TimeZoneList
public static void main(String[] args) {
new TimeZoneList();
System.exit(0);
}
}
Данная кодификация работает так:
- Align – выравнивает отображение информации от «часов», заданных по Гринвичу;
- drawTimeZoneParam – параметры ТаймЗон;
- в конструкторе TimeZoneList определяется нынешняя TimeZone, далее осуществляется вывод всех вариантов, которые могут быть.
А еще метод getAvailableIDs позволит получить перечень TimeZone, у которых имеет место смещение по времени, совпадающее с текущей «территорией».
Всемирное координирование
В процессе программирования иногда недостаточно задействовать dates, days, time. Часто приходится пользоваться временным сдвигом, который относится к нестандартной деятельности человека. Пример – расписание поездов по России.
Для этого используется TimeZone UTC. UTC – это всемирное координирование времени. Заменяет Гринвич. В Джаве можно работать с Date для координации часов, но это – лишние манипуляции. При программировании они не нужны.
Ниже представлен наглядный пример применения TimeZone UTC. Здесь часы будут привязаны к одной из сторон (серверной), на компьютере устанавливаются различные «зональности». Для того, чтобы установить конкретный вариант, потребуется:
- обратиться к панели управления;
- открыть раздел «Data and Time»;
- выбрать TimeZone, которую хочется.
Код имеет следующую форму записи:
Применяются три TimeZone (current Zone). В двух вариантах (Москва и UTC) выводится в консоль:
- объект Data в состоянии «not formatted»;
- он же, но с форматирование и DateFormat/SimpleDateFormat.
Для того чтобы программа функционировала в конкретной временной зоне, требуется через SetDefault установить подходящий вариант в процессе обработки «времени».
В помощь программисту
Java позволяет работать с calendar day_of_week и другими параметрами календарного характера всем программистам. Чтобы облегчить понимание принципов взаимодействия, а также используемые formats и классы, стоит углубленно изучить Джаву.
Сделать это помогают специализированные курсы. Возможно очное и дистанционное обучение. Курсы рассчитаны на срок до года. По завершению выдаются сертификаты установленного образца. Во время занятий программерам объяснят, что такое формат даты, научат основам написания кодов на Джаве. Есть предложения не только для новичков, но и для тех, кто хочет улучшить свои навыки в Java. В процессе обучения можно общаться не только с коллегами, но и с опытными преподавателями.
package
com.example.customcalendar;
import
androidx.appcompat.app.AppCompatActivity;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.Toast;
import
org.naishadhparmar.zcustomcalendar.CustomCalendar;
import
org.naishadhparmar.zcustomcalendar.OnDateSelectedListener;
import
org.naishadhparmar.zcustomcalendar.Property;
import
java.util.Calendar;
import
java.util.HashMap;
public
class
MainActivity
extends
AppCompatActivity {
CustomCalendar customCalendar;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
customCalendar=findViewById(R.id.custom_calendar);
HashMap<Object, Property> descHashMap=
new
HashMap<>();
Property defaultProperty=
new
Property();
defaultProperty.layoutResource=R.layout.default_view;
defaultProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"default"
,defaultProperty);
Property currentProperty=
new
Property();
currentProperty.layoutResource=R.layout.current_view;
currentProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"current"
,currentProperty);
Property presentProperty=
new
Property();
presentProperty.layoutResource=R.layout.present_view;
presentProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"present"
,presentProperty);
Property absentProperty =
new
Property();
absentProperty.layoutResource=R.layout.absent_view;
absentProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"absent"
,absentProperty);
customCalendar.setMapDescToProp(descHashMap);
HashMap<Integer,Object> dateHashmap=
new
HashMap<>();
Calendar calendar= Calendar.getInstance();
dateHashmap.put(calendar.get(Calendar.DAY_OF_MONTH),
"current"
);
dateHashmap.put(
1
,
"present"
);
dateHashmap.put(
2
,
"absent"
);
dateHashmap.put(
3
,
"present"
);
dateHashmap.put(
4
,
"absent"
);
dateHashmap.put(
20
,
"present"
);
dateHashmap.put(
30
,
"absent"
);
customCalendar.setDate(calendar,dateHashmap);
customCalendar.setOnDateSelectedListener(
new
OnDateSelectedListener() {
@Override
public
void
onDateSelected(View view, Calendar selectedDate, Object desc) {
String sDate=selectedDate.get(Calendar.DAY_OF_MONTH)
+
"/"
+(selectedDate.get(Calendar.MONTH)+
1
)
+
"/"
+ selectedDate.get(Calendar.YEAR);
Toast.makeText(getApplicationContext(),sDate, Toast.LENGTH_SHORT).show();
}
});
}
}
package
com.example.customcalendar;
import
androidx.appcompat.app.AppCompatActivity;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.Toast;
import
org.naishadhparmar.zcustomcalendar.CustomCalendar;
import
org.naishadhparmar.zcustomcalendar.OnDateSelectedListener;
import
org.naishadhparmar.zcustomcalendar.Property;
import
java.util.Calendar;
import
java.util.HashMap;
public
class
MainActivity
extends
AppCompatActivity {
CustomCalendar customCalendar;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
customCalendar=findViewById(R.id.custom_calendar);
HashMap<Object, Property> descHashMap=
new
HashMap<>();
Property defaultProperty=
new
Property();
defaultProperty.layoutResource=R.layout.default_view;
defaultProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"default"
,defaultProperty);
Property currentProperty=
new
Property();
currentProperty.layoutResource=R.layout.current_view;
currentProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"current"
,currentProperty);
Property presentProperty=
new
Property();
presentProperty.layoutResource=R.layout.present_view;
presentProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"present"
,presentProperty);
Property absentProperty =
new
Property();
absentProperty.layoutResource=R.layout.absent_view;
absentProperty.dateTextViewResource=R.id.text_view;
descHashMap.put(
"absent"
,absentProperty);
customCalendar.setMapDescToProp(descHashMap);
HashMap<Integer,Object> dateHashmap=
new
HashMap<>();
Calendar calendar= Calendar.getInstance();
dateHashmap.put(calendar.get(Calendar.DAY_OF_MONTH),
"current"
);
dateHashmap.put(
1
,
"present"
);
dateHashmap.put(
2
,
"absent"
);
dateHashmap.put(
3
,
"present"
);
dateHashmap.put(
4
,
"absent"
);
dateHashmap.put(
20
,
"present"
);
dateHashmap.put(
30
,
"absent"
);
customCalendar.setDate(calendar,dateHashmap);
customCalendar.setOnDateSelectedListener(
new
OnDateSelectedListener() {
@Override
public
void
onDateSelected(View view, Calendar selectedDate, Object desc) {
String sDate=selectedDate.get(Calendar.DAY_OF_MONTH)
+
"/"
+(selectedDate.get(Calendar.MONTH)+
1
)
+
"/"
+ selectedDate.get(Calendar.YEAR);
Toast.makeText(getApplicationContext(),sDate, Toast.LENGTH_SHORT).show();
}
});
}
}
Improve Article
Save Article
Improve Article
Save Article
Calendar class in Java is an abstract class that provides methods for converting date between a specific instant in time and a set of calendar fields such as MONTH, YEAR, HOUR, etc. It inherits Object class and implements the Comparable, Serializable, Cloneable interfaces.
As it is an Abstract class, so we cannot use a constructor to create an instance. Instead, we will have to use the static method Calendar.getInstance() to instantiate and implement a sub-class.
- Calendar.getInstance(): return a Calendar instance based on the current time in the default time zone with the default locale.
- Calendar.getInstance(TimeZone zone)
- Calendar.getInstance(Locale aLocale)
- Calendar.getInstance(TimeZone zone, Locale aLocale)
Java program to demonstrate getInstance() method:
import
java.util.*;
public
class
Calendar1 {
public
static
void
main(String args[])
{
Calendar c = Calendar.getInstance();
System.out.println(
"The Current Date is:"
+ c.getTime());
}
}
Output:
The Current Date is:Tue Aug 28 11:10:40 UTC 2018
Important Methods and their usage
METHOD | DESCRIPTION |
---|---|
abstract void add(int field, int amount) | It is used to add or subtract the specified amount of time to the given calendar field, based on the calendar’s rules. |
int get(int field) | It is used to return the value of the given calendar field. |
abstract int getMaximum(int field) | It is used to return the maximum value for the given calendar field of this Calendar instance. |
abstract int getMinimum(int field) | It is used to return the minimum value for the given calendar field of this Calendar instance. |
Date getTime() | It is used to return a Date object representing this Calendar’s time value.</td |
Below programs illustrate the above methods:
Program 1: Java program to demonstrate get() method.
import
java.util.*;
public
class
Calendar2 {
public
static
void
main(String[] args)
{
Calendar calendar = Calendar.getInstance();
System.out.println(
"Current Calendar's Year: "
+ calendar.get(Calendar.YEAR));
System.out.println(
"Current Calendar's Day: "
+ calendar.get(Calendar.DATE));
System.out.println(
"Current MINUTE: "
+ calendar.get(Calendar.MINUTE));
System.out.println(
"Current SECOND: "
+ calendar.get(Calendar.SECOND));
}
}
Output:
Current Calendar's Year: 2018 Current Calendar's Day: 28 Current MINUTE: 10 Current SECOND: 45
Program 2: Java program to demonstrate getMaximum() method.
import
java.util.*;
public
class
Calendar3 {
public
static
void
main(String[] args)
{
Calendar calendar = Calendar.getInstance();
int
max = calendar.getMaximum(Calendar.DAY_OF_WEEK);
System.out.println(
"Maximum number of days in a week: "
+ max);
max = calendar.getMaximum(Calendar.WEEK_OF_YEAR);
System.out.println(
"Maximum number of weeks in a year: "
+ max);
}
}
Output:
Maximum number of days in a week: 7 Maximum number of weeks in a year: 53
Program 3: Java program to demonstrate the getMinimum() method.
import
java.util.*;
public
class
Calendar4 {
public
static
void
main(String[] args)
{
Calendar calendar = Calendar.getInstance();
int
min = calendar.getMinimum(Calendar.DAY_OF_WEEK);
System.out.println(
"Minimum number of days in week: "
+ min);
min = calendar.getMinimum(Calendar.WEEK_OF_YEAR);
System.out.println(
"Minimum number of weeks in year: "
+ min);
}
}
Output:
Minimum number of days in week: 1 Minimum number of weeks in year: 1
Program 4: Java program to demonstrate add() method.
import
java.util.*;
public
class
Calendar5 {
public
static
void
main(String[] args)
{
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, -
15
);
System.out.println(
"15 days ago: "
+ calendar.getTime());
calendar.add(Calendar.MONTH,
4
);
System.out.println(
"4 months later: "
+ calendar.getTime());
calendar.add(Calendar.YEAR,
2
);
System.out.println(
"2 years later: "
+ calendar.getTime());
}
}
Output:
15 days ago: Mon Aug 13 11:10:57 UTC 2018 4 months later: Thu Dec 13 11:10:57 UTC 2018 2 years later: Sun Dec 13 11:10:57 UTC 2020
Reference: https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
Афоризм
Склероз нельзя вылечить, но о нем можно забыть.
Поддержка проекта
Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
• Yandex.Деньги
410013796724260
• Webmoney
R335386147728
Z369087728698
Для удобной работы с датой и временем в Java используются классы Date и Calendar. Оба класса находятся в
библиотеке java.util. Класс TimeZone используется совместно с классами Calendar и DateFormat
Класс SimpleDateFormat является подклассом класса DateFormat и позволяет определять собственные шаблоны
форматирования для отображения даты и времени.
На странице рассмотрены следующие классы :
- форматирование SimpleDateFormat
- календарь Calendar
- григорианский календарь GregorianCalendar
- временная зона TimeZone
Класс Date
Класс Date хранит время в миллисекундах начиная с 1 января 1970 года. Данный класс имеет конструктор по умолчанию,
который возвращает текущее время. Кроме этого можно создать объект Date используя конструктор, который принимает количество
миллисекунд начиная с 1 января 1970 года. Для получения этого внутреннего времени используется метод getTime(). Кроме
этого уже после создания экземпляра класса можно изменить время с помощью setTime(long date).
Конструкторы класса Date :
Date() Date(long milliseconds)
Первый конструктор без параметров инициализирует объект текущей датой и временем. Во втором конструкторе можно
указать количество миллисекунд, прошедших с полуночи 1 января 1970 года.
Методы класса Date:
- boolean after(Date date) — если объект содержит более позднюю дату, чем указано в параметре date,
то возвращается true; - boolean before(Date date) — если объект содержит более раннюю дату, чем указано в параметре date,
то возвращается true; - int compareTo(Date date) — сравнивает даты. Возвращает 0, если совпадают, отрицательное значение — если
вызывающая дата более ранняя, положительное значение — если вызывающая дата более поздняя, чем в параметре; - boolean equals(Object object) — если даты совпадают, то возвращается true;
- long getTime() — возвращает количество миллисекунд, прошедших с полуночи 1 января 1970 года;
- void setTime(long milliseconds) — устанавливает время и дату в виде числа миллисекунд, прошедших с полночи
1 января 1970 года.
Простой пример использования Date для вывода даты в консоль.
Date date = new Date(); System.out.println(date.toString());
С помощью метода getTime() можно отобразить количество миллисекунд, прошедших с 1 января 1970 года.
Date date = new Date(); long millis = date.getTime(); System.out.println(String.valueOf(millis));
Класс SimpleDateFormat
Для того, чтобы отображать дату и время в удобном формате можно использовать класс SimpleDataFormat :
package ru.test; import java.util.Date; import java.text.SimpleDateFormat; public class Test { public void test() { Date d = new Date(); SimpleDateFormat format1; SimpleDateFormat format2; format1 = new SimpleDateFormat( "dd.MM.yyyy hh:mm"); format2 = new SimpleDateFormat( "День dd Месяц MM Год yyyy Время hh:mm"); System.out.println( format1.format(d) // 25.02.2013 09:03 ); System.out.println( format2.format(d) // День 25 Месяц 02 Год 2013 Время 09:03 ); } }
При создании шаблона представления даты SimpleDateFormat использовались следующие параметры :
- dd — означает день;
- MM — месяц;
- yyyy — год;
- hh — часы;
- mm — минуты;
В качестве разделитель можно использовать любой текст.
Класс SimpleDateFormat является подклассом класса DateFormat и позволяет определять
собственные шаблоны форматирования для отображения даты и времени.
Символы форматирования строки
- A — AM или PM
- d — день месяца (1-31)
- D — день в году (1-366)
- H — часы в формате AM/PM (1-12)
- K — часы в формате суток (1-24)
- M — минуты (0-59)
- S — секунды (0-59)
- W — неделя в году (1-53)
- y — год
- z — часовой пояс
Количество повторений символа определяет способ представления даты. Например, можно указать hh:mm:ss,
а можно h:m:s. В первом случае при необходимости для чисел 0..9 будет отображаться ноль перед цифрой.
Класс Calendar
В документации представлено множество методов для получения или установки отдельных компонентов времени и даты,
например, getMinutes()/setMinutes() и др. Все они являются устаревшими и вместо них следует использовать класс
Calendar.
Абстрактный класс Calendar позволяет работать с датой в рамках календаря, т.е он умеет прибавлять день, при этом
учитывать високосные год и прочее, а также позволяет преобразовать время в миллисекундах в более удобном виде — год, месяц,
день, часы, минуты, секунды. Единственной реализацией Calendar является класс GregorianCalendar, также как и у даты
конструктор по умолчанию возвращает календарь на текущий день, но можно задать его явно указав все параметры :
Пример использования классов Calendar и GregorianCalendar
import java.util.Date; import java.util.Calendar; import java.util.GregorianCalendar; import java.text.SimpleDateFormat; public class Test { public void test() { // календарь на текущую дату Calendar c = new GregorianCalendar(); // календарь на 21.12.2014 Calendar c2 = new GregorianCalendar(2014, 12, 21); // увеличиваем дату на 1 день c2.add(Calendar.DAY_OF_YEAR, 1); System.out.println(c2.getTime()); // 22.12.2014 // уменьшаем дату на 1 день c2.add(Calendar.DAY_OF_YEAR, -1); } }
Поля класса Calendar
- Переменная типа boolean с именем areFieldsSet указывает, были ли установлены компоненты времени.
- Переменная fields — это массив целочисленных значений, содержащий компоненты времени.
- Переменная isSet — массив типа boolean, указывающий, был ли установлен специфический компонент времени.
- Переменная time (тип long) содержит текущее время объекта.
- Переменная isTimeSet (тип boolean) указывает, что было установлено текущее время.
Методы класса Calendar
Наименование | Описание |
---|---|
abstract void add(int field, int value) | добавляет value к компоненту времени или даты, указанному в параметре field (например, Calendar.HOUR). Чтобы отнять, используйте отрицательное значение. |
boolean after(Object calendar) | возвращает значение true, если вызывающий объект класса Calendar содержит более позднюю дату, чем calendar. |
boolean before(Object calendar) | возвращает значение true, если вызывающий объект класса Calendar содержит более раннюю дату, чем calendar. |
final void clear() | обнуляет все компоненты времени в вызывающем объекте. |
final void clear(int field) | обнуляет компонент, указанный в параметре field |
int get(int field) | возвращает значение одного компонента, например, Calendar.MINUTE |
synchronized static Locale[] getAvailableLocales() | возвращает массив объектов класса Locale, содержащий региональные данные |
synchronized static Calendar getInstance() | возвращает объект класса Calendar для региональных данных и часового пояса по умолчанию. Есть и другие перегруженные версии. |
final Date getTime() | возвращает объекта класса Date, содержащий время, эквивалентное вызывающему объекту. |
TimeZone getTimeZone() | возвращает часовой пояс |
final boolean isSet(int field) | возвращает значение true, если указанный компонент времени указан. |
void set(int field, int value) | устанавливает компоненты даты или времени. Есть перегруженные версии. |
final void setTime(Date date) | устанавливает различные компоненты даты и времени через объект класса Date. |
void setTimeZone(TimeZone timezone) | устанавливает часовой пояс через объект класса TimeZone. |
Календарь достаточно мощный класс, который позволяет получать названия месяцев и дней недели, увеличивать или уменьшать
различные параметры текущей даты, а также получать их. Для удобства работы с ним нужно просто разобраться с типами данных,
с которыми он работает:
- DAY_OF_YEAR — день года (0- 365);
- DAY_OF_MONTH — день месяца( какой по счету день в месяце 0 — 31);
- WEEK_OF_MONTH — неделя месяца;
- WEEK_OF_YEAR — неделя в году;
- MONTH — номер месяца;
- Year — номер года;
- Calendar.ERA — эра.
Пример Calendar, GregorianCalendar
import java.util.Date; import java.util.Calendar; import java.util.GregorianCalendar; import java.text.SimpleDateFormat; public class Test { public void test() { // календарь на 25.01.2015 Calendar c = new GregorianCalendar(2015, 01, 25); System.out.println(c.get(Calendar.MONTH)); // 01 System.out.println(c.get(Calendar.YEAR)); // 2015 System.out.println( c.get(Calendar.DAY_OF_WEEK_IN_MONTH)); System.out.println( c.get(Calendar.DAY_OF_WEEK)); System.out.println( c.get(Calendar.DAY_OF_YEAR)); System.out.println( c.get(Calendar.DAY_OF_MONTH)); } }
Класс GregorianCalendar
Класс GregorianCalendar является подклассом Calendar, который представляет обычный Григорианский календарь.
Метод getInstance() класса Calendar обычно возвращает объект класса GregorianCalendar, инициированный текущей
датой и временем согласно региональным настройкам.
У класса есть два поля AD и BC — до нашей эры и наша эра.
Кроме стандартных методов, которые есть в классе Calendar, у GregorianCalendar есть метод isLeapYear()
для проверки високосного года:
boolean isLeapYear(int year)
Если год високосный, то возвращается true.
Отсчёт месяцев идёт от нуля, поэтому декабрь будет одиннадцатым месяцем. Чтобы не путаться с такими случаями,
проще использовать понятные константы:
GregorianCalendar calendar; calendar = new GregorianCalendar(2012,Calendar.DECEMBER,31);
А получать нужные отрезки времени можно через метод get (). Например, узнать, какой месяц содержится в
созданной нами дате можно так:
int month = calendar.get(Calendar.MONTH); System.out.println(month); // вернёт 11
Изменить состояние объекта можно через метод set (). Например, установим новую дату у нашего объекта.
GregorianCalendar calendar; calendar = new GregorianCalendar(2012,Calendar.DECEMBER,31); calendar.set(2013, Calendar.FEBRUARY, 23); // Убедимся, что возвращает 1 - февраль System.out.println(calendar.get(Calendar.MONTH));
Можно сдвинуть дату на определённый период с помощью метода add (). Отодвинем дату на два месяца.
GregorianCalendar calendar; calendar = new GregorianCalendar(2012,Calendar.DECEMBER,31); calendar.add(Calendar.MONTH, 2); System.out.println(calendar.get(Calendar.MONTH));
Методы getTime() и setTime() работают с объектами Date и полезны для преобразования.
GregorianCalendar calendar; calendar = new GregorianCalendar(year, month, day); Date hireDay = calendar.getTime();
Класс TimeZone
Класс TimeZone предназначен для совместного использования с классами Calendar и DateFormat.
Этот класс абстрактный, поэтому от него порождать объекты нельзя. Вместо этого определен статический метод getDefault(),
который возвращает экземпляр наследника TimeZone с настройками, взятыми из операционной системы, под управлением
которой работает JVM.
TimeZone имеет статический метод getTimeZone(String ID), используя который можно указать наименование
конкретного временного пояса, для которого необходимо получить объект TimeZone.
Набор полей, определяющих возможный набор параметров для getTimeZone, нигде явно не описывается. Но имеется
статический метод getAvailableIds(), возвращающий список возможных значений наименование временных зон типа
String[], который можно использовать в методе getTimeZone. Так можно определить набор возможных параметров для
конкретного временного пояса относительно Гринвича String[] getAvailableIds(int offset).
Рассмотрим пример, в котором на консоль последовательно выводятся:
— временная зона по умолчанию;
— список всех возможных временных зон;
— список временных зон, которые совпадают с временной зоной Москвы.
Пример получения списка TimeZone
import java.util.Arrays; import java.util.TimeZone; public class TimeZoneList { private final int hour = 1000 * 60 * 60; private final String TEMPL_TZ = "%s (%s)"; private final String TEMPL_OFFS = "hour offset=(%d)"; String align(String str, int len) { if (len - str.length() > 0){ char[] buf = new char[len - str.length()]; Arrays.fill (buf, ' '); return str + new String(buf); } else return str.substring(0, len); } private void drawTimeZoneParam(final TimeZone tz) { String line = null; line = String.format(TEMPL_TZ, tz.getID(), tz.getDisplayName()); line = align(line, 64); line += String.format(TEMPL_OFFS, tz.getRawOffset() / hour); System.out.println(line); } public TimeZoneList() { TimeZone tz = TimeZone.getDefault(); int rawOffset = tz.getRawOffset(); System.out.println("Текущая TimeZone : " + tz.getID() + " (" + tz.getDisplayName() + ")n"); // Display all available TimeZones System.out.println("Доступные TimeZonen"); String[] timezones = TimeZone.getAvailableIDs(); for (int cnt = 0; cnt < timezones.length; cnt++){ tz = TimeZone.getTimeZone(timezones[cnt]); drawTimeZoneParam(tz); } // All available TimeZones same as for Moscow System.out.println( "Список TimeZone, соответствующие текущей"); timezones = TimeZone.getAvailableIDs(rawOffset); for(int cnt = 0;cnt < timezones.length;cnt++){ tz = TimeZone.getTimeZone(timezones[cnt]); drawTimeZoneParam(tz); } } public static void main(String[] args) { new TimeZoneList(); System.exit(0); } }
Код программы несложный. Метод align выполняет выравнивание для отображения смещения по времени TimeZone
от среднего времени по Гринвичу GMT — времени меридиана, проходящего через прежнее место расположения
Гринвичской обсерватории около Лондона. Метод drawTimeZoneParam отображает параметры TimeZone.
В конструкторе класса TimeZoneList сначала определяется текущая TimeZone, после чего выводится список
возможных TimeZone. И в заключении, используя метод getAvailableIDs получаем список TimeZone,
у которых смещение по времени соответствует текущей зоне.
В результате работы программы в консоль будет выведена следующая информация (первый список в усеченном
виде):
Текущая TimeZone : Europe/Moscow (Moscow Standard Time) Доступные TimeZone Etc/GMT+12 (GMT-12:00) hour offset=(-12) Etc/GMT+11 (GMT-11:00) hour offset=(-11) Pacific/Midway (Samoa Standard Time) hour offset=(-11) Pacific/Niue (Niue Time) hour offset=(-11) Pacific/Pago_Pago (Samoa Standard Time) hour offset=(-11) Pacific/Samoa (Samoa Standard Time) hour offset=(-11) US/Samoa (Samoa Standard Time) hour offset=(-11) . . . Список TimeZone, соответствующие текущей Asia/Baku (Azerbaijan Time) hour offset=(4) Asia/Dubai (Gulf Standard Time) hour offset=(4) Asia/Muscat (Gulf Standard Time) hour offset=(4) Asia/Tbilisi (Georgia Time) hour offset=(4) Asia/Yerevan (Armenia Time) hour offset=(4) Etc/GMT-4 (GMT+04:00) hour offset=(4) Europe/Moscow (Moscow Standard Time) hour offset=(4) Europe/Samara (Samara Time) hour offset=(4) Europe/Simferopol (Moscow Standard Time) hour offset=(4) Europe/Volgograd (Volgograd Time) hour offset=(4) Indian/Mahe (Seychelles Time) hour offset=(4) Indian/Mauritius (Mauritius Time) hour offset=(4) Indian/Reunion (Reunion Time) hour offset=(4) NET (Armenia Time) hour offset=(4) W-SU (Moscow Standard Time) hour offset=(4)
TimeZone UTC
В практике не часто приходится использовать различные TimeZone. Задачи, где разработчику приходится учитывать
временной сдвиг, относятся к специфической деятельности человечества. Так, например, в расписании движения
пассажирских поездов РФ указывается привязка к московскому и местному времени. А по какому времени ведет пассажирский
состав машинист дальнего следования? Эта несложная задача решается в рамках министерства ЖД транспорта. Если состав
выходит за пределы страны, то время движения (расписание) должно быть согласовано с соответствующей стороной. Аналогично
это касается и полетов воздушного транспорта, где все согласования между различными аэропортами выполняются по времени
UTC — всеми́рное координи́рованное вре́мя (Coordinated Universal Time).
UTC было введено вместо устаревшего среднего времени по Гринвичу (GMT), поскольку GMT является неравномерной шкалой
и связана с суточным вращением Земли. Шкала UTC основана на равномерной шкале атомного времени и является более удобной
для гражданского использования.
Как может влиять TimeZone, с точки зрения разработчика, на результаты работы программы? Давайте представим
себе ситуацию, что время формируется на сервере (объект типа Date) и отправляется удаленному пользователю по сети. Это
типично для WEB-приложений, у которых сервер и пользователи (браузеры) могут быть расположены в разных временных зонах.
Для отправки объекта Date по сети (Internet) используется сериализация, позволяющая
упаковать объект в набор байт на сервере и восстановить объект типа Date на клиенте (браузере). И вот здесь Вас может
ожидать «засада». Если сервер и клиент имеют разные TimeZone (часовые пояса), то на клиенте будет восстановлен
объект Date с временем сервера. И наоборот, если объект будет отправлен с клиента на сервер, то на сервере объект
десериализуется с временем клиента.
Конечно, объект Date можно конвертировать не сервере в текстовый вид, используя DateFormat, и на клиенте его
восстановить. Но Java позволяет учитывать различные TimeZone, не оказывающие влияние на сериализацию/десериализацию
объектов типа Date.
Давайте рассмотрим пример TimeZoneExample (код представлен ниже), в котором время будем привязывать к одной из сторон
(желательно серверной), а на компьютере устанавливать различные зоны (UTC, Москва, Владивосток). Для установки определенной
временной зоны необходимо открыть в панели управления окно «Date and Time» и выбрать соответствующую TimeZone.
import java.util.Date; import java.util.TimeZone; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; public class TimeZoneExample { private final String TIMEZONE_utc ; private final String TIMEZONE_msc ; private final String DATETIME_format; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public TimeZoneExample() { // TimeZone.setDefault( // TimeZone.getTimeZone(TIMEZONE_utc)); TIMEZONE_utc = "UTC"; TIMEZONE_msc = "Europe/Moscow"; DATETIME_format = "yyyy-MM-dd HH:mm:ss.SS"; Date date = new Date(); Date dt_msk = null; TimeZone tm_curr = TimeZone.getDefault(); System.out.println ("Current TimeZone : "" + tm_curr.getID() + "" (" + tm_curr.getDisplayName() + ")"); System.out.println ("useDaylightTime : " + tm_curr.useDaylightTime() + "n"); TimeZone tm_utc; TimeZone tm_msk; tm_utc = TimeZone.getTimeZone(TIMEZONE_utc); tm_msk = TimeZone.getTimeZone(TIMEZONE_msc); DateFormat df_utc; DateFormat df_msk; df_utc = new SimpleDateFormat(DATETIME_format); df_msk = new SimpleDateFormat(DATETIME_format); df_utc.setTimeZone(tm_utc); df_msk.setTimeZone(tm_msk); String date_utc = df_utc.format(date); String date_msk = df_msk.format(date); try { dt_msk = df_msk.parse(date_msk); } catch (ParseException e) {} System.out.println ("UTCn" + date); System.out.println (date_utc); System.out.println (tm_utc.getRawOffset()); System.out.println (); System.out.println ("Moscown" + dt_msk); System.out.println (date_msk); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public static void main(String[] args) { new TimeZoneExample(); System.exit(0); } }
В примере используется три TimeZone (tm_curr, tm_utc, tm_msk — текущая, зона UTC, зона Москвы).
Для двух временных зон (tm_utc, tm_msk) выводим в консоль объект Date без форматирования и с форматированием
с использованием tm_utc, tm_msk и DateFormat/SimpleDateFormat.
Первоначально на компьютере устанавливаем зону UTC и получаем в консоли следующий текст :
Current TimeZone : "UTC" (Coordinated Universal Time) useDaylightTime : false UTC Fri Dec 23 08:50:24 UTC 2016 2016-12-23 08:50:24.547 Moscow Fri Dec 23 08:50:24 UTC 2016 2016-12-23 11:50:24.547
Здесь следует сказать, что для зоны UTC и для зоны Москвы неформатированные даты (date, dt_msk) совпадают,
но вот с учетом временной зоны форматированные даты отличаются на соответствующие 3 часа.
Теперь установим зону на компьютере зону Москвы и получим в консоли следующий текст :
Current TimeZone : "Europe/Moscow" (Moscow Standard Time) useDaylightTime : false UTC Fri Dec 23 11:51:18 MSK 2016 2016-12-23 08:51:18.915 Moscow Fri Dec 23 11:51:18 MSK 2016 2016-12-23 11:51:18.915
Все как по науке — смещения по времени для дат UTC и Москвы поменялись местами. В заключении устанавливаем
временную зону Владивостока :
Current TimeZone : "Asia/Vladivostok" (Vladivostok Time) useDaylightTime : false UTC Fri Dec 23 19:55:35 VLAT 2016 2016-12-23 09:55:35.924 Moscow Fri Dec 23 19:55:35 VLAT 2016 2016-12-23 12:55:35.924
Все соответствует действительности — объект даты создается во временной зоне Владивостока. Время для TimeZone
Москвы и UTC соответствуют.
Если приложение должно работать в определенной временной зоне TimeZone, то можно, используя метод setDefault
класса TimeZone, установить соответствующую временную зону в приложении при работе с датой. В примере можно было
бы снять комментарий с первой строки и установить сответствующую временную зону в приложении, не оказывая влияния
на временную зону в настройках компьютера.
Скачать исходный код примера
Исходный код рассмотренных примеров можно скачать здесь (6.69 Кб).
Наверх