ファイルの更新日を調べる命令であるFile.lastModified(path)を実行すると、1970年1月1日午前0時0分0秒から数えた時間である「UNIXTIME(単位はmsec)」が出力されます。
このままだと「1621927895482」のように、ケタがとんでもなく多い数字を一つ渡されるだけなので上手く使えません。
これを我々が理解できる「普通の日付」に変換するプログラムを紹介します。
ネットで調べたものを参考に、というよりしっかりパクってImageJマクロ用にアレンジしました。ありがとうございました!
コード
//unixtime(msec) to tokyotime(yyyy/mm/dd hh:mm:ss)
var year, month, day, hour, minute, second;
tokyotime = ConvertUnixTimeToTokyoTime(1621927895482);
print(tokyotime);
//-----------------------------------------------------------------------------
//Define function ConvertUnixTimeToTokyoTime
function ConvertUnixTimeToTokyoTime(unixtime) {
year = 0;
leap = 0;
GMT_TOKYO = 9*60*60;
SECONDS_IN_A_DAY = 24*60*60;
UNIX_EPOCH_DAY = 1969*365 + floor(1969/4) - floor(1969/100) + floor(1969/400) + 306; // days from 0000/03/01 to 1970/01/01
YEAR_ONE = 365;
YEAR_FOUR = YEAR_ONE * 4 + 1;
YEAR_100 = YEAR_FOUR * 25 - 1;
YEAR_400 = YEAR_100*4 + 1;
monthday = newArray (0,31,61,92,122,153,184,214,245,275,306,337);
unixtime = unixtime / 1000; //msec to sec
unixtime = unixtime + GMT_TOKYO;
second = floor(unixtime % 60);
minute = floor(unixtime / 60) % 60;
hour = floor(unixtime / 3600) % 24;
unixday = floor(unixtime / SECONDS_IN_A_DAY);
unixday = unixday + UNIX_EPOCH_DAY;
year = year + 400 * floor(unixday / YEAR_400);
unixday = unixday % YEAR_400 ;
n = floor(unixday / YEAR_100);
year = year + n * 100;
unixday = unixday % YEAR_100 ;
if (n == 4){
leap = 1;
}else{
year = year + 4 * floor(unixday / YEAR_FOUR);
unixday = unixday % YEAR_FOUR ;
n = floor(unixday / YEAR_ONE);
year = year + n;
unixday = unixday % YEAR_ONE ;
if (n == 4) {
leap = 1;
}
}
if (leap != 0) {
month = 2;
day = 29;
}else{
month = floor(((unixday + 0.4) * 5) / 153);
day = unixday - monthday[month] + 1;
month = month + 3;
if (month > 12) {
year++;
month = month - 12;
}
}
tokyotime = "" + year + "/" + zeroPad(month,2) + "/" + zeroPad(day,2) + " " + zeroPad(hour,2) + ":" +zeroPad(minute,2) + ":" + zeroPad(second,2);
return tokyotime;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//Define function zeroPadding
function zeroPad(int,digitZeroPad){
if(int < 0){
exit("ZeroPadding Error!! int<0");
}
stringInt = ""+int;
digitStringInt = lengthOf(stringInt);
digitSubtra = digitZeroPad-digitStringInt;
if(digitSubtra < 0){
exit("ZeroPadding Error!! digitSubtra<0");
}
if(digitZeroPad > 0){
for(i=0; i<digitSubtra; i++){
stringInt = "0"+stringInt;
}
}
return stringInt;
}
//-----------------------------------------------------------------------------
実行すると、unixtime「1621927895482 (msec)」は、「2021/05/25 16:31:35」であると出力されるはずです。
よく理解できていないけど大事なポイント
① 時差を修正
→グリニッジ標準時間と日本の時差が9時間なので、9×60×60秒を足す。
② 西暦0年3月1日からの日数に変換
→3月1日というのがミソ。最終日が平年なら2月28日、うるう年なら2月29日になる。最後の一日をカウントするのかしないのかを考えるだけで良いので、プログラムを組むのがラクになるらしい。
③ うるう年に注意して年数をカウント
→うるう年のルールは
1. 西暦の年号が4で割り切れるなら「うるう年」
2. でも、100で割り切れる年は「うるう年ではない」
3. それなのに、400で割り切れる年はやっぱり「うるう年」
このへんてこで複雑なルールを取り込んだうえで年数を正しくカウントするために、YEAR_400とかYEAR_ONEとかを使って場合分けしているみたい。
YEAR_FOURは4年間の日数。4年ごとにうるう年が1日来るからプラス1されて365×4+1日。YEAR_100は、100年に一度うるう年から除外する日が来るからYEAR_FOUR×25回分-1日。YEAR_400は、400年に一度除外ルールを無視してうるう年が来るのでYEAR_100×4回分+1日。
これらがunixday(単位は日数)の中に何回入るのかで、年数を計算してるっぽい。
④ 先人の知恵で月を算出
→謎アルゴリズムです。
month = floor(((unixday + 0.4) * 5) / 153); のあたり。
なぜこんなことに気付けるのでしょうか。考えた方の素晴らしさに敬意を払いつつ、そのまま使いましょう。
⑤ 日の算出
→3月1日からある月の初めまでの日数を配列monthdayにあらかじめテーブル化しておく。このテーブルと上で算出した「月」を使って、「unixday - その月の初めまでの日数」を計算することで、その月の何日なのかが計算されるらしい。
⑥ 仕上げ
→3月スタートだからmonthに+3する。13月、14月が計算で出てくるから-12して1月、2月に直す。終了。
実際に使ってみた
自炊した本を一覧化するマクロに「ファイル最終更新日」表示機能を盛り込んでみた。
おしまい
Thanks to