Lambda(node.js)で日付の計算をしたら思ったより面倒だったのでまとめる。
やりたかったこと
日本標準時(JST)で先週/先月の範囲を、世界標準時(UTC)で取得したい。
例えば、今日が 2020-07-29 とすると先週の範囲は日曜日始まりでこんな感じ。
タイムゾーン | 開始 | 終了 |
---|---|---|
JST | 2020-07-19T00:00:00+0900 | 2020-07-26T00:00:00+0900 |
UTC | 2020-07-18T15:00:00Z | 2020-07-25T15:00:00Z |
やりたくなかったこと
大した処理じゃないので余計なライブラリは使いたくない。
結論
- タイムゾーンの設定はそのままにプログラム内で対応する
- タイムゾーンオフセット値からJSTを自力で設定する
- UTCへの変換も自力でやる
それぞれのタイムゾーン
Lambdaのタイムゾーン
UTCに固定されている模様。
ググるとTZ環境変数を設定すればいいという記事が大量にヒットする。
ただ、TZ環境変数はAWSに予約されているので、それを変更するのはよろしくなさそう。
Lambda のタイムゾーンを環境変数TZで指定してはいけないっていう話 | Serverworks ENGINEER BLOG
他の利用しているAWSサービスでUTCで動作するものもあったので、プログラム内で対応することにした。
JavaScriptのタイムゾーン
JavaScriptのDateクラスにはタイムゾーンを設定する方法はないようだった。
ただ getTimezoneOffset
で分単位の時差は取得できた。JSTは+9時間なので、なぜか-540分が返ってくる。取得した値を+しとけばUTCに変更できそう。
toLocaleString
でタイムゾーン指定の日付文字列を取得して、新しくDateオブジェクトを作る方法もあるようだが、Lambdaでは動作しないのとDateクラスのコンストラクタに日付文字列を渡すのは非推奨だったのでやめた。
最終的にJavaScriptのタイムゾーンは無視して getTimezoneOffset
を使って自力で日時を計算することにした。
オレのMacのタイムゾーン
JSTだった。
AWS SAMを使ってローカルで開発していると、ローカルではJSTでLambda上ではUTCになる。
タイムゾーンを変更してテストしたい場合は、TZ環境変数を設定することで変更できる。
実装
日本標準時で現在日時を取得
考慮するタイムゾーンはJSTかUTCの2つという前提で、タイムゾーン設定を無視して日本標準時での現在日時を取得することにした。
const jstOffset = 9 * 60;
const now = new Date();
const offset = now.getTimezoneOffset() + jstOffset;
now.setTime(date.getTime() + offset * 60 * 1000);
先週の開始/終了日時を取得
日本標準時で先週の日曜日を取得。
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());
start.setDate(start.getDate() - 7 - start.getDay());
同様に今週の日曜日を取得。
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate());
end.setDate(end.getDate() - end.getDay());
先月の開始/終了日時を取得
先月1日を取得。
const start = new Date(now.getFullYear(), now.getMonth() - 1, 1);
今月1日を取得。
const end = new Date(now.getFullYear(), now.getMonth(), 1);
JST→UTCの変換
それぞれの日付をUTCに変換。
実際はタイムゾーンを変換してないので getUTCFULLYear
などは使えない。
const jstOffset = 9 * 60;
date.setTime(date.getTime() - jstOffset * 60 * 1000);
date.getFullYear();
date.getMonth() + 1;
date.getDate();
date.getHours();