目的
-
時刻や日時の計算は一度エポック秒に変換して加算、減算するのがもっとも間違いが少ないです。
-
そのためJavaScriptでも指定時刻からエポック秒を得たいことがJavaScriptでもShell(Bash)でもあります。サマータイムとか閏とか手動で設定するのは悪夢です。オリジナルコマンドなんか作るのはやめた方がいいです(この考えに行き着くまで苦い経験を繰り返しました)。
-
JavaScriptのデフォルトのDateで格闘するのも否定しませんが、時間かけずにさっさとコーディングしたいものです。
-
JavaScriptには
moment.js
を導入することにしています。cgiではbash/gdateを使っています -
moment.js
とgdate
は互換の無い記述なのでその備忘録としての書いておきます。 -
検索性が悪かったので全面書き換えしました[2020-09-06]
環境
- macOS
- moment.js 2.17
- bash 5.0.17
- date (GNU coreutils) 8.32
リンク
- UNIX時間
- Moment.js Documentation
- 日付からエポック、エポックから日付をワンライナーで
- シェルスクリプトでunixtimeへ変換・unixtimeから変換をしてみる
- シェルスクリプトでUNIXTIMEの取得と日時との相互変換(POSIX準拠dateコマンドのみ使用)
JavaScriptでエポック秒と指定フォーマット日時の相互変換
moment.jsの準備
- JavaScriptのmoment.jsライブラリを使います。
<script src="..."></script>
なんかでCDNで読めばいいと思います。 - moment.jsはデフォルトではローカル時間で解析および表示されます。
<!-- moment.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/locale/ja.js"></script>
JavaScript(moment.js)で現在時間と現在のエポック秒の取得
// 現在の時間の取得(ここで出力は省略)
> moment()
// 現在のエポック秒の取得
moment.unix()
< 1595722136
時刻→エポック秒(moment.js)
// 第1引数で指定した時刻のフォーマットは第2引数で指定します。
> moment("200101 123456", "YYMMSS HHmmss").unix()
< 1577849696
エポック秒→時刻( moment.js)
// エポック秒から指定フォーマットに戻します。
> moment.unix(1577849696).format("YYMMDD HHmmss")
< "200101 123456"
// もちろん可読性の高いフォーマットにできます。
> moment.unix(1577849696).format("YYYY-MM-DD HH:mm:ss Z")
< "2020-01-01 12:34:56 +09:00"
moment.jsの時刻のフォーマット(使うものだけ)
- moment()の時刻表現は非常にフレキシブルなのですが、shellの
gdate
と表現は似ていて違います。なので忘れます。 - 私は使うのは下記に限っています。
表1 moment.jsのフォーマット(ここのリンクから改変)
Input | Example | Description |
---|---|---|
YY | 14 | 2 digit year |
MM | 1..12 | Month number |
HH | 0..23 | Hours (24 hour time) |
mm | 0..59 | Minutes |
ss | 0..59 | Seconds |
Z | +12:00 | Offset from UTC as +-HH:mm |
ZZ | +0900 | Offset from UTC as +-HHmm |
- 使用例;
moment("200101 123456", "YYMMSS HHmmss").unix()
moment.unix(1577849696).format("YYMMDD HHmmss")
エポック秒⇄時刻の相互変換(bash)
- cgi側でも同じことをしたいですね。
- 実は
bash
の方が面倒です。
gdateを使う(インストール)
-
GNU
date
を使いたいのでbashのcoreutil
をインストールしておきます。詳しくは下記が面白いです。使い方も載っているサイトあります。
時刻(UNIX形式)→エポック秒(bash)
gdate -d "2020-01-01 12:34:56" +%s
1577849696
# こちらでもOK
gdate -d '2020/01/01 12:34:56' +%s
1577849696
- エポック秒を得る定番ですね。
-
gdate
は入力フォーマットと出力フォーマットを別個に指定できないのでUNIX時間フォーマットで指定する必要があります。 - 時間指定にはUNIX形式の指定が必要ですが柔軟性を持たせたいですね。
時刻→エポック秒(awkのmktimeを使う)
echo "200101 123456" | fold -s -w2 |tr '\n' ' ' |awk '{print mktime(20$0)}'
1577849696
# こっちが簡単かな
echo "200101 123456" | fold -s -w2 |xargs|awk '{print mktime(20$0)}'
1577849696
- 少しだけ解説:
- 文字列200101 123456を
fold -s -w2
でスペースを気にしないで二文字に分けます。 - それを
tr '\n' ' '
で改行をスペースに分けて、awkのmktime()
でエポック秒に変換します。mktime()
で必要な最初の項目はは4桁年なので20を$0に加えています。 - 最初、awkで200101を2020-01-01とかに変換すればいいかと考えましたがawkにはmktime()があるからそれ使えばいいじゃんと考え直した次第です。
時刻→エポック秒(utconvを使う)
- こんなコマンドもあります。TZの設定もできます(詳しくはリンク先を)
- rich mikanさん製コマンド:utconv
cd /usr/local/bin
# インストールします
wget https://gist.githubusercontent.com/richmikan/8703117/raw/e44e6a357cb7423c1a1e58df96da9792c43e80aa/utconv
# 実行権を与えてください
chmod +x utconv
echo "20200101123456" | utconv
1577849696
- この文字列生成はshellでは比較的簡単でしょう。
エポック秒→時刻(gdate)
- gdateではエポック秒は
@数字
で指定します。
gdate '-d @1577849696'
水 1 1 12:34:56 JST 2020
# 可読性の高いフォーマットに
gdate '-d @1577849696' +"%Y-%m-%d %H:%M:%S (%Z)%:z"
2020-01-01 12:34:56 (JST)+09:00
指定したのは2020年01月01日12:34:56でしたので、正しく戻っています。ローカル時間帯の(JST)で戻っていますね。
表2 GNU dateのフォーマット(ここのリンクから改変)
Input | Example | Description |
---|---|---|
%y | 00..99 | last two digits of year |
%m | 01..12 | month |
%d | e.g., 01 | day of month |
%H | 00..23 | hour |
%M | 00..59 | minute |
%S | 00..60 | second |
%z | e.g., -0400 | +hhmm numeric time zone |
%:z | e.g., -04:00 | +hh:mm numeric time zone |
- 使用例
-
gdate '+%y%m%d %H%M%S'
で200726 095643を得ます
-
エポック秒→時刻(convert -rを使う)
- 逆の計算もできます。ただしYYMMDDHHmmssです。これから
sed/awk
などで色々なフォーマットにできますね。
echo "1577849696" | utconv -r
20200101123456
エポック秒→時刻(awkを使う)
echo "1577849696" | awk '{print strftime("%Y-%m-%d,%H:%M:%S",$0)}'
2020-01-01,12:34:56
- 自分の備忘録のために書きましたがどなたかのお役に立てれば嬉しいです。