1. 概要

夏時間は、世界の多くの地理的な場所で一般的な方法です。 したがって、時計を進める(通常は1時間)ので、標準時を夏時間に切り替えた日の1時間は明らかに失われます。

このチュートリアルでは、 DSTセーフな方法で相対日付を取得するユースケースに焦点を当てます

2. 相対的な日付

date コマンドは、UnixまたはLinuxシステムの日付と時刻の情報を取得するためのデファクトスタンダードです。 このセクションでは、昨日や明日など、自然言語の単語を使用して相対的な日付を取得する方法を学習します。 さらに、DSTセーフな相対日付を取得する際の微妙な問題を発見します。

2.1. 基本

dateコマンドを使用して相対的な日付を取得することに関連する概念の10,000フィートのビューを取得することから始めましょう。 yesterdayキーワードを–date オプションとともに使用して、昨日の日付を取得できます。

$ date; date --date "yesterday"
Sat Mar 12 10:15:39 PST 2022
Fri Mar 11 10:15:39 PST 2022

デフォルトの出力形式には、日付と時刻の両方が含まれていることがわかります。

同様に、 tomorrow キーワードを使用して、明日の日付を取得しましょう。

$ date; date --date "tomorrow"
Sat Mar 12 10:18:45 PST 2022
Sun Mar 13 11:18:45 PDT 2022

そのため、夏時間調整は、2022年の3月13日の午前2時に切り替える予定です。 したがって、明日の日付に反映されたPDTタイムゾーンに気付くことができます。 また、予想通り、現在の時刻と比較して1時間進んでいます。

日付値のみを表示するように出力を制限する場合は、%F形式を使用できます。

$ date +%F; date --date "tomorrow" +%F
2022-03-12
2022-03-13

2.2. DST-安全でない相対日付

ここまでは順調ですね。 ただし、現在の時刻が標準時間の1日の最後の時間であり、将来の日付が夏時間に該当する場合、は問題になります

$ date; date --date='3 days'
Thu Mar 10 23:11:01 PST 2022
Mon Mar 14 00:11:01 PDT 2022

出力を日付のみに制限するには、%F形式を使用します。

$ date +%F; date --date='3 days' +%F
2022-03-10
2022-03-14

今日が3月10日だとすると、3日目は3月13日になると思います。 ただし、タイムゾーンと時間情報がないと数学は足し合わないようです。

さらに、同様の不整合は、現在の時刻が夏時間に該当する1日の最初の1時間であるのに、標準時刻に該当する過去の日付を取得しようとすると表示されます

$ date; date --date='3 days ago'
Mon Mar 14 00:11:01 PDT 2022
Thu Mar 10 23:11:01 PST 2022

以前と同様に、 %F 形式を使用して出力を日付のみに制限すると、この問題はより顕著になります。

$ date +%F; date --date='3 days ago' +%F
2022-03-14
2022-03-10

DSTセーフな方法で相対的な日付を取得する方法を学びましょう。

3. GNU dateの使用

この問題の根本的な原因は、GNU date コマンド(ほとんどのLinuxディストリビューションのデフォルトの日付ユーティリティ)が夏時間を認識していることです。 そのため、このシナリオでは必要以上に複雑な計算を行う傾向があります。 対照的に、相対的な日付の自然な意味は、その日の現在の時刻を気にせずに、日付レベルでの単純な算術です。

この問題を解決するために、過去または未来の相対時刻を取得する時刻を指定できます

将来の相対的な日付を取得して、これが実際に動作していることを見てみましょう。

$ date; date --date='3 days 00:00'
Thu Mar 10 23:11:01 PST 2022
Sun Mar 13 00:00:00 PDT 2022

ここで、 %F 形式を使用して日付を取得すると、相対的な日付の自然な概念とよく一致します。

$ date +%F; date --date='3 days 00:00' +%F
2022-03-10
2022-03-13

同様に、過去の相対的な日付を取得できます。

$ date; date --date='3 days ago 00:00'
Mon Mar 14 00:11:01 PDT 2022
Fri Mar 11 00:00:00 PST 2022

以前と同様に、 %F 形式を安全に含めて、DSTセーフ日付値を取得できます。

$ date +%F; date --date='3 days ago 00:00' +%F
2022-03-14
2022-03-11

4. BSD dateの使用

前のセクションで述べたように、ほとんどのLinuxディストリビューションでは、GNU dateがデフォルトのdateユーティリティです。 ただし、macOSなどの一部の最新のオペレーティングシステムでは、BSDバージョンをデフォルトのdateユーティリティとして使用しています。

相対的な日付を取得することになると、dateコマンドのBSDバージョンはGNUベースのdateコマンドよりも賢いようです。 -vフラグを使用すると、ユーザーは常にDSTセーフ日付を取得します。

-v フラグを使用して、2022年3月13日から夏時間を採用しているロサンゼルスのタイムゾーンで将来の日付を取得する方法を見てみましょう。

$ TZ="America/Los_Angeles" date; TZ="America/Los_Angeles" date -v+1d;
Sat Mar 12 23:11:01 PST 2022
Sun Mar 13 23:11:01 PDT 2022

タイムゾーン情報がPSTからPDTに変更されても、時間値は現在の時刻と同じままであることがわかります。 そのため、BSD date ユーティリティは、1時間の時計の進みを内部で調整しました。

したがって、BSD dateコマンドを使用して相対日付を取得するために-vフラグを使用する場合、%F形式を安全に使用できます。

$ TZ="America/Los_Angeles" date +%F; TZ="America/Los_Angeles" date -v+1d +%F;
2022-03-12
2022-03-13

5. 結論

このチュートリアルでは、DSTセーフな方法でdateコマンドを使用して相対的な日付を取得する際の微妙な問題を調査しました。 さらに、dateユーティリティのGNUおよびBSDバージョンを使用する際の問題を解決するための簡単なテクニックを学びました。