2018年5月4日金曜日

[MQL4] datetime を long にキャストすると 1970/1/1 からの秒になる

2018/6/12 追記
負数の扱いと最大値について加筆・修正しました。

参考

Datetime Type - Integer Types - Data Types - Language Basics - MQL4 Reference

公式ドキュメントによると、datetime は 1970/1/1 からの秒を格納する 8 bytes の型だそうです。 これは long と同じサイズで、相互変換が可能です。

どちらを使っていても動作上問題はないのですが、以下のような特徴があるので使い分けると良いでしょう。

  • datetime
    日付文字列との相互変換が容易。実際の日付を表す場合に使用。
  • long
    純粋な秒を表す場合に使用。

キャストしてみる

1
2
3
4
5
6
datetime date1 = D'2008.01.01';
long date1_sec = (long) date1;
printf("%lld", date1_sec);
 
// 結果
// 1199145600

この値、UNIX Time として知られている1もので、Linux 等では簡単に調べられます。

$ date -u --date='2008/01/01' +%s
1199145600

一致しました。

datetime にはタイムゾーンという概念がないので、どのタイムゾーンを表しているのかは別途考えなければなりません。

差分計算の結果は、long で受けた方が良い

上記定義より datetime と datetime の差分計算結果も datetime に格納することが出来ます。

1
2
3
4
5
6
7
datetime date1 = D'2008.01.01';
datetime date2 = D'2008.01.02';
datetime date3 = date2 - date1;
Print(TimeToString(date3, TIME_DATE));
 
// 結果
// 1970.01.02

差分結果が 1970.01.02 という意味のないものになってしまいました。

date3 に格納されている値は 1970/1/1 からの秒なので、使用時に long にキャストすれば実行上問題はありません。 しかし、せっかく相互変換が可能な型なのですから、実体を表した使い方をした方が良いだろうと思います。

つまり、以下のように差分は long で受ける方が自然です。

1
2
3
4
5
6
7
datetime date1 = D'2008.01.01';
datetime date2 = D'2008.01.02';
long time_delta = date2 - date1;
printf("%lld", time_delta);
 
// 結果
// 86400 (= 60 * 60 * 24)

なお、差分が4バイト2を超えるような計算は、特殊なケースに限られるはずです。 つまり、int で受けても実害はないと思われますが、メモリに余裕がある系ではそういった最適化はしない方が無難です。 最近の PC でメモリが枯渇することはあまり無いですよね?

差分が負になっても datetime で扱えるが、やはり long で受けた方が良い

以下のように、負の値を datetime に入れることも可能ですが、TimeToString() は正しく動作しません。 やはり、long で受けておく方が無難でしょう。

1
2
3
4
5
6
7
datetime date1 = D'2008.01.01';
datetime date2 = D'2008.01.02';
datetime date3 = date1 - date2;
printf("%s : %lld", TimeToString(date3, TIME_DATE), date3);
 
// 結果
// : -86400

最大値は 8bytes ではない

公式ドキュメントによれば、datetime の最大値は 3000/12/31 (≒ 0x7933FFF7F3)だそうです。 実際は 5bytes 程度ということですね。

ところで、正確な時間まで調べてみたところ、本当の最大値は 3001/01/01 07:59:59 になりました。

1
2
3
4
5
6
7
8
9
datetime date1 = 0x0793406FFF;
printf("%lld %s", date1, TimeToString(date1, TIME_DATE|TIME_MINUTES|TIME_SECONDS));
// 結果
// 32535244799 3001.01.01 07:59:59
 
datetime date2 = 0x0793407000;
printf("%lld %s", date2, TimeToString(date2, TIME_DATE|TIME_MINUTES|TIME_SECONDS));
// 結果
// 32535244800

環境依存の可能性もありますし、1000年近い未来の数時間など誤差でしかありませんが。

  1. UNIX Time は UTC 基準なので正確にはちょっと違う 
  2. 大体68年 
  3. 時間まで書いてないので「ほぼ」にしました 
?