AWK: フリーゲルの公式に基づく Unix time 変換処理
gawk が使える場合を除き、AWKスクリプトにおけるグレゴリオ暦とUnix time(POSIX time)の相互変換処理は自前で準備する必要がある。
そこで今回はフリーゲルの公式を使って実装してみる。
・unix_time.awk ※テスト用コードも実装済み
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/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
1 2 3 4 5 6 7 8 9 10 11 | #!/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
1 2 3 4 5 6 | #!/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 件のコメント:
コメントを投稿