OSX(Darwin)環境下でGNU Dateを使わずにmillisecondsを含めたunixtimeを出力する方法を模索してみた

OSX(Darwin)環境下でGNU Dateを使わずにmillisecondsを含めたunixtimeを出力はどのくらいあるのか、確認してみました。
2020.03.12

はじめに

millisesondsを含めたunixtimeを使うケースはそれほど頻繁でもないのですが、そのタイミングになった時に案外計算方法に手を焼かされます。aws-cliを使った場合だと、aws logs create-export-taskの引数(--from, --to)等があります。

Linux環境では date コマンドを使って対処できますが、同じ感覚のままMac上で使おうとすると恐らく以下の出力になるはずです。

% date -d "-30days" +%s%N | xargs -I{} expr {} / 1000000
usage: date [-jnRu] [-d dst] [-r seconds] [-t west] [-v[+|-]val[ymwdHMS]] ...
            [-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]
# Linux環境では……
% date -d "-30days" +%s%N | xargs -I{} expr {} / 1000000
1581301639622

HomeBrew経由でGNU Dateを入れるという方法もありますが、環境によってまちまちになることもあり、標準で備わっているライブラリを使って実行できる前提にて確認してみました。

実行する前提

ターミナル上にて、或いはシェルスクリプトの2択とします。millisecondsを含めたunixtimeで、aws logs create-export-task--from--to に渡せる形とします。

各言語での実行

Python

Python3で動かせる前提としています。Pythonが最初から入っているDockerイメージ等でも利用可能なはずです。開始対象範囲を変更したい場合はdatetime.timedelta()に指定した 30 を求めたい値に変更します。

# from
echo $(python -c "import datetime;print(int((datetime.datetime.now() - datetime.timedelta(30)).timestamp() * 1000))")
# to
echo $(python -c "import time;print(int(time.time() * 1000))")

Ruby

Time.now.to_iでは10桁までの出力となります。30日前の日付取得にはactivesupportを利用しています。

gem install activesupport
# from
echo $(ruby -e "require 'active_support/all';print 30.days.ago.strftime('%s%L').to_i")
# to
echo $(ruby -e "print Time.now.strftime('%s%L').to_i")

php

途中で計算と変換が面倒になり、今回はmicrotime()に足し引きする形としました。

# from
echo $(php -r 'echo ceil(microtime(true)*1000 - (60*60*24*30*1000));')
# to
echo $(php -r 'echo ceil(microtime(true)*1000);')

JavaScript

インタプリタ言語だけどできるのかなと思いましたが、node.jsで出来ました。

# from
echo $(node -e "console.log(new Date().setDate(new Date().getDate() - 30));")
# to
echo $(node -e "console.log(new Date().setDate(new Date().getDate()));")

なお、Mac限定ですが以下のようなやり方もあります。以下の記事にて知りました。

JavaScriptをコマンドラインから使う方法

# from
echo $(/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc -e 'print(new Date().setDate(new Date().getDate() - 30));')
# to
echo $(/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc -e 'print(new Date().setDate(new Date().getDate()));')

date

gdateではない、Mac標準のものです。millisecondは取れないので0埋めしています。Linux環境下で使うスクリプトに入れる場合はuname等で判定して分岐させる必要があります。

# from
echo $(date -v-30d +%s000)
# to
echo $(date +%s000)

あとがき

当初はgdateを使って書いていましたが、何も入れない状態でも動くようにしたいなと思った結果、今回の記事のきっかけとなりました。個人的にはNode.jsが一番すっきりしているという感想です。

普段滅多に行わないけど、やるとなると意外に悩まされる計算でもあり、良い振り返りになりました。参考になれば幸いです。