【C++】C/C++における時間処理の備忘録

C言語のデータ型は主に、文字・数値・判定・時間・ポインタである。
今回はその中で、"時間"についての扱い方を紹介する。

## time_t型
```#include <time.h>```で呼べるグリニッチ標準時(GMT)で```1970/1/1 00:00:00```から現在までの経過"秒数"を返す型。返し値は秒[sec]単位であり、エラー時は-1を返し、1970年1月1日以前の時間はエラーとなり-1を返すことに注意。
## struct tm構造体
```#include <time.h>```の中で宣言され、time_tの変数を年・月・日・時・分・秒に分けることができる。

```c++
struct tm {
  int tm_sec;      /* 秒 [0-61] 最大2秒までのうるう秒を考慮 */
  int tm_min;      /* 分 [0-59] */
  int tm_hour;     /* 時 [0-23] */
  int tm_mday;     /* 日 [1-31] */
  int tm_mon;      /* 月 [0-11] 0から始まることに注意 */
  int tm_year;     /* 年 [1900からの経過年数] */
  int tm_wday;     /* 曜日 [0:日 1:月 ... 6:土] */
  int tm_yday;     /* 年内の通し日数 [0-365] 0から始まることに注意*/
  int tm_isdst;    /* 夏時間が無効であれば 0 */
  long tm_gmtoff;  /*グリニッジ時刻からのオフセット*/
  char *tm_zone;   /*タイムゾーン*/
};
```

使い方は以下のようにtime_t変数をlocaltime64で構造体に変換して変数に渡す。

```c++
struct tm when;
time_t tme = time(NULL);
when = *localtime64(&tme);
```

## strftime~struct tm構造体からstring型へ変換~
```#include <time.h>```で宣言されるstrftimeで、string型に任意の形式で変換できる。

```c++
strftime(datetime,sizeof(datetime),"%Y/%m/%d %H:%I:%S",&when);
```

## _mktime64~struct tm構造体からtime_t型変数へ変換~
```#include <time.h>```で宣言される_mktime64で、struct tm構造体を受け取りtime_t型を返す。

```c++
time_t new_t = _mktime64(&when)
```

## std::put_time~time_t型変数からstring型へ変換~
std::put_timeを使い、time_tをstringに変換したのち、ostringstream()で一度文字列ストリームへ受け渡し、string型変数へ渡している。

```c++
std::string longdate = static_cast<ostringstream&&>(ostringstream() << std::put_time(localtime(&t), "%Y/%m/%d %H:%M:%S")).str();
```
## string型からtime_t型への変換
ファイルを読み込んだ時、いろいろな書き方で日付を指定しているので、複数の場合分けをしてstruct tm構造体へ渡したのち、time_t型へ変換している。

```C++
   time_t string_to_time_t(string s)
  {
      int yy, mm, dd, hour, min, sec;
      struct tm when;
      time_t tme;
      size_t len = s.size();
 
      if (s[len-6]  == ':' ) {
        memset(&when, 0, sizeof(struct tm));
        sscanf(s.c_str(), "%d/%d/%d %d:%d:%d", &yy, &mm, &dd, &hour, &min, &sec);
        time(&tme);
        when = *_localtime64(&tme);
        when.tm_year = yy-1900;
        when.tm_mon = mm-1;
        when.tm_mday = dd;
        when.tm_hour = hour;
        when.tm_min = min;
        when.tm_sec = sec;
        return _mktime64(&when);     
      } else if (s[len-3]  == ':' ) {
        memset(&when, 0, sizeof(struct tm));
        sscanf(s.c_str(), "%d/%d/%d %d:%d", &yy, &mm, &dd, &hour, &min);
        time(&tme);
        when = *_localtime64(&tme);
        when.tm_year = yy-1900;
        when.tm_mon = mm-1;
        when.tm_mday = dd;
        when.tm_hour = hour;
        when.tm_min = min;
        when.tm_sec = 0;
        return _mktime64(&when); 
      } else if (s[len-3]  == ' ' ) {
        memset(&when, 0, sizeof(struct tm));
        sscanf(s.c_str(), "%d/%d/%d %d", &yy, &mm, &dd, &hour);
        time(&tme);
        when = *_localtime64(&tme);
        when.tm_year = yy-1900;
        when.tm_mon = mm-1;
        when.tm_mday = dd;
        when.tm_hour = hour;
        when.tm_min = 0;
        when.tm_sec = 0;
        return _mktime64(&when); 
      }else {
        memset(&when, 0, sizeof(struct tm));
        sscanf(s.c_str(), "%d/%d/%d", &yy, &mm, &dd);
        time(&tme);
        when = *_localtime64(&tme);
        when.tm_year = yy-1900;
        when.tm_mon = mm-1;
        when.tm_mday = dd;
        when.tm_hour = 0;
        when.tm_min = 0;
        when.tm_sec = 0;
        return _mktime64(&when);
      }
  }
 
```

## 基準時刻の変更

```c++
std::cout.imbue(std::locale("ja_JP.utf8"));
std::cout.imbue(std::locale("en_US.utf8"));/*英語 アメリカ*/
std::cout.imbue(std::locale("ar_EG.UTF-8"));/*アラビア語 エジプト*/
std::cout.imbue(std::locale("as_IN.UTF-8")); /*アッサム語 インド*/
std::cout.imbue(std::locale("de_DE.UTF-8"));/*ドイツ語 ドイツ*/
std::cout.imbue(std::locale("en_GB.UTF-8"));/*英語 イギリス*/
std::cout.imbue(std::locale("es_ES.UTF-8"));/*スペイン語 スペイン*/
std::cout.imbue(std::locale("fr_FR.UTF-8"));/*フランス語 フランス*/
std::cout.imbue(std::locale("it_IT.UTF-8"));/*イタリア語 イタリア*/
std::cout.imbue(std::locale("ko_KR.UTF-8"));/*韓国語*/
std::cout.imbue(std::locale("zh_CN.UTF-8"));/*中国語*/
```


## まとめ
今回はCにおける時間・日付の取り扱いについて紹介した。