AWK: フリーゲルの公式に基づく Unix time 変換処理
gawk が使える場合を除き、AWKスクリプトにおけるグレゴリオ暦とUnix time(POSIX time)の相互変換処理は自前で準備する必要がある。
そこで今回はフリーゲルの公式を使って実装してみる。
・unix_time.awk ※テスト用コードも実装済み
#!/usr/bin/nawk -f # Based on Fliegel-Van Flandern algorithm. # Inputs must be Epoch (1970/01/01 00:00:00) and over. # Time zone will not be considered. function to_unix_time(yyyy, mm, dd, hh, mi, ss) { if (mm - 2 <= 0) { --yyyy; mm += 12} days = int(365.25 * yyyy) + int(yyyy / 400) - int(yyyy / 100) \ + int(30.59 * (mm - 2)) + dd - 719499 # 1721089 - 2440588(Epoch) return ((days * 24 + hh) * 60 + mi) * 60 + ss } function to_string(unix_time) { ss = unix_time % 60; unix_time = (unix_time - ss) / 60 mi = unix_time % 60; unix_time = (unix_time - mi) / 60 hh = unix_time % 24; unix_time = (unix_time - hh) / 24 j = unix_time + 2472632 # 2440588(Epoch) + 32044 g = int(j / 146097); dg = j % 146097 c = int((int(dg / 36524) + 1) * 3 / 4); dc = dg - c * 36524 b = int(dc / 1461); db = dc % 1461 a = int((int(db / 365) + 1) * 3 / 4); da = db - a * 365 y = g * 400 + c * 100 + b * 4 + a m = int((da * 5 + 308) / 153) - 2 d = da - int((m + 4) * 153 / 5) + 122 yyyy = y - 4800 + int((m + 2) / 12) mm = (m + 2) % 12 + 1 dd = d + 1 return sprintf("%04d-%02d-%02d %02d:%02d:%02d", yyyy, mm, dd, hh, mi, ss) } # test code { x = to_unix_time(substr($1, 1, 4), substr($1, 6, 2), substr($1, 9, 2)) expected = (NR - 1) * 60 * 60 * 24 if (x != expected) { print "Assertion failed. line " NR " - Expected: " expected ", Received: " x exit } print to_string(x) }
Python の datetime モジュールの処理結果と比較することで、1970/1/1~9999/12/31 の期間の全日付について連続性および妥当性を検証する。
・unix_time_test.py
#!/usr/bin/env python import datetime s = datetime.date(1970, 1, 1) t = datetime.date(9999, 12, 31) while True: print '%s 00:00:00' % s if s >= t: break s += datetime.timedelta(days=1)
datetime.date では西暦10000年は表現できないので注意。(Exception が発生)
テスト用のシェルを作るならこのような感じである。
・unix_time_test.sh
#!/usr/bin/ksh ./unix_time_test.py > ./test_in.txt ./unix_time.awk ./test_in.txt > ./test_out.txt diff ./test_in.txt ./test_out.txt > /dev/null if [ $? -eq 0 ]; then print 'OK'; else print 'NG'; fi
改行コードがLFの場合、58657940 bytes(≒56MB) のファイルが2個生成される。(test_in.txt, test_out.txt)
Windows 環境なら diff のところを comp で検査。
・出力結果
OK
ただ実際のところ、もう少しわかりやすいコーディングのほうが周囲の理解を得やすいかもしれない。
Perl や Python、Ruby が使える環境であれば尚更である。
参考:
http://www5d.biglobe.ne.jp/~noocyte/Programming/GregorianAndJulianCalendars.html#DateToDayNumber
http://en.wikipedia.org/wiki/Julian_day
0 件のコメント:
コメントを投稿