VC++で困惑した時刻関連処理まとめ

#背景
自分がVC++のコーディングする時、現在時刻の取得にはtime()を使っていましたが、ローカル時刻の変換を行うにあたりネット上で時刻関連処理で調べていると全然馴染みのない時刻関連の処理が沢山出てきたので、同様に困惑されている方の助けとなればと思い、主な時刻関連の関数の使用方法などをまとめてみました。
なお、今回の確認環境にはWindows7 Pro. SP1(64bit)、Microsoft Visual Studio Community 2013 Update 5を使用しています。

※2016/2/22 22:00 CTimeクラスの処理結果以降の箇所か加筆修正しました。
　詳細は編集履歴を参照ください。

#VC++で使用可能な時刻関連処理
VC++はC言語、C++、MFC、STL、ATLなど色々ライブラリがあるようですが、ざっと探して出てきた主な時刻関連処理、またはクラスは以下に含まれています。

1. time.h
2. Win32 API
3. atltime.h

##time.h
time()
gmtime_s()
localtime_s()
mktime()

MSDN
https://msdn.microsoft.com/ja-jp/library/634ca0c2.aspx


##Win32 API
GetSystemTime()
GetLocalTime()
SystemTimeToFileTime()
FileTimeToSystemTime()
FileTimeToLocalFileTime()

MSDN
https://msdn.microsoft.com/ja-jp/library/cc429379.aspx

##atltime.h
CTimeクラス

MSDN
https://msdn.microsoft.com/ja-jp/library/78zb0ese.aspx

#実際の使用例

今回のincludeはこんな感じです。

```lang:DateTimeConvert.cpp
#include "stdafx.h"
#include <iostream>
#include "time.h"
#include "atltime.h"

using namespace std;
```

ここから実際の処理です。
まずはtime.hの処理。

```lang:DateTimeConvert.cpp
	// 1. <time.h>
	time_t curUTC_sec;
	time_t cnvTime_sec;
	struct tm tmUTC;
	struct tm tmLocal;

	// Get Current Time(UTC sec.)
	time(&curUTC_sec);

	// UTC sec. -> UTC
	char ascstr[32];
	gmtime_s(&tmUTC, &curUTC_sec);
	asctime_s(ascstr, sizeof(ascstr), &tmUTC);
	cout << "tmUTC  :" << ascstr;

	// UTC sec. -> Local Time
	localtime_s(&tmLocal, &curUTC_sec);
	asctime_s(ascstr, sizeof(ascstr), &tmLocal);
	cout << "tmLocal:" << ascstr;
	cout << endl;

	// Local Time -> UTC sec.
	cnvTime_sec = mktime(&tmLocal);
	cout << "curUTC_sec  :" << curUTC_sec << endl;
	cout << "cnvTime_sec :" << cnvTime_sec << endl;
	cout << endl;

```

```lang:処理結果
tmUTC  :Sun Feb 21 03:06:16 2016
tmLocal:Sun Feb 21 12:06:16 2016

curUTC_sec  :1456023976
cnvTime_sec :1456023976
```

処理結果より
localtime_s()の処理結果がtmUTC+09:00となっており、ローカル時刻に変換されています。
また、mktime()でのtmLocalの変換処理結果がtime()の処理結果と同じ値となっています。

各処理の関係図は以下です。
![time_h.png](https://qiita-image-store.s3.amazonaws.com/0/58935/fab5ae78-74e8-7aad-447b-4b6f54b875b2.png)





続いてWin32 APIです。

```lang:DateTimeConvert.cpp
	// 2. Win32 API
	SYSTEMTIME st_UTC;
	SYSTEMTIME st_Local;

	// Get Current SYSTEMTIME
	GetSystemTime(&st_UTC);
	GetLocalTime(&st_Local);
	CTime ct1(st_UTC);
	CTime ct2(st_Local);
	CString ct_str1 = ct1.Format(L"st_UTC   = %Y/%m/%d %H:%M:%S \n");
	CString ct_str2 = ct2.Format(L"st_Local = %Y/%m/%d %H:%M:%S \n");
	cout << "Get Current SYSTEMTIME" << endl;
	_tprintf((LPCTSTR)ct_str1);
	_tprintf((LPCTSTR)ct_str2);
	cout << endl;

	cout << "SYSTEMTIME -> FILETIME" << endl;
	FILETIME ft;
	FILETIME ft_Local;
	SystemTimeToFileTime(&st_UTC, &ft);
	SystemTimeToFileTime(&st_Local, &ft_Local);
	CTime ct3(ft);
	CTime ct4(ft_Local);
	CString ct_str3 = ct3.Format(L"ft       = %Y/%m/%d %H:%M:%S \n");
	CString ct_str4 = ct4.Format(L"ft_Local = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)ct_str3);
	_tprintf((LPCTSTR)ct_str4);
	cout << endl;

	cout << "FILETIME -> SYSTEMTIME" << endl;
	SYSTEMTIME st_cnvFrom_ft;
	SYSTEMTIME st_cnvFrom_ft_Local;
	FileTimeToSystemTime(&ft, &st_cnvFrom_ft);
	FileTimeToSystemTime(&ft_Local, &st_cnvFrom_ft_Local);
	CTime ct5(st_cnvFrom_ft);
	CTime ct6(st_cnvFrom_ft_Local);
	CString ct_str5 = ct5.Format(L"st_From_ft       = %Y/%m/%d %H:%M:%S \n");
	CString ct_str6 = ct6.Format(L"st_From_ft_Local = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)ct_str5);
	_tprintf((LPCTSTR)ct_str6);
	cout << endl;

	cout << "FILETIME -> FILETIME(Local)" << endl;
	FILETIME ftLocal_From_ft;
	FILETIME ftLocal_From_ft_local;
	FileTimeToLocalFileTime(&ft, &ftLocal_From_ft);
	FileTimeToLocalFileTime(&ft_Local, &ftLocal_From_ft_local);
	CTime ct7(st_cnvFrom_ft);
	CTime ct8(st_cnvFrom_ft_Local);
	CString ct_str7 = ct7.Format(L"ftLocal_From_ft       = %Y/%m/%d %H:%M:%S \n");
	CString ct_str8 = ct8.Format(L"ftLocal_From_ft_local = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)ct_str7);
	_tprintf((LPCTSTR)ct_str8);
	cout << endl;
```

```lang:処理結果
Get Current SYSTEMTIME
st_UTC   = 2016/02/21 03:06:16
st_Local = 2016/02/21 12:06:16

SYSTEMTIME -> FILETIME
ft       = 2016/02/21 12:06:16
ft_Local = 2016/02/21 21:06:16

FILETIME -> SYSTEMTIME
st_From_ft       = 2016/02/21 03:06:16
st_From_ft_Local = 2016/02/21 12:06:16

FILETIME -> FILETIME(Local)
ftLocal_From_ft       = 2016/02/21 21:06:16
ftLocal_From_ft_local = 2016/02/22 06:06:16
```
処理結果で注目したいのは、
SystemTimeToFileTime()でローカル時刻に変換されています。
また、FileTimeToSystemTime()でUTC時刻に変換されています。
そのため、これらの処理使用時の注意点としてはローカル時刻を入力として扱う場合だといえます。
各処理の関係図は以下です。
![Qiita用画像 (5).png](https://qiita-image-store.s3.amazonaws.com/0/58935/4d14761a-ccf0-0e98-8c5b-580f383cc248.png)


最後にCTimeクラスです。

```lang:DateTimeConvert.cpp
	// 3. <atltime.h>
	cout << "Create CTime object using time_t" << endl;
	CTime curTime = CTime::GetTickCount();
	CString curTime_str = curTime.Format(L"curTime = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)curTime_str);
	cout << "curTime.GetTime() = " << curTime.GetTime() << endl;

	struct tm tm_curTime;
	struct tm tmLocal_curTime;
	curTime.GetGmtTm(&tm_curTime);
	curTime.GetLocalTm(&tmLocal_curTime);
	asctime_s(ascstr, sizeof(ascstr), &tm_curTime);
	cout << "tm_curTime     :" << ascstr;
	asctime_s(ascstr, sizeof(ascstr), &tmLocal_curTime);
	cout << "tmLocal_curTime:" << ascstr;
	cout << endl;

	cout << "Create CTime obj using SYSTEMTIME(Local)" << endl;
	CTime stime(st_UTC);
	CString stime_str = stime.Format(L"stime   = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)stime_str);
	cout << endl;

	cout << "Create CTime obj using FILETIME" << endl;
	CTime ftime(ft);
	CString ftime_str = ftime.Format(L"ftime   = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)ftime_str);
	cout << endl;

	cout << "Create CTime obj using time value" << endl;
		   // ( year, mon, day, hour, min, sec)
	CTime time( 2016,    1,   1,   0,   0,   0);
	CString time_str = time.Format(L"time    = %Y/%m/%d %H:%M:%S \n");
	_tprintf((LPCTSTR)time_str);
```


```lang:処理結果
Create CTime obj using time_t
curTime = 2016/02/21 12:06:16
curTime.GetTime() = 1456023976
tm_curTime     :Sun Feb 21 03:06:16 2016
tmLocal_curTime:Sun Feb 21 12:06:16 2016

Create CTime obj using SYSTEMTIME(Local)
stime   = 2016/02/21 03:06:16

Create CTime obj using FILETIME
ftime   = 2016/02/21 12:06:16

Create CTime obj using time value
time    = 2016/01/01 00:00:00
```
CTimeクラスのコンストラクタの引数としては以下が扱えます。
・CTime(\_time64_t) ※\_time64_tはUTC時刻

・CTime(const SYSTEMTIME&) ※SYSTEMTIMEはローカル時刻

・CTime(cost FILETIME&)　※FILETIMEはUTC時刻

・CTime(int,int…)　※int,int…はローカル時刻

また、CTime::GetTickCount()にて現在時刻の取得も行えます。
そして、CTimeオブジェクトからはSYSTEMTIMEやFILETIMEの値も取得できるので、VC++で時刻を扱う場合はCTimeオブジェクトで扱うのが良いと感じます。

##タイムゾーンを用いたローカル時刻からUTCへの変換(追記)
も書こうと思いましたが、以下のリンクにわかりやく説明されておりましたのでそちらを参考ください。

[VC++/MFC タイムゾーンによる日時変換 (JST->UTC)](http://www.northwind.mydns.jp/samples/blog/2013/02/26/vc-mfc-%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%BE%E3%83%BC%E3%83%B3%E3%81%AB%E3%82%88%E3%82%8B%E6%97%A5%E6%99%82%E5%A4%89%E6%8F%9B/)

##まとめ
**UTC時刻の取得**
・time()
・GetSystemTime()
・CTime::GetTickCount()

**UTC時刻→ローカル時刻への変換（一例です）**
1. 入力：time_t　→　localtime_s()
2. 入力：SYSTEMTIME　→　CTime(int,int) →　CTime::GetLocalTm()
3. 入力：FILETIME → FileTimeToLocalFileTime()

**ローカル時刻→UTC時刻への変換（一例です）**
1. 入力 struct tm → mktime()
2. 入力 SYSTEMTIME → CTime(SYSTEMTIME&) → Ctime::GetGmtTm() or CTime::GetTime()
3. 入力 FILETIME → FileTimeToSystemTime() → 

時刻処理について調べてみて、基本的にUTC時刻を基点とした時間管理を行うことが前提で各時刻処理が作られているように感じました。
~~そのため単にローカル時刻からUTC時刻を求めたい場合には、CTimeクラス使う場合はタイムゾーンを求めたりSYSTEMTIMEに変換する必要などがあり、time.hの関数を使ったほうが若干見ため的にもいいかもというとがわかりました。~~
取得したい変数の型で使い分けることが必要そうです。


##最後に
時刻を扱う上で注意すべき点の一つとして、最終的な変換結果を得る過程での出力結果がUTC時刻またはローカル時刻どちらなのかを理解しておくことだと思います。
今回紹介した内容がみなさんの参考になれば幸いです。
また、もっといい方法など有りましたらコメントいただけると助かります。