Open1
DuckDBメモ
日付関連
とりあえずよく使うやつ。
SELECT
first_day: date_trunc('month', '2025-03-23'::date),
last_day: last_day('2025-03-23'::date);
┌────────────┬────────────┐
│ first_day │ last_day │
│ date │ date │
├────────────┼────────────┤
│ 2025-03-01 │ 2025-03-31 │
└────────────┴────────────┘
前月末とか翌月末とかが必要な場合は '1 month'::INTERVAL
を必要な分だけ足し引きしてやれば良い。ちなみに '1 month'::INTERVAL
の整数倍で足し引きする限りにおいては月の日数の違いは良い感じに扱ってくれるので助かる。
SELECT
last_month: base_date - '1 month'::interval,
base_date,
next_month: base_date + '1 month'::interval,
FROM (values
('2025-03-01'::date),
('2025-03-14'::date),
('2025-03-31'::date), -- ←この前後の日付に注目
) t(base_date);
┌─────────────────────┬────────────┬─────────────────────┐
│ last_month │ base_date │ next_month │
│ timestamp │ date │ timestamp │
├─────────────────────┼────────────┼─────────────────────┤
│ 2025-02-01 00:00:00 │ 2025-03-01 │ 2025-04-01 00:00:00 │
│ 2025-02-14 00:00:00 │ 2025-03-14 │ 2025-04-14 00:00:00 │
│ 2025-02-28 00:00:00 │ 2025-03-31 │ 2025-04-30 00:00:00 │
└─────────────────────┴────────────┴─────────────────────┘
マクロ定義
DuckDBでは関数みたいな感じでマクロが定義できる。引数の数の違いでオーバーロードしたりデフォルト値の指定や名前付き引数なども使える。
試しに前月末日、翌月1日、翌月末日、とか経理でよく使う日付を取得するマクロを定義してみる。
-- 月の初日を返すマクロ
CREATE OR REPLACE MACRO first_day_of_month
() AS date_trunc('month', current_date)::DATE,
(month_offset) AS date_trunc('month', current_date + month_offset * INTERVAL 1 month)::DATE,
(month_offset, base_date) AS date_trunc('month', base_date + month_offset * INTERVAL 1 month)::DATE;
-- 月の最終日を返すマクロ
CREATE OR REPLACE MACRO last_day_of_month
() AS last_day(current_date)::DATE,
(month_offset) AS last_day(current_date + month_offset * INTERVAL 1 month)::DATE,
(month_offset, base_date) AS last_day(base_date + month_offset * INTERVAL 1 month)::DATE;
-- 月の日数を返すマクロ
CREATE OR REPLACE MACRO days_of_month
() AS date_part('day', last_day_of_month()),
(month_offset) AS date_part('day', last_day_of_month(month_offset)),
(month_offset, base_date) AS date_part('day', last_day_of_month(month_offset, base_date));
-- 試しに使ってみる
SELECT
month_offset,
base_date: current_date + month_offset * INTERVAL 1 month,
first_day_of_month: first_day_of_month(month_offset),
last_day_of_month: last_day_of_month(month_offset),
days_of_month: days_of_month(month_offset)
FROM generate_series(-2, 2) as t(month_offset);
┌──────────────┬─────────────────────┬────────────────────┬───────────────────┬───────────────┐
│ month_offset │ base_date │ first_day_of_month │ last_day_of_month │ days_of_month │
│ int64 │ timestamp │ date │ date │ int64 │
├──────────────┼─────────────────────┼────────────────────┼───────────────────┼───────────────┤
│ -2 │ 2025-01-23 00:00:00 │ 2025-01-01 │ 2025-01-31 │ 31 │
│ -1 │ 2025-02-23 00:00:00 │ 2025-02-01 │ 2025-02-28 │ 28 │
│ 0 │ 2025-03-23 00:00:00 │ 2025-03-01 │ 2025-03-31 │ 31 │
│ 1 │ 2025-04-23 00:00:00 │ 2025-04-01 │ 2025-04-30 │ 30 │
│ 2 │ 2025-05-23 00:00:00 │ 2025-05-01 │ 2025-05-31 │ 31 │
└──────────────┴─────────────────────┴────────────────────┴───────────────────┴───────────────┘
ログインするとコメントできます