NScripterでepoch秒を扱ってみる。

epoch秒と言うのは、UNIX文化圏で使われているもので、グリニッジ標準時間1970年1月1日00:00:00からの経過秒数のことです。PerlCGIとかやってれば、日付や時間を取り扱うのに避けては通れない概念な訳です。
これ、あったらあったでかなり楽になります。たとえば、ある日から別のある日まで何日経過したのかなどを計算するのに使えます。両方の日付のepoch秒を出して、その差を24*60*60で割れば日数になるからです。他にも、時間を記録したいが人間がぱっと見気付かない、あるいは調査させる気をなくさせる目的で、epoch秒を使うこともあります。
まあ、そんなのもコミで、色々NScripter用に色々追加してみたりします。

追加命令

年月日の年は、NScripterフォーマット、つまり、西暦2000年を0とした数値を使います。

now2epoch
現在年月日時分秒をepoch秒に変換
date2epoch
年月日時分秒を与えてecpoch秒に変換
epoch2date
逆にepoch秒を年月日時分秒に変換
is_leapyear
年(このコマンドだけ西暦)を与えると、それが閏年かどうか判定する。
date2weekday
年月日を与えると、その曜日を返す。0が日曜日、6が土曜日
date2day_of_year
年月日を与えると、その日がその年の何日目かを返す。1月1日が1、12月31日が365 or 366

注意点

閏年判定はきちんとしてる(はず)ので、未来の日付を使うこともできます。
しかしその性質上、マイナスのepoch秒は扱えません。1970年以前の日付は表現できないことになります。

使い道

ちょっと考えてみましたが、実際の暦をゲームに導入するのに、epoch秒は使えるかも知れません。
また、時限付btn系命令を使う場合、resettimer等を使ってしまうので、NScripterが起動してからの秒数を破壊してしまうことがあるでしょう。その場合、*start節の早いうちにepoch秒を取得しておき、現在epoch秒と比較することで、NScripter起動時からの秒数を取得できます。ミリ秒でないのはご勘弁を。

define節game以上

mov %0,100 ; 環境に合わせてお好みで
numalias time_year,%0:inc %0
numalias time_month,%0:inc %0
numalias time_day,%0:inc %0
numalias time_hour,%0:inc %0
numalias time_min,%0:inc %0
numalias time_sec,%0:inc %0
numalias time_loop,%0:inc %0
numalias time_leap,%0:inc %0
numalias time_epoch,%0:inc %0
numalias is_leap_result,%0:inc %0
numalias is_leap_year,%0:inc %0
defsub now2epoch
defsub date2epoch
defsub epoch2date
defsub is_leapyear
defsub date2weekday
defsub date2day_of_year

game以下start節前

;==================
; date2weekday
;==================
; 年月日から曜日を計算する。
; 第一引数:結果を受け取る数値変数。0〜6が日曜日から土曜日に対応
; 第二引数〜第三引数:年月日の数値。NScripterフォーマット
; zellerの公式ばんざーい
*date2weekday
getparam i%time_epoch,%time_year,%time_month,%time_day
add %time_year,2000
if %time_month<3 add %time_month,12:dec %time_year
mov %%time_epoch,(%time_year+%time_year/4-%time_year/100+%time_year/400+(13*%time_month+8)/5+%time_day) mod 7
return

;==================
; date2day_of_year
;==================
; ある年月日がその年の何日目かを返す。
; 第一引数:結果を受け取る数値変数。0〜6が日曜日から土曜日に対応
; 第二引数〜第三引数:年月日の数値。NScripterフォーマット
; 1月1日は1に、12月31日は365 or 366になる。
*date2day_of_year
getparam i%time_epoch,%time_year,%time_month,%time_day
add %time_year,2000
is_leapyear %time_leap,%time_year
mov %%time_epoch,%time_day ; 下準備
if %time_month=1 return
add %%time_epoch,31
if %time_month=2 return
add %%time_epoch,28+%time_leap
if %time_month=3 return
add %%time_epoch,31
if %time_month=4 return
add %%time_epoch,30
if %time_month=5 return
add %%time_epoch,31
if %time_month=6 return
add %%time_epoch,30
if %time_month=7 return
add %%time_epoch,31
if %time_month=8 return
add %%time_epoch,31
if %time_month=9 return
add %%time_epoch,30
if %time_month=10 return
add %%time_epoch,31
if %time_month=11 return
add %%time_epoch,30
return

;==================
; now2epoch
;==================
; 現在の日付・時刻をエポック秒に変換する。
; 第一引数:結果を受け取る数値変数
*now2epoch
getparam i%time_epoch
date %time_year,%time_month,%time_day
time %time_hour,%time_min,%time_sec
goto *date2epoch_main

;==================
; epoch2date
;==================
; エポック秒をNScripterの日付形式に変換する。
; 第一引数:変換するエポック秒
; 第二引数〜第七引数:結果を受け取る数値変数。年・月・日・時・分・秒。
*epoch2date
getparam %time_epoch,i%time_year,i%time_month,i%time_day,i%time_hour,i%time_min,i%time_sec
add %time_epoch,32400 ; タイムゾーンを東京に設定
mov %%time_day,%time_epoch
div %%time_day,24*60*60 ; 日数を計算。
mov %%time_year,1970 ; 年の処理
~
is_leapyear %time_leap,%%time_year
if %%time_day<366+%time_leap jumpf
inc %%time_year
sub %%time_day,365+%time_leap
jumpb
~
sub %%time_year,2000
mov %%time_month,1 ; 月の処理と日の処理
notif %%time_day>31 jumpf ; 一月
sub %%time_day,31:inc %%time_month
if %%time_day<29+%time_leap=1 jumpf ; 二月
sub %%time_day,28+%time_leap:inc %%time_month
if %%time_day<32 jumpf ; 三月
sub %%time_day,31:inc %%time_month
if %%time_day<31 jumpf ; 四月
sub %%time_day,30:inc %%time_month
if %%time_day<32 jumpf ; 五月
sub %%time_day,31:inc %%time_month
if %%time_day<31 jumpf ; 六月
sub %%time_day,30:inc %%time_month
if %%time_day<32 jumpf ; 七月
sub %%time_day,31:inc %%time_month
if %%time_day<32 jumpf ; 八月
sub %%time_day,31:inc %%time_month
if %%time_day<31 jumpf ; 九月
sub %%time_day,30:inc %%time_month
if %%time_day<32 jumpf ; 十月
sub %%time_day,31:inc %%time_month
if %%time_day<31 jumpf ; 十一月
sub %%time_day,30:inc %%time_month ; 十二月
~
inc %%time_day

if %%time_day=32 mov %%time_day,1:mov %%time_month,1:inc %%time_year
; 時の処理
mov %%time_sec,%time_epoch mod (24*60*60)
mov %%time_hour,0
~
notif %%time_sec>60*60 jumpf
inc %%time_hour
sub %%time_sec,60*60
jumpb
~
; 分、秒の処理
mov %%time_min,0
~
notif %%time_sec>60 jumpf
inc %%time_min
sub %%time_sec,60
jumpb
~
return

;==================
; date2epoch
;==================
; 日付をエポック秒(1970年1月1日00:00:00からの経過秒)に変換する。
; 第一引数:結果を受け取る数値変数
; 第二引数:年を表す数値。0は西暦2000年を意味する。
; 第三引数:月を表す数値。1〜12の範囲で。
; 第四引数〜第七引数:それぞれ日、時、分、秒。
*date2epoch
getparam i%time_epoch,%time_year,%time_month,%time_day,%time_hour,%time_min,%time_sec
 *date2epoch_main
mov %%time_epoch,0
; 年の処理
if %time_year=1970 jumpf
for %time_loop=1970 to %time_year+1999
	add %%time_epoch,365
	is_leapyear %time_leap,%time_loop
	if 1=%time_leap inc %%time_epoch
next
~
; 月の処理
if %time_month=1 jumpf
add %%time_epoch,31
if %time_month=2 jumpf
is_leapyear %time_leap,%time_year
add %%time_epoch,28+%time_leap
if %time_month=3 jumpf
add %%time_epoch,31
if %time_month=4 jumpf
add %%time_epoch,30
if %time_month=5 jumpf
add %%time_epoch,31
if %time_month=6 jumpf
add %%time_epoch,30
if %time_month=7 jumpf
add %%time_epoch,31
if %time_month=8 jumpf
add %%time_epoch,31
if %time_month=9 jumpf
add %%time_epoch,30
if %time_month=10 jumpf
add %%time_epoch,31
if %time_month=11 jumpf
add %%time_epoch,30
~
add %%time_epoch,%time_day-1 ; 日の処理
mul %%time_epoch,24*60*60 ; 日数を24*60*60倍して秒数に変換
add %%time_epoch,%time_hour*60*60 ; 時の処理
add %%time_epoch,%time_min*60 ; 分の処理
add %%time_epoch,%time_sec ; 秒の処理
sub %%time_epoch,32400 ; タイムゾーンを東京に。
return

;==================
; is_leapyear
;==================
; その年が閏年かどうか調べる。
; 第一引数:結果を受け取る数値変数。0は通常年。1は閏年
; 第二引数:年。西暦で指定
*is_leapyear
getparam i%is_leap_result,%is_leap_year
mov %%is_leap_result,0
if 0=%is_leap_year mod 400 mov %%is_leap_result,1:return
if 0=%is_leap_year mod 100 return
if 0=%is_leap_year mod 4 mov %%is_leap_result,1:return
return