LayerX エンジニアブログ

LayerX の エンジニアブログです。

SnowflakeにおけるWEEK_STARTは意志を持って決めよう

こんにちは。バクラク事業部 BizOps部 データグループの@civitaspoです。先日、大阪万博に行ったとき、「ミャクミャク」と10回連続で言うのが難しいことに気が付きました。10回連続で言えなかった人は、この記事をシェアするときに「ミャクミャク10回連続not言え太郎」と投稿して下さい。

今回の記事は小ネタです。Snowflakeの WEEK_START というパラメータについて書きます。このパラメータは、Snowflakeにおける曜日番号(たとえば、DAYOFWEEK 関数の返却値)を決めるパラメータです。 docs.snowflake.com

ドキュメントには、以下のようにデフォルト値を 0 から 1 に変更すべし、と記載されています。

The default value for the parameter is 0, which preserves the legacy Snowflake behavior (ISO-like semantics). However, we recommend changing this value to explicitly control the resulting behavior of the functions. The most common scenario is to set the parameter to 1.

docs.snowflake.com

本記事では、ドキュメントのこの記載を深堀り、意志を持って WEEK_START パラメータを決めるべし、という話を書きます。

WEEK_START の変更による挙動の変化

まず、 WEEK_START を変更することによって、どのような挙動の変化が起きるかを説明します。主に DAYOFWEEK 関数の返り値が変わります。1

Snowflakeのデフォルトでは、 WEEK_START の値は 0 です。 DAYOFWEEK 関数はこのとき、以下のように日曜日を基準として 0 ~ 6 が割り当てられます。

WEEK_START=1 だと月曜日を基準として 1 ~ 7 が割り当てられます。

WEEK_START=3 だと水曜日を基準として1 ~ 7 が割り当てられます。

WEEK_START=7 だと日曜日を基準として 1 ~ 7 が割り当てられます。

この WEEK_START パラメータには 0 ~ 7 を設定することができ、それぞれの挙動をまとめると以下のようになります。

WEEK_START 基準となる曜日 割り当てられる曜日番号の範囲
0 日曜日 0 ~ 6
1 月曜日 1 ~ 7
2 火曜日 1 ~ 7
3 水曜日 1 ~ 7
4 木曜日 1 ~ 7
5 金曜日 1 ~ 7
6 土曜日 1 ~ 7
7 日曜日 1 ~ 7

国際標準化機構による定義

次に、国際標準化機構(以下、ISO)2 による曜日番号の定義を見てみます。

ISOでは、ISO 8601 という日付及び時間に関する表現について定めた企画が存在します。ISO 8601 では、以下のように「月曜日を基準として 1 ~ 7 を割り当てる」と定められています。

曜日番号 曜日
1 月曜日
2 火曜日
3 水曜日
4 木曜日
5 金曜日
6 土曜日
7 日曜日

www.iso.org

ここで、冒頭で引用したSnowflakeのドキュメントの文章に立ち返ります。

The default value for the parameter is 0, which preserves the legacy Snowflake behavior (ISO-like semantics). However, we recommend changing this value to explicitly control the resulting behavior of the functions. The most common scenario is to set the parameter to 1.

docs.snowflake.com

Snowflakeはデフォルトの挙動を”ISO-like semantics”と表現しています。Snowflakeのデフォルトの挙動では日曜日は 0 となりますが、ISO 8601 では 7 となります。一方、日曜日以外の曜日に関しては ISO 8601 準拠となります。つまり、Snowflakeは「日曜日以外の曜日はISO 8601 準拠」を指して、”ISO-like semantics”と表現しているようです。(非常に誤読を産む表現だと思うので私は修正すべきだと思っています。)

他のシステムの挙動

他のシステム(データベースや言語、APIなど)についても調査してみたところ、驚くほど多様なことがわかりました。多くのシステムでISO 8601準拠の曜日番号を返す方法も存在している前提で、あくまでデフォルトの挙動として読んで下さい。

日曜を基準として 0 ~ 6 を割り当てるパターン

システム名 参考リンク
PostgreSQL https://www.postgresql.org/docs/8.1/functions-datetime.html
.NET https://learn.microsoft.com/en-us/dotnet/api/system.dayofweek?view=net-9.0
JavaScript https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getDay
Golang https://pkg.go.dev/time#Weekday.String
Redshift https://docs.aws.amazon.com/redshift/latest/dg/r_DATE_PART_function.html
DuckDB https://duckdb.org/docs/stable/sql/functions/datepart.html#part-specifiers-only-usable-as-date-part-specifiers
ケンオール 日本の祝日 API https://kenall.jp/docs/API/holidays/#曜日とレスポンスフィールドの対応表

日曜を基準として 1 ~ 7 を割り当てるパターン

システム名 参考リンク
MySQL https://dev.mysql.com/doc/refman/8.4/en/date-and-time-functions.html#function_dayofweek
SQL Server https://learn.microsoft.com/en-us/sql/t-sql/functions/datepart-transact-sql?view=sql-server-ver17#week-and-weekday-datepart-arguments
BigQuery https://cloud.google.com/bigquery/docs/reference/standard-sql/date_functions
Excel https://support.microsoft.com/en-us/office/weekday-function-60e44483-2ed1-439f-8bd0-e404c190949a

月曜を基準として 0 ~ 6 を割り当てるパターン

システム名 参考リンク
Python Pandas API https://pandas.pydata.org/docs/reference/api/pandas.Series.dt.weekday.html

月曜を基準として 1 ~ 7 を割り当てるパターン

システム名 参考リンク
Java 1.8 ~ https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html
Trino https://trino.io/docs/current/functions/datetime.html#day_of_week

意志を持って WEEK_START の値を決めるべし

ここまで読んで、曜日番号を返す挙動がシステムによって多様であり、統一された標準はあるものの、現実には統一されていないことがおわかりいただけたと思います。それでは、実際にSnowflakeの WEEK_START パラメータをどの値に設定すべきでしょうか。

まず重要なのは、データ統合の観点です。現実的には、Snowflakeに様々なシステムからデータが流入してきます。前述したように、PostgreSQLからは日曜日基準の 0 ~ 6、BigQueryからは日曜日基準の 1 ~ 7、Pandasで処理したデータは月曜日基準の 0 ~ 6、といった具合に、異なる曜日番号の体系でデータが入ってくる可能性があります。利用するシステムが大量にあったり、分散管理されて無尽蔵に増えていくケースでは、曜日番号の扱いを統一するのは非現実的である可能性があります。

また、Snowflakeの DAYOFWEEKISO 関数との互換性も考えるべきです。デフォルトでは DAYOFWEEK 関数と DAYOFWEEKISO 関数は異なる値を返します。WEEK_START=1 に設定すると、DAYOFWEEK 関数と DAYOFWEEKISO 関数が完全に同じ挙動になるため、意図せず異なる関数を使ってしまい、想定外の結果になるリスクを回避できたり、レビューコストを下げたり出来ます。 docs.snowflake.com

これらを考慮して、「曜日番号はSnowflakeでは使わないべし」と言った運用にするのか、Snowflakeのデフォルトの挙動のまま運用するのか、WEEK_START=1 を設定して運用するのか等を「意志を持って決めるべし」だと考えています。

なお、Snowflake Accountレベルで設定を変更する場合は以下のSQLを実行して下さい。

ALTER ACCOUNT SET WEEK_START = 1;

おわりに

この記事では、Snowflakeにおける WEEK_START パラメータについて深堀りして説明をしました。実は他にも WEEK_OF_YEAR_POLICY というパラメータがあり、同じような議論があります。説明が大変なので本記事では触れていませんが、データ基盤の運用者は是非調べて、決めてもらえればと思います。 docs.snowflake.com

LayerXでは一緒にデータ基盤を作ってくれる仲間を募集しています。ちょっとでも興味のある方は一度ぜひお話しましょう!

open.talentio.com