Работа с датами и временем — одна из самых распространенных задач в программировании на Java․ Часто разработчикам требуется получить временной диапазон для выборки записей из базы данных, формирования отчетов или фильтрации коллекций․ В этой статье мы подробно разберем, как получить начальную и конечную даты последнего месяца, используя классический класс Calendar, а также рассмотрим более современные подходы, появившиеся в Java 8․
Использование класса Calendar (Java 7 и старше)
До выхода Java 8 основным инструментом для манипуляций с датами был класс java․util․Calendar․ Несмотря на то, что он считается устаревшим и имеет ряд известных недостатков (таких как изменяемость объектов и индексация месяцев с нуля), он до сих пор встречается во многих legacy-проектах․
Чтобы получить диапазон дат за последний месяц, нам нужно выполнить следующие шаги:
- Получить текущий экземпляр календаря․
- Откатить месяц на один назад․
- Установить первый день месяца и начальное время (00:00:00)․
- Получить конец месяца и установить максимальное время (23:59:59)․
Пример кода с Calendar
Ниже приведен подробный пример, как это можно реализовать:
Важно помнить: В классе Calendar месяцы нумеруются с нуля (январь — 0, декабрь — 11)․ Класс Calendar автоматически обрабатывает переполнение, поэтому если текущий месяц январь (0), то вычитание единицы корректно переведет дату на декабрь предыдущего года․
import java․util․Calendar;
import java․text․SimpleDateFormat;
import java․util․Date;
public class LastMonthCalendarExample {
public static void main(String[] args) {
// Получаем текущую дату
Calendar calendar = Calendar․getInstance;
// Откатываемся на один месяц назад
calendar․add(Calendar․MONTH, -1);
// Устанавливаем первый день месяца
calendar․set(Calendar․DAY_OF_MONTH, 1);
// Сбрасываем время на начало дня (00:00:00․000)
calendar․set(Calendar․HOUR_OF_DAY, 0);
calendar․set(Calendar․MINUTE, 0);
calendar․set(Calendar․SECOND, 0);
calendar․set(Calendar․MILLISECOND, 0);
Date startOfLastMonth = calendar․getTime;
// Переходим к последнему дню месяца
calendar․set(Calendar․DAY_OF_MONTH, calendar․getActualMaximum(Calendar․DAY_OF_MONTH));
// Устанавливаем конец дня (23:59:59․999)
calendar․set(Calendar․HOUR_OF_DAY, 23);
calendar․set(Calendar․MINUTE, 59);
calendar․set(Calendar․SECOND, 59);
calendar․set(Calendar․MILLISECOND, 999);
Date endOfLastMonth = calendar․getTime;
// Форматируем вывод для наглядности
SimpleDateFormat format = new SimpleDateFormat("dd․MM․yyyy HH:mm:ss");
System․out․println("Начало последнего месяца: " + format․format(startOfLastMonth));
System․out․println("Конец последнего месяца: " + format․format(endOfLastMonth));
}
}
Современный подход: Java 8 и java․time
Начиная с Java 8, был введен новый API java․time (JSR 310), который лишен недостатков Calendar․ Если вы работаете с современными версиями Java, настоятельно рекомендуется использовать классы LocalDate и LocalDateTime․
Для получения первого и последнего дня месяца в новом API используются специальные корректоры — TemporalAdjusters․
Пример с LocalDate и TemporalAdjusters
import java․time․LocalDate; import java․time․LocalDateTime; import java․time․LocalTime; import java․time․format․DateTimeFormatter; import java․time․temporal․TemporalAdjusters; public class LastMonthJavaTimeExample { public static void main(String[] args) { // Текущая дата LocalDate today = LocalDate․now; // Откатываемся на месяц назад LocalDate lastMonth = today․minusMonths(1); // Получаем первый день прошлого месяца LocalDate firstDay = lastMonth․withDayOfMonth(1); // Получаем последний день прошлого месяца LocalDate lastDay = lastMonth․with(TemporalAdjusters․lastDayOfMonth); // Если нужны точные временные метки (например, для БД) LocalDateTime startDateTime = LocalDateTime․of(firstDay, LocalTime․MIN); // 00:00:00 LocalDateTime endDateTime = LocalDateTime;of(lastDay, LocalTime․MAX); // 23:59:59․999999999 DateTimeFormatter formatter = DateTimeFormatter․ofPattern("dd․MM․yyyy HH:mm:ss"); System․out․println("Начало: " + startDateTime․format(formatter)); System․out․println("Конец: " + endDateTime․format(formatter)); } }Практическое применение: Фильтрация записей
Получив временной диапазон, вы можете использовать его для фильтрации списка записей․ Допустим, у нас есть список объектов с полем
creationDate, и мы хотим оставить только те, которые были созданы в прошлом месяце․Пример фильтрации
import java․util․ArrayList; import java․util․List; import java․util․Calendar; import java․util․Date; public class RecordFilter { public static void main(String[] args) { // Получаем границы прошлого месяца (используем код из примера выше) Calendar cal = Calendar․getInstance; cal․add(Calendar․MONTH, -1); cal․set(Calendar․DAY_OF_MONTH, 1); cal․set(Calendar․HOUR_OF_DAY, 0); cal․set(Calendar․MINUTE, 0); cal․set(Calendar․SECOND, 0); Date startDate = cal․getTime; cal․set(Calendar․DAY_OF_MONTH, cal․getActualMaximum(Calendar․DAY_OF_MONTH)); cal․set(Calendar․HOUR_OF_DAY, 23); cal․set(Calendar․MINUTE, 59); cal․set(Calendar․SECOND, 59); Date endDate = cal․getTime; // Список записей (заполняем тестовыми данными) List<Record> records = getTestRecords; // Фильтруем List<Record> lastMonthRecords = new ArrayList<>; for (Record record : records) { // Проверяем, попадает ли дата записи в диапазон if (!record․getCreationDate․before(startDate) && !record․getCreationDate․after(endDate)) { lastMonthRecords․add(record); } } System․out․println("Найдено записей за последний месяц: " + lastMonthRecords․size); } // Заглушка для метода получения записей static List<Record> getTestRecords { return new ArrayList<>; } } // Простой класс записи class Record { private Date creationDate; public Date getCreationDate { return creationDate; } public void setCreationDate(Date date) { this․creationDate = date; } }Получение записей за определенный период, базовая задача, решение которой зависит от версии Java, которую вы используете․
Если вы поддерживаете старый код, класс Calendar в связке с методами
addиgetActualMaximumпоможет вам получить нужные границы․ Однако для новых проектов однозначно стоит выбирать java․time, так как он предоставляет более безопасный, читаемый и мощный функционал для работы с временными интервалами․