При работе с датами периодически приходится определять первый и последний день месяца по дате. Этим мы сейчас и займемся.
Для усечения даты в PostgreSQL есть функция date_trunc(поле, значение)
. Работает она аналогично функции trunc
для чисел.
SELECT date_trunc('day', timestamp '2023-02-17 13:25')
# | date_trunc |
---|---|
1 | 2023-02-17 00:00:00 |
Первый параметр функции date_trunc
может принимать значения:
- microseconds
- milliseconds
- second
- minute
- hour
- day
- week
- month
- quarter
- year
- decade
- century
- millennium
Первый день месяца
С помощью функции date_trunc
мы можем легко определить первый день месяца:
SELECT date_trunc('month', timestamp '2023-02-17 13:25')
# | date_trunc |
---|---|
1 | 2023-02-01 00:00:00 |
При желании можно привести результат к дате:
SELECT date_trunc('month', timestamp '2023-02-17 13:25')::date
# | date_trunc |
---|---|
1 | 2023-02-01 |
Первый день месяца можно получить преобразовав исходную дату в строку с годом и месяцем, а затем сделать обратное преобразование в дату, добавив 1-е число.
SELECT (to_char(timestamp '2023-02-17 13:25', 'YYYY-MM') || '-01')::date
# | date |
---|---|
1 | 2023-02-01 |
Последний день месяца
С последним днем месяца дела обстоят немножко сложнее. В месяце может быть от 28 до 31 дней в зависимости от месяца и года. Просто так подставить число в строку не получится.
На помощь нам придет получение первого числа месяца и добавление интервала в один месяц.
SELECT date_trunc('month', timestamp '2023-02-17 13:25') + interval '1 month' AS result
# | result |
---|---|
1 | 2023-03-01 00:00:00 |
Так мы получаем первое число следующего месяца. Теперь нам достаточно отнять один день и мы получим последний день текущего месяца:
SELECT date_trunc('month', timestamp '2023-02-17 13:25') + interval '1 month -1 day' AS result
# | result |
---|---|
1 | 2023-02-28 00:00:00 |
Итоговый запрос для получения дат первого и последнего дней месяца:
SELECT date_trunc('month', timestamp '2023-02-17 13:25') AS start,
date_trunc('month', timestamp '2023-02-17 13:25') + interval '1 month -1 day' AS end
# | start | end |
---|---|---|
1 | 2023-02-01 00:00:00 | 2023-02-28 00:00:00 |
Добавление месяцев
Стоит отметить, как работает добавление месяцев к дате.
Если в исходной дате день месяца с 1 по 28, то в результате будет этот же день месяца.
SELECT timestamp '2023-02-17 13:25' + interval '1 month'
# | ?column? |
---|---|
1 | 2023-03-17 13:25:00 |
Для дней с 29 по 31 может получиться так, что после добавления нужного количества месяцев этого же числа не будет в месяце результата. В этом случае будет взят последний день месяца.
Например, к 31 января добавляем 1 месяц. 31 февраля не существует, поэтому результатом будет последний день февраля - 28 февраля (или 29 для високосного года).
SELECT date '2023-01-31' + interval '1 month'
# | ?column? |
---|---|
1 | 2023-02-28 00:00:00 |
Для високосного года:
SELECT date '2024-01-31' + interval '1 month'
# | ?column? |
---|---|
1 | 2024-02-29 00:00:00 |
Определение начала и конца года
Аналогично определению первого и последнего дня месяца можно найти первый и последний день года по дате.
SELECT date_trunc('year', timestamp '2023-02-17 13:25') AS start,
date_trunc('year', timestamp '2023-02-17 13:25') + interval '1 year -1 day' AS end
# | start | end |
---|---|---|
1 | 2023-01-01 00:00:00 | 2023-12-31 00:00:00 |