#pragma once
#include <time.h>

//!	最大文字数
#define	MAX_TIME_FORMAT_LEN	256

/*!
	time_t ラッパ
*/
class CTime_t
{
public:
	/////////////////////////////////////////////////////////////////////
	//	初期化
	/////////////////////////////////////////////////////////////////////
	//!	現時刻を取得
	static CTime_t GetCurrentTime()
	{
		return(CTime_t(::_time64( NULL )));
	}

	//!	ノーマルコンストラクタ
	CTime_t(void)
	{
		m_time = 0;
	}

	//!	コピーコンストラクタ
	CTime_t(const CTime_t &time)
	{
		m_time = time.m_time;
	}

	//!	time_tコンストラクタ
	CTime_t(const __time64_t time)
	{
		m_time = time;
	}

	//!	全要素指定
	CTime_t(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec)
	{
		SetTime(nYear, nMonth, nDay, nHour, nMin, nSec);
	}

	//!	SYSTEMTIMEコンストラクタ
	CTime_t(const SYSTEMTIME& st)
	{
		*this = st;
	}

	//!	FILETIMEコンストラクタ
	CTime_t(const FILETIME& ft)
	{
		*this = ft;
	}

	/////////////////////////////////////////////////////////////////////
	//	代入
	/////////////////////////////////////////////////////////////////////
	//!	time_t
	CTime_t& operator=(const CTime_t &time)
	{
		m_time = time.m_time;
	}

	//!	CTime_t
	CTime_t& operator=(const __time64_t time)
	{
		m_time = time;
	}

	//!	SYSTEMTIME
	CTime_t& operator=(const SYSTEMTIME& sysTime)
	{
		if(sysTime.wYear < 1900)
		{
			*this = (__time64_t)0;
		}
		else
		{
			CTime_t timeT(
				(int)sysTime.wYear, (int)sysTime.wMonth, (int)sysTime.wDay,
				(int)sysTime.wHour, (int)sysTime.wMinute, (int)sysTime.wSecond);
			*this = timeT;
		}
		return(*this);
	}

	//!	FILETIME
	CTime_t& operator=(const FILETIME& fileTime)
	{
		// まずは、ローカルタイムへ変換
		FILETIME localTime;
		if(!FileTimeToLocalFileTime(&fileTime, &localTime))
		{
			m_time = 0;
			return(*this);
		}

		// システムタイムへ
		SYSTEMTIME sysTime;
		if(!FileTimeToSystemTime(&localTime, &sysTime))
		{
			m_time = 0;
			return(*this);
		}

		//	システムタイム経由で変換
		*this = sysTime;
		return(*this);
	}

	//!	時間を指定してセット
	CTime_t& SetTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec)
	{
		ASSERT( nYear >= 1900 );
		ASSERT( nMonth >= 1 && nMonth <= 12 );
		ASSERT( nDay >= 1 && nDay <= 31 );
		ASSERT( nHour >= 0 && nHour <= 23 );
		ASSERT( nMin >= 0 && nMin <= 59 );
		ASSERT( nSec >= 0 && nSec <= 59 );

		struct tm atm;
		atm.tm_sec = nSec;
		atm.tm_min = nMin;
		atm.tm_hour = nHour;
		atm.tm_mday = nDay;
		atm.tm_mon = nMonth - 1;
		atm.tm_year = nYear - 1900;
		atm.tm_isdst = -1;
		m_time = _mktime64(&atm);

		ASSERT( m_time != -1 );
		return(*this);
	}


	/////////////////////////////////////////////////////////////////////
	//	取得
	/////////////////////////////////////////////////////////////////////
	//!	__time64_t取得
	__time64_t GetTime_t()
	{
		return m_time;
	}
	
	/////////////////////////////////////////////////////////////////////
	//	Format
	/////////////////////////////////////////////////////////////////////
	//!	書式化
	CUTF8String Format(CUTF8String format, ...) const
	{
		if(format.IsEmpty())
			return format;

		//	変換
		struct tm ptm;
		if(_localtime64_s(&ptm, &m_time))
			return(_U8(""));

		//	出力
		utf8_char line[MAX_TIME_FORMAT_LEN] = "";
		strftime((LPSTR)line, MAX_TIME_FORMAT_LEN, (LPCSTR)format.GetString(), &ptm);

		return line;
	}

	//!	書式化
	CUTF8String FormatGMT(CUTF8String format, ...) const
	{
		if(format.IsEmpty())
			return format;

		//	GMT取得
		CTime_t	temp(*this);
		temp.ConvertLocalTimeToGMT();

		//	変換
		struct tm ptm;
		if(_localtime64_s(&ptm, &temp.m_time))
			return(_U8(""));

		//	出力
		utf8_char line[MAX_TIME_FORMAT_LEN] = "";
		strftime((LPSTR)line, MAX_TIME_FORMAT_LEN, (LPCSTR)format.GetString(), &ptm);

		return line;
	}

	/////////////////////////////////////////////////////////////////////
	//	操作
	/////////////////////////////////////////////////////////////////////
	/*!
		ローカル時間へ変換
	*/
	void ConvertGMTToLocalTime()
	{
		//	タイムゾーン取得
		TIME_ZONE_INFORMATION	zoneInfo;
		::GetTimeZoneInformation(&zoneInfo);

		//	タイムゾーンに合わせて変換
		m_time -= (zoneInfo.Bias * 60);
	}

	/*!
		GMT/UTCへ変換
	*/
	void ConvertLocalTimeToGMT()
	{
		//	タイムゾーン取得
		TIME_ZONE_INFORMATION	zoneInfo;
		::GetTimeZoneInformation(&zoneInfo);

		//	タイムゾーンに合わせて変換
		m_time += (zoneInfo.Bias * 60);
	}

protected:
	/////////////////////////////////////////////////////////////////////
	//	メンバ変数
	/////////////////////////////////////////////////////////////////////
	//!	保持
	__time64_t	m_time;
};
