Класс Calendar в Java

Класс Calendar — это абстрактный класс в Java для работы с датами и временем. Он находится вjava.utilпакете. Этот класс предоставляет ряд методов для работы с полями даты и времени (такими как год, месяц, день, час, минута и т. д.) и позволяет выполнять вычисления и сравнения дат.

Зачем нужен класс Calendar?

В Java, хотя класс Date также может представлять даты и время, он имеет следующие ограничения:

  1. Большинство методов устарело
  2. Не поддерживает интернационализацию
  3. Ограниченная функциональность вычисления дат

Класс Calendar решает эти проблемы и предоставляет более мощные и гибкие возможности работы с датой и временем.


Базовое использование класса Calendar

Получение экземпляра Calendar

Поскольку Calendar — абстрактный класс, мы не можем создать его экземпляр напрямую. Стандартный способ получения экземпляра Calendar:

Пример

Calendar calendar = Calendar.getInstance();

Этот метод возвращает экземпляр Calendar (обычно GregorianCalendar) на основе часового пояса и локали по умолчанию.

Установка даты и времени

Мы можем использоватьset()метод для установки различных полей объекта Calendar:

Пример

// Установить год, месяц и день
calendar.set(2023, Calendar.NOVEMBER, 15);

// Установить год, месяц, день, час, минуту и секунду
calendar.set(2023, Calendar.NOVEMBER, 15, 14, 30, 0);

Примечание: нумерация месяцев начинается с нуля: 0 соответствует январю, а 11 — декабрю. Чтобы избежать путаницы, рекомендуется использовать константы, определённые в классе Calendar (например, Calendar.JANUARY, Calendar.FEBRUARY и т. д.).

Получение информации о дате и времени

Используйтеget()метод для получения различных полей объекта Calendar:

Пример

int year = calendar.get(Calendar.YEAR);       // Получить год
int month = calendar.get(Calendar.MONTH);     // Получить месяц (0-11)
int day = calendar.get(Calendar.DAY_OF_MONTH);// Получить день
int hour = calendar.get(Calendar.HOUR_OF_DAY);// Получить час (24-часовой формат)
int minute = calendar.get(Calendar.MINUTE);   // Получить минуту
int second = calendar.get(Calendar.SECOND);   // Получить секунду

Общие методы класса Calendar

Вычисление даты

Класс Calendar предоставляет удобные методы вычисления даты:

Пример

// Добавить 10 дней к текущей дате
calendar.add(Calendar.DAY_OF_MONTH, 10);

// Вычесть 3 месяца из текущего месяца
calendar.add(Calendar.MONTH, -3);

Сравнение дат

Мы можем использоватьcompareTo()метод для сравнения двух объектов Calendar:

Пример

Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal2.add(Calendar.DAY_OF_MONTH, 1);

int result = cal1.compareTo(cal2);
// result < 0 означает, что cal1 раньше, чем cal2
// result == 0 означает, что cal1 равен cal2
// result > 0 означает, что cal1 позже, чем cal2

Получение временной метки

Вы можете использоватьgetTimeInMillis()метод для получения временной метки (в миллисекундах), представленной объектом Calendar:

Пример

long timestamp = calendar.getTimeInMillis();

Вы также можете использоватьgetTime()метод, чтобы преобразовать его в объект Date:

Пример

Date date = calendar.getTime();

Расширенное использование класса Calendar

Установка часового пояса

Мы можем задать конкретный часовой пояс для объекта Calendar:

Пример

TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
calendar.setTimeZone(timeZone);

Операции с полями Calendar

Класс Calendar предоставляетroll()метод, который может прокрутить поле, не затрагивая другие поля:

Пример

// 添加月份,但不改变年份
calendar.roll(Calendar.MONTH, true);  // Or calendar.roll(Calendar.MONTH, 1);

获取一周的第一天

不同地区对一周的第一天定义不同(有些使用周日,有些使用周一):

Пример

int firstDayOfWeek = calendar.getFirstDayOfWeek();

综合示例

Пример

import java.util.Calendar;
import java.util.GregorianCalendar;
import java.text.SimpleDateFormat;

public class CalendarDemo {
    public static void main(String[] args) {
        // 1. 获取一个 Calendar 实例(默认使用当前日期和时间)
        Calendar calendar = Calendar.getInstance();
       
        // 2. 获取各个字段的值
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1; // Месяц начинается с 0, поэтому добавьте 1
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int hour = calendar.get(Calendar.HOUR_OF_DAY); // 24-часовой формат
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
       
        System.out.printf("Текущее время: %d год %d месяц %d день %d:%d:%d%n",
                        year, month, day, hour, minute, second);
       
        // 3. Установите конкретную дату и время
        calendar.set(2023, Calendar.MAY, 15, 10, 30, 0); // 15 мая 2023 г. 10:30:00
       
        // 4. Используйте SimpleDateFormat для форматированного вывода
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Время после установки: " + sdf.format(calendar.getTime()));
       
        // 5. Арифметика с датами
        calendar.add(Calendar.DAY_OF_MONTH, 5); // Добавить 5 дней
        calendar.add(Calendar.HOUR, -3); // Вычесть 3 часа
       
        System.out.println("Время после вычисления: " + sdf.format(calendar.getTime()));
       
        // 6. Сравнить даты
        Calendar anotherCalendar = new GregorianCalendar(2023, Calendar.JUNE, 1);
        System.out.println("Результат сравнения: " +
            (calendar.before(anotherCalendar) ? "до" : "после"));
       
        // 7. Получить день недели (воскресенье=1, суббота=7)
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        System.out.println("День недели" + getChineseWeekday(dayOfWeek));
    }
   
    private static String getChineseWeekday(int dayOfWeek) {
        String[] weekdays = {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
        return weekdays[dayOfWeek];
    }
}

Результат вывода:

当前时间: 2023年5月15日 14:25:36
设置后的时间: 2023-05-15 10:30:00
运算后的时间: 2023-05-20 07:30:00
比较结果: 之前
星期二

Замечания о классе Calendar

  1. Месяцы нумеруются с нуля: В классе Calendar месяцы нумеруются с нуля (0=январь, 11=декабрь), что легко может привести к ошибкам.

  2. Изменяемость: Объекты Calendar изменяемы; изменение одного объекта Calendar влияет на все места, которые ссылаются на него.

  3. Потокобезопасность: Класс Calendar не является потокобезопасным, и в многопоточных средах требуется дополнительная синхронизация.

  4. Производительность: Частое создание экземпляров Calendar влияет на производительность; подумайте о повторном использовании экземпляров.

  5. Проблемы с часовым поясом: По умолчанию используется системный часовой пояс, и для приложений, работающих в нескольких часовых поясах, требуется особое внимание.


Альтернатива в Java 8

Начиная с Java 8, новый API даты и времени (java.timepackage) был представлен, обеспечивая более современный и удобный способ работы с датами и временем. Если вы используете Java 8 или новее, рекомендуется отдавать предпочтение новому API:

Пример

// Новый API для замены Calendar
LocalDate date = LocalDate.now();
LocalDateTime dateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now();

Новый API решает многие проблемы класса Calendar, включая лучшую потокобезопасность, более интуитивный дизайн API и более мощную функциональность.


Общие методы класса Java Calendar

Ниже приведены общие методы класса java.util.Calendar:

Основные методы

Метод Описание Пример
static Calendar getInstance() Получает экземпляр Calendar с часовым поясом и локалью по умолчанию Calendar cal = Calendar.getInstance()
static Calendar getInstance(TimeZone zone) Получает экземпляр Calendar с указанным часовым поясом Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"))
static Calendar getInstance(Locale locale) Получает экземпляр Calendar с указанной локалью Calendar cal = Calendar.getInstance(Locale.CHINA)
static Calendar getInstance(TimeZone zone, Locale locale) Получает экземпляр Calendar с указанными часовым поясом и локалью Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"), Locale.CHINA)

Константы полей (основные)

Поле Описание Диапазон значений
Calendar.YEAR Поле года -
Calendar.MONTH Поле месяца 0-11 (0 означает январь)
Calendar.DATEилиCalendar.DAY_OF_MONTH Количество дней в месяце 1-31
Calendar.DAY_OF_WEEK День недели 1-7 (1 означает воскресенье)
Calendar.HOUR Час в 12-часовом формате 0-11
Calendar.HOUR_OF_DAY Час в 24-часовом формате 0-23
Calendar.MINUTE Минуты 0-59
Calendar.SECOND second 0-59
Calendar.MILLISECOND Миллисекунды 0-999
Calendar.AM_PM AM или PM 0 (AM) или 1 (PM)

Методы операций с датой и временем

Метод Описание Пример
int get(int field) Получить значение указанного поля int year = cal.get(Calendar.YEAR)
void set(int field, int value) Установить значение указанного поля cal.set(Calendar.MONTH, 5)(установить на июнь)
void set(int year, int month, int date) Установить год, месяц, день cal.set(2023, 5, 15)(15 июня 2023)
void set(int year, int month, int date, int hourOfDay, int minute) Установить год, месяц, день, час, минуту cal.set(2023, 5, 15, 14, 30)
void set(int year, int month, int date, int hourOfDay, int minute, int second) Установить год, месяц, день, час, минуту, секунду cal.set(2023, 5, 15, 14, 30, 45)
void add(int field, int amount) Добавить или вычесть указанное количество времени cal.add(Calendar.DATE, 5)(добавить 5 дней)
void roll(int field, int amount) Добавить или вычесть количество времени без изменения более крупных полей cal.roll(Calendar.DATE, 5)(изменяет только поле дня)

Методы сравнения времени

Метод Описание Пример
boolean after(Object when) Определить, находится ли этот Calendar после указанного времени cal1.after(cal2)
boolean before(Object when) Определить, находится ли этот Calendar до указанного времени cal1.before(cal2)
int compareTo(Calendar anotherCalendar) Сравнить хронологический порядок двух объектов Calendar cal1.compareTo(cal2)

Другие полезные методы

Метод Описание Пример
long getTimeInMillis() Вернуть значение времени этого Calendar (в миллисекундах) long millis = cal.getTimeInMillis()
void setTimeInMillis(long millis) Установить Calendar с заданным значением времени в миллисекундах cal.setTimeInMillis(1626345600000L)
Date getTime() Вернуть объект Date, представляющий значение времени этого Calendar Date date = cal.getTime()
void setTime(Date date) Установить время Calendar с помощью заданного Date cal.setTime(new Date())
void clear() Очистить все значения полей cal.clear()
void clear(int field) Очистить значение указанного поля cal.clear(Calendar.HOUR)
boolean isSet(int field) Определить, установлено ли указанное поле if(cal.isSet(Calendar.YEAR))
Другие расширения