Redshift でタイムスタンプを月曜日に丸める方法など
🍪この記事の内容:
ログを週ごとや4週ごとに集約したいときなど、タイムスタンプを丸めたいことがある。Presto には日付を丸める関数 date_trunc があるが、Redshift にはないので、Redshift でタイムスタンプを丸める方法の例を記す。
- RedShift でタイムスタンプを直前の月曜日に丸める。
- RedShift でタイムスタンプを基準日から N 日ごとの日に丸める。
参考文献
- TO_TIMESTAMP 関数 - Amazon Redshift, , 2025年9月25日参照.
- EXTRACT 関数 - Amazon Redshift, , 2025年9月25日参照.
- ISO 8601 - Wikipedia#年と週と曜日, , 2025年9月25日参照.
- AT TIME ZONE 関数 - Amazon Redshift, , 2025年9月25日参照.
- DATEDIFF 関数 - Amazon Redshift, , 2025年9月25日参照.
タイムスタンプを直前の月曜日に丸める
Redshift の DOW (曜日番号) は日曜日が 0, ..., 土曜日が 6 なので、日曜日以外は DOW - 1 日前の日付をとれば月曜日になる。日曜日は 6 日前の日付をとれば月曜日になる。よって、すべての日について (DOW + 6) % 7 日前をとれば月曜日になる。- なお、ISODOW (ISO 8601 規格の曜日) なら月曜日が 1, ..., 日曜日が 7 なので常に ISODOW - 1 日前をとれば月曜日になるが、Redshift は ISODOW に対応していない。
WITH test_data AS (
-- テストデータ: ここでは UTC タイムゾーン付きタイムスタンプ TIMESTAMPTZ 型とする
SELECT TO_TIMESTAMP(v::TEXT, 'YYYYMMDD HH24:MI:SS.MS') AS ts_utc
FROM (
SELECT ARRAY(
'20250901 02:00:00.000', -- 日本でも月曜
'20250902 02:00:00.000', -- 日本でも火曜
'20250907 02:00:00.000', -- 日本でも日曜
'20250907 22:00:00.000', -- 日本では月曜 (イギリスではまだ日曜)
'20250908 02:00:00.000' -- 日本でも月曜
) AS v
) AS g, g.v AS v
)
SELECT
ts_utc,
TO_CHAR( -- (DOW + 6) % 7 日前をとれば直前の月曜日に丸めることができる
ts_utc - INTERVAL '1 day' * ((EXTRACT(DOW FROM ts_utc) + 6) % 7),
'YYYY-MM-DD'
) AS week_utc
FROM test_data
ts_utc, week_utc
2025-09-01 02:00:00+00, 2025-09-01
2025-09-02 02:00:00+00, 2025-09-01
2025-09-07 02:00:00+00, 2025-09-01
2025-09-07 22:00:00+00, 2025-09-01
2025-09-08 02:00:00+00, 2025-09-08
もしデータベースに格納されているタイムスタンプが目的のタイムゾーンの時刻ではない場合は、DOW をとる前に目的のタイムゾーンの時刻にする必要があることに注意 (以下: 日本時間にするとテストデータの4行目は丸め先が変わる)。
- AT TIME ZONE 関数はタイムゾーン付きタイムスタンプ TIMESTAMPTZ 型をタイムゾーンなしタイムスタンプ TIMESTAMP 型にするが、どちらも EXTRACT 関数で曜日番号を抽出できる。
SELECT
-- もしデータベースが UTC だが日本における直前の月曜日をとりたい場合は JST に変換する
ts_utc AT TIME ZONE 'JST' AS ts_jst,
TO_CHAR(
ts_jst - INTERVAL '1 day' * ((EXTRACT(DOW FROM ts_jst) + 6) % 7),
'YYYY-MM-DD'
) AS week_jst
FROM test_data
ts_jst, week_jst
2025-09-01 11:00:00, 2025-09-01
2025-09-02 11:00:00, 2025-09-01
2025-09-07 11:00:00, 2025-09-01
2025-09-08 07:00:00, 2025-09-08
2025-09-08 11:00:00, 2025-09-08
タイムスタンプを基準日から N 日ごとの日に丸める
より一般に、基準日から N 日ごとにデータを区切るためにタイムスタンプを丸めたいときは、DATEDIFF 関数 (日付の差を返す) を利用して、DATEDIFF % N 日前の日付をとればよい。- 以下では基準日をタイムゾーンなしタイムスタンプ TIMESTAMP 型として与え、DATEDIFF をとるときはデータ側も TIMESTAMP 型にキャストしている。
WITH test_data AS (
-- テストデータ: ここでは UTC タイムゾーン付きタイムスタンプ TIMESTAMPTZ 型とする
SELECT TO_TIMESTAMP(v::TEXT, 'YYYYMMDD HH24:MI:SS.MS') AS ts_utc
FROM (
SELECT ARRAY(
'20250901 02:00:00.000', -- 日本でも9月の1週目
'20250902 02:00:00.000', -- 日本でも9月の1週目
'20250907 02:00:00.000', -- 日本でも9月の1週目
'20250907 22:00:00.000', -- 日本では9月の2週目 (イギリスではまだ1週目)
'20250915 02:00:00.000', -- 日本でも9月の3週目
'20250922 02:00:00.000', -- 日本でも9月の4週目
'20250929 02:00:00.000' -- 日本でも9月の5週目
) AS v
) AS g, g.v AS v
),
configs AS (
SELECT
'20250901'::TIMESTAMP AS kijun -- 基準日
)
SELECT
ts_utc,
DATEDIFF(days, (SELECT kijun FROM configs), ts_utc::TIMESTAMP) AS diff,
TO_CHAR(ts_utc - INTERVAL '1 day' * (diff % 7), 'YYYY-MM-DD') AS week,
TO_CHAR(ts_utc - INTERVAL '1 day' * (diff % 28), 'YYYY-MM-DD') AS week4
FROM test_data
ts_utc, diff, week, week4
2025-09-01 02:00:00+00, 0, 2025-09-01, 2025-09-01
2025-09-02 02:00:00+00, 1, 2025-09-01, 2025-09-01
2025-09-07 02:00:00+00, 6, 2025-09-01, 2025-09-01
2025-09-07 22:00:00+00, 6, 2025-09-01, 2025-09-01
2025-09-15 02:00:00+00, 14, 2025-09-15, 2025-09-01
2025-09-22 02:00:00+00, 21, 2025-09-22, 2025-09-01
2025-09-29 02:00:00+00, 28, 2025-09-29, 2025-09-29
もしデータベースに格納されているタイムスタンプが目的のタイムゾーンの時刻ではない場合は、DATEDIFF をとる前に目的のタイムゾーンの時刻にする必要があることに注意 (以下: 日本時間にするとテストデータの4行目は丸め先が変わる)。
SELECT
-- もしデータベースが UTC だが日本における基準日から N 日ごとの日に丸めたい場合は変換する
ts AT TIME ZONE 'JST' AS ts_jst, -- TIMESTAMP 型
DATEDIFF(days, (SELECT kijun FROM configs), ts_jst) AS diff,
TO_CHAR(ts_jst - INTERVAL '1 day' * (diff % 7), 'YYYY-MM-DD') AS week,
TO_CHAR(ts_jst - INTERVAL '1 day' * (diff % 28), 'YYYY-MM-DD') AS week4
FROM test_data
ts_jst, diff, week, week4
2025-09-01 11:00:00, 0, 2025-09-01, 2025-09-01
2025-09-02 11:00:00, 1, 2025-09-01, 2025-09-01
2025-09-07 11:00:00, 6, 2025-09-01, 2025-09-01
2025-09-08 07:00:00, 7, 2025-09-08, 2025-09-01
2025-09-15 11:00:00, 14, 2025-09-15, 2025-09-01
2025-09-22 11:00:00, 21, 2025-09-22, 2025-09-01
2025-09-29 11:00:00, 28, 2025-09-29, 2025-09-29