JavaScript(以下、js)…ECMA-262のdate関数にハマってしまった。
やりたかったことは、
①phpで、ある日のunixタイムスタンプを取り
②jsのdate関数にunixタイムスタンプを渡し(jsで日付を成形して(2桁づめ))
③現在時間と、①の日付を比較してごにょごにょごにょ
がしたかった。
コード的には、(例えば今日:2014-07-23, ある任意の日:2014-07-30としよう)
①phpで、ある日のunixタイムスタンプを取り(Asia/Tokyoのタイムゾーン)
[code class=”php”]
$target_day = date(‘20140730’);
$target_dayStamp = strtotime($target_day); //unixタイムスタンプ
$target_day_msec = $target_dayStamp * 1000; //※unixタイムスタンプは秒、jsのdate関数へ渡せるのはミリ秒のため
//今日の時間もサーバ時間で変更したいので
$today = date(‘Ymd’);
$todayStamp = strtotime(); //unixタイムスタンプ
$today_msec = todayStamp * 1000; //unixタイムスタンプをミリ秒へ変更
[/code]
②jsのdate関数にunixタイムスタンプを渡し
(今、ajaxで上記コード①の$target_day_msecが帰ってきていると想定)
[code lang=”js”]
//ターゲットの日付(2014-07-30)
var targetDay_msec = data.target_day_msec; //ajaxでdata変数の中に値がわたっていると過程
var trD = new Date(targetDay_msec);
var targetDay = formateDate(trD); //formateDateは下記で自作
//今日
var today_msec = data.today_msec; //ajax返るdata変数の中に入っているとする
var tD = new Date(today_msec);
var today = formateDate(tD); //formateDateは下記で自作
//2桁詰めに変更する
function formateDate(d){
var y = d.getFullYear();
var m = d.getMonth()+1;
var d = d.getDate();
m = String(m).length <2 ? ‘0’+m:m;
d = String(d).length <2 ? ‘0’+d:d;
return ”+y+m+d;
}
[/code]
③現在時間と、①の日付を比較してごにょごにょごにょ
[code class=”js”]
if (today <= targetDay){ //上記コード②で定義した2つを比較
alert("ごにょごにょごにょ");
}
[/code]
と、こんな感じのコードを書いていた。
上記の様なめんどくさいフローを踏んだのは、js側でいろいろしたいけど、
時間はローカルマシンに依存ではなく、サーバ時間を利用したかったからなのですよ。
この苦悩はお分かりいただけると(きっと)思う。
が、しかし!
しかしですよ!
これ、同じタイムゾーンに属していれば問題なく動くんですが、
違うタイムゾーンに設定した状態でみると、動きがかわるんですよ!
上記のサーバ時間を、Asia/Tokyoで取得して、
JS側が動いている端末をCanadaあたりにすると、、、
見事に、1日ずれてくれるわけですよ!
どうやら、jsのdate関数が所属するタイムゾーンに従って勝手に修正を加えてくれているみたい?
(この辺、後ほど調査事項)
なので、修正を加えられた値に、本来の日本時間のズレ分を保管して上げれば、(きっと)正しい値がでるはず!
ということで、以下の様なUTCの日本時間分を補足する関数を作成
[code class=”js”]
//ミリ秒を渡してくることを前提、new Date(msec)の代わりに用いることを想定
function fixJapaneseTimeZone(d){
//d->unixタイムスタンプを渡す
var d = new Date(d);
var utcJapOffset = 9; //日本のUTC時差は+9時間
var utcJapOffset_hour = 60 * utcJapOffset; //540分
if (d.getTimezoneOffset() != utcJapOffset_hour){ //日本時間とはずれていれば処理
utc = d.getTime() + d.getTimezoneOffset()*60*1000;
utcJap = utcJapOffset*3600000; //60*60*1000
utcJap_result = utc + utcJap;
d = new Date(utcJap_result);
}
return d;
}
[/code]
上記関数を通すと、無事に想定どおりの時間を取得できました。
※下記を使っている端末(ex.MacBook Air!)の時間をいじって実行してみると、
違いがわかるはずです。
[code class=”html”]
<html>
<head>
<script type="text/javascript">
var a = 1406646000 * 1000; //echo date(‘Ymd’, 1406646000); -> 20140730
var d = new Date(a);
console.log("new Date(msec)の方(2014-07-30想定)", formateDate(d));
var d2 = fixJapaneseTimeZone(a); //日本時間で修正を加えた関数
console.log("日本時間を加えた修正Verの方(2014-07-30想定)", formateDate(d2));
var now = 1406041200 * 1000; //echo date(‘Ymd’, 1406041200); -> 20140723
var n = new Date(now);
console.log("new Date(msec)の方(2014-07-23想定)", formateDate(n));
var n2 = fixJapaneseTimeZone(now); //日本時間で修正を加えた関数
console.log("日本時間を加えた修正Verの方(2014-07-23想定)", formateDate(n2));
function formateDate(d){
var y = d.getFullYear();
var m = d.getMonth()+1;
var d = d.getDate();
m = String(m).length <2 ? ‘0’+m:m;
d = String(d).length <2 ? ‘0’+d:d;
return ”+y+m+d;
}
//ミリ秒を渡してくることを前提、new Date(msec)の代わりに用いることを想定
function fixJapaneseTimeZone(d){
//d->unixタイムスタンプを渡す
var d = new Date(d);
var utcJapOffset = 9; //日本のUTC時差は+9時間
var utcJapOffset_hour = 60 * utcJapOffset; //540分
if (d.getTimezoneOffset() != utcJapOffset_hour){ //日本時間とはずれていれば処理
utc = d.getTime() + d.getTimezoneOffset()*60*1000;
utcJap = utcJapOffset*3600000; //60*60*1000
utcJap_result = utc + utcJap;
d = new Date(utcJap_result);
}
return d;
}
</script>
</head>
<body>
</body>
</html>
[/code]
↓↓↓ 一応実行結果(MacでタイムゾーンをCanadaに設定後実行) ↓↓↓
[Log] new Date(msec)の方(2014-07-30想定) 20140729 (Untitled.html, line 6) [Log] 日本時間を加えた修正Verの方(2014-07-30想定) 20140730 (Untitled.html, line 8) [Log] new Date(msec)の方(2014-07-23想定) 20140722 (Untitled.html, line 13) [Log] 日本時間を加えた修正Verの方(2014-07-23想定) 20140723 (Untitled.html, line 15)
JSちゃんともっと仲良くならねば。
[amazonjs asin=”487311621X” locale=”JP” title=”開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質”]
[amazonjs asin=”479803892X” locale=”JP” title=”ECMA-262 Edition 5.1を読む”]