2018年5月7日月曜日

[MQL4] string と datetime 型の相互変換方法5種

[string と datetime の加算演算は strict モードかどうかで動作が変わる](https://strategyofc.blogspot.com/2018/05/mql4-string-datetime-strict.html) に書いたように datetime の string への変換は明示的に行ったほうが良いと思います。

基本的には、MQL4 の固定フォーマット "yyyy.mm.dd hh:mi" を使うのが簡単ですが、独自のフォーマットで出力することも可能です後述するように、独自フォーマットの string を datetime に変換する際は注意が必要

### datetime を string にする方法1 (固定フォーマット)
[TimeToString()](https://docs.mql4.com/convert/timetostr) もしくは [TimeToStr()](https://docs.mql4.com/convert/timetostr) を使うのが簡単です多分、この2つの関数は全く同じだと思われる。

```mq4
datetime now = TimeLocal();

Print(TimeToString(now, TIME_DATE));               // 2018.05.04
Print(TimeToString(now, TIME_DATE|TIME_MINUTES));  // 2018.05.04 15:51
Print(TimeToString(now, TIME_DATE|TIME_SECONDS));  // 2018.05.04 15:51:12
Print(TimeToString(now, TIME_MINUTES));            // 15:51
Print(TimeToString(now, TIME_SECONDS));            // 15:51:12
```

### datetime を string にする方法2 (任意フォーマット)
上記の方法では特定のフォーマットに決まってしまいますが、任意のフォーマットにしたい場合は、一度 [MqlDateTime](https://docs.mql4.com/constants/structures/mqldatetime) に変換して[StringFormat()](https://docs.mql4.com/convert/stringformat) で整形すると良いでしょう。

```mq4
datetime now = TimeLocal();

MqlDateTime now_struct;
TimeToStruct(now, now_struct);

Print(StringFormat("%4d/%02d/%02d %02d:%02d",
                   now_struct.year,
                   now_struct.mon,
                   now_struct.day,
                   now_struct.hour,
                   now_struct.min)); // 2018/05/04 16:03
```

### datetime を string にする方法3 (任意フォーマット)
もしくは [TimeXXX](https://docs.mql4.com/dateandtime) 関数を使って、datetime を直接各値に変換することも可能です。

```mq4
datetime now = TimeLocal();

Print(StringFormat("%4d/%02d/%02d %02d:%02d",
                   TimeYear(now),
                   TimeMonth(now),
                   TimeDay(now),
                   TimeHour(now),
                   TimeMinute(now))); // 2018/05/04 16:42
```

一般的に、都度関数呼び出しの方がパフォーマンスが悪くなることが多いです。
ただ、MQL4 の仕様でどうなっているのかはわかりませんコンパイラが優秀だと、差はほとんどなかったりします。どちらにせよ、全体のパフォーマンスにはあまり影響しないだろうと思います。


### string を datetime にする方法1 (固定文字列)
先頭に 'D' をつけたシングルクォートで囲まれた文字列は datetime とみなされます。

```mq4
datetime date1 = D'2018.05.04 07:23:01';

// こちらはコンパイルエラー
datetime date2 = D'This is not a date string';
```

> 参考
>
> [Datetime Type - Integer Types - Data Types - Language Basics - MQL4 Reference](https://docs.mql4.com/basis/types/integer/datetime)

### string を datetime にする方法2
動的な string を datetime に変換する場合は、
[StringToTime()](https://docs.mql4.com/convert/stringtotime) もしくは [StrToTime()](https://docs.mql4.com/convert/strtotime) が使えます多分、この2つも全く同じ関数だと思われる。

```mq4
string date_string = "1970.01.01 01:00:00";

datetime date = StringToTime(date_string);
printf("%llu", date);                              // 3600
Print(TimeToString(date, TIME_DATE|TIME_SECONDS)); // 1970.01.01 01:00:00
```

> 参考
>
> [[MQL4] datetime を long にキャストすると 1970/1/1 からの秒になる | Strategy of C](https://strategyofc.blogspot.com/2018/05/mql4-datetime-long-197011.html)


この関数、下記のように多少フォーマットが異なっていても動作するようです。
しかし、公式のドキュメントに記述が無いので、使用する場合は慎重に確認した方が良いでしょう。

```mq4
`highlight: 1;
string date_string = "1970/01/01 01:00:00";

datetime date = StringToTime(date_string);
printf("%llu", date);                              // 3600
Print(TimeToString(date, TIME_DATE|TIME_SECONDS)); // 1970.01.01 01:00:00
```

なお、以下のように日付ではない文字列を変換した場合、実行時の日付、もしくは日時が入るようです本当はエラーを返してほしいが、MQL4 に例外は無いしな…。
時刻が入るかどうかは文字列によるようで、動作が微妙です。公式のドキュメントにも記述はありません。

想定外の文字列が入力される可能性のある系では、気をつけた方が良いでしょう。

```mq4
string no_date_string = "This is not a date string";
datetime date = StringToTime(no_date_string);
Print(TimeToString(date, TIME_DATE|TIME_SECONDS)); // 実行時の日時?
```