【C++】Ruby ライクな C++ Date クラス

C++ で日付を扱いたかったがうまくいかず、Ruby の Date クラスのような感じで C++ を使えるようなクラスを作りました。
Boost を使えば同様のクラスを使えると聞きましたが、Boost の導入がうまく行かなかったため自作。
SH_ は SharedLibrary(共通ライブラリ)を意味しています。

想定環境
OS : Windows10
IDE : Visual Studio 2015

```SH_Date.h
#ifndef SHDATE_H_
#define SHDATE_H_

#include <time.h>
#include <string>
#include <iostream>

using namespace std;

class SH_Date {
public:
	SH_Date();
	SH_Date(string str);
	SH_Date(long lYear, long lMonth, long lDay);
	virtual ~SH_Date();

	bool operator==(SH_Date &rSH_Date);
	bool operator!=(SH_Date &rSH_Date);
	SH_Date operator=(SH_Date &rSH_Date);
	SH_Date operator+(long lAdjDayNum);
	SH_Date operator+=(long lAdjDayNum);
	SH_Date operator++(int);
	SH_Date operator-(long lAdjDayNum);
	SH_Date operator-=(long lAdjDayNum);
	SH_Date operator--(int);
	bool operator > (SH_Date &rSH_Date);
	bool operator >= (SH_Date &rSH_Date);
	bool operator < (SH_Date &rSH_Date);
	bool operator <= (SH_Date &rSH_Date);

	SH_Date setToday();
	void setStrDate(string strDate);

	string toString() const;

	bool getNowDateTime(tm* tm);
	time_t getNowTimeStamp();

	// time_t から tm* 型に変換
	bool transTimeStampToDateTime(time_t timer, tm* tm);

	// tm* から tiemr_t に変換
	time_t transDateTimeToTimeStamp(tm* tm);

	// 文字列から time_t 型に変換
	// yyyy-mm-dd HH:MM:SS
	time_t get_t_time_from_string(const char *timebuf);

	SH_Date transTimeStampToSH_Date(time_t* timer);

	SH_Date transTmToSH_Date(struct tm tm);

	void print();

	long getLDay() const;
	long getLMonth() const;
	long getLYear() const;


private:
	long m_lYear;
	long m_lMonth;
	long m_lDay;


};

inline long SH_Date::getLDay() const {
	return m_lDay;
}

inline long SH_Date::getLMonth() const {
	return m_lMonth;
}

inline long SH_Date::getLYear() const {
	return m_lYear;
}

#endif /* SHDATE_H_ */
```

``` SH_Date.cpp
#include "SH_Date.h"

#include <iostream>
#include <string>
#include <sstream>


#define N 20 // "yyyy/mm/dd hh:mm:ss" の表示文字数

using namespace std;

SH_Date::SH_Date()
	: m_lYear(0),
	m_lMonth(0),
	m_lDay(0) {

}

SH_Date::SH_Date(long lYear, long lMonth, long lDay)
	: m_lYear(lYear),
	m_lMonth(lMonth),
	m_lDay(lDay) {
	if (m_lYear < 1900) {
		m_lYear += 1900;
	}
}

SH_Date::SH_Date(string strDate) {
	// yyyy/mm/dd をそれぞれ属性に分ける

	size_t lMonthPos = strDate.find("/");
	size_t lDayPos = strDate.find("/", lMonthPos + 1);
	string strYear = strDate.substr(0, lMonthPos);
	string strMonth = strDate.substr(lMonthPos + 1, lDayPos - lMonthPos - 1);
	string strDay = strDate.substr(lDayPos + 1, strDate.length() - lDayPos - 1);

	cout << "strDate : " + strDate << endl;

	cout << "year : " + strYear << endl;
	cout << "month : " + strMonth << endl;
	cout << "day : " + strDay << endl;

	m_lYear = stol(strYear);
	m_lMonth = stol(strMonth);
	m_lDay = stol(strDay);
}


SH_Date::~SH_Date() {

}

bool SH_Date::getNowDateTime(tm* tm) {
	time_t timer;
	char datetime[N];
	timer = time(0);
	errno_t err;

	err = localtime_s(tm, &timer);
	strftime(datetime, N, "%Y/%m/%d %H:%M:%S", tm);

	string sDateTime = datetime;

	return true;
}

time_t SH_Date::getNowTimeStamp() {
	time_t epoch_time;
	epoch_time = time(0);
	cout << "TIMESTAMP =" + to_string(epoch_time) << endl;

	return epoch_time;
}


bool SH_Date::transTimeStampToDateTime(time_t timer, tm* tm) {
	char datetime[N];
	errno_t err;

	err = localtime_s(tm, &timer);

	strftime(datetime, N, "%Y/%m/%d %H:%M:%S", tm);
	string sDateTime = datetime;

	return true;
}

string SH_Date::toString() const {
	stringstream strYear;
	stringstream strMonth;
	stringstream strDay;

	strYear << m_lYear;
	strMonth << m_lMonth;
	strDay << m_lDay;

	string reStr = strYear.str() + "/" + strMonth.str() + "/" + strDay.str();

	return reStr;

}

time_t SH_Date::transDateTimeToTimeStamp(tm* tm) {
	if (tm == 0) {
		cout << "SH_Date::transDateTimeToTimeStamp tm is 0 " << endl;
	}
	return mktime(tm);
}

time_t SH_Date::get_t_time_from_string(const char *timebuf)
{
	int res;
	int year, month, day, hour, minute, second = 0;
	// char wday[36];
	struct tm tm;

	if (strlen(timebuf)>36) {
		return 0;
	}

	/* old version */
	res = sscanf_s(timebuf, "%d-%d-%d %d:%d:%d",
		&year, &month, &day,
		&hour, &minute, &second);

	/* format error */
	if (res < 1) {
		return 0;
	}

	tm.tm_sec = second;
	tm.tm_min = minute;
	tm.tm_hour = hour;
	tm.tm_mday = day;
	tm.tm_mon = month - 1;
	tm.tm_year = year - 1900;
	tm.tm_isdst = -1;

	return mktime(&tm);
}

// timer から SH_Date 変換
SH_Date SH_Date::transTimeStampToSH_Date(time_t* timer)
{
	struct tm tm;
	// 一度 tm 型に変換
	transTimeStampToDateTime(*timer, &tm);

	return SH_Date(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
}

SH_Date SH_Date::transTmToSH_Date(tm tm)
{
	// 直接年月日を入れると有り得ない年月日でも
	// 戻してしまうため、一度mktimeで正す
	time_t timer = transDateTimeToTimeStamp(&tm);

	return transTimeStampToSH_Date(&timer);
}

bool SH_Date::operator==(SH_Date &rSH_Date) {
	if (m_lYear != rSH_Date.getLYear()) {
		return false;
	}
	if (m_lMonth != rSH_Date.getLMonth()) {
		return false;
	}
	if (m_lDay != rSH_Date.getLDay()) {
		return false;
	}
	return true;
}

bool SH_Date::operator!=(SH_Date & rSH_Date)
{
	if (m_lYear != rSH_Date.getLYear()) {
		return true;
	}
	if (m_lMonth != rSH_Date.getLMonth()) {
		return true;
	}
	if (m_lDay != rSH_Date.getLDay()) {
		return true;
	}
	return false;
}

SH_Date SH_Date::operator=(SH_Date &rSH_Date) {
	m_lYear = rSH_Date.getLYear();
	m_lMonth = rSH_Date.getLMonth();
	m_lDay = rSH_Date.getLDay();
	return *this;
}

SH_Date SH_Date::operator+(long lAdjDayNum)
{
	// 一度 tm 型に変換
	struct tm adjTm = { 0, 0, 0, m_lDay + lAdjDayNum, m_lMonth - 1, m_lYear - 1900 };

	time_t adjTime = mktime(&adjTm);

	SH_Date rSH_Date = transTimeStampToSH_Date(&adjTime);

	return rSH_Date;
}

SH_Date SH_Date::operator+=(long lAdjDayNum)
{
	*this = *this + lAdjDayNum;
	return *this;
}

SH_Date SH_Date::operator++(int)
{
	*this = *this + 1;
	return *this;
}

SH_Date SH_Date::operator-(long lBeforeDayNum) {

	// 一度 tm 型に変換
	struct tm adjTm = { 0, 0, 0, m_lDay - lBeforeDayNum, m_lMonth - 1, m_lYear - 1900 };

	// struct tm tomorrowStruct = { 0, 0, 0, beforeTm.tm_mday + 1, beforeTm.tm_mon, beforeTm.tm_year };
	time_t adjTime = mktime(&adjTm);

	// SH_Date* pSH_Date = transTmToSH_Date(beforeTm);
	SH_Date rSH_Date = transTimeStampToSH_Date(&adjTime);

	return rSH_Date;
}

SH_Date SH_Date::operator-=(long lAdjDayNum)
{
	*this = *this - lAdjDayNum;
	return *this;
}

SH_Date SH_Date::operator--(int)
{
	*this = *this - 1;
	return *this;
}

SH_Date SH_Date::setToday() {
	struct tm now;
	time_t longtime;

	longtime = time(0);

	localtime_s(&now, &longtime);

	*this = transTmToSH_Date(now);

	return transTmToSH_Date(now);
}

void SH_Date::setStrDate(string strDate)
{
	size_t lMonthPos = strDate.find("/");
	size_t lDayPos = strDate.find("/", lMonthPos + 1);
	string strYear = strDate.substr(0, lMonthPos);
	string strMonth = strDate.substr(lMonthPos + 1, lDayPos - lMonthPos - 1);
	string strDay = strDate.substr(lDayPos + 1, strDate.length() - lDayPos - 1);

	m_lYear = stol(strYear);
	m_lMonth = stol(strMonth);
	m_lDay = stol(strDay);
}


bool SH_Date::operator>(SH_Date &rSH_Date)
{
	struct tm thisTm = { 0, 0, 0, m_lDay, m_lMonth - 1, m_lYear - 1900 };
	struct tm compTm = { 0, 0, 0, rSH_Date.m_lDay, rSH_Date.m_lMonth - 1, rSH_Date.m_lYear - 1900 };

	time_t thisTime = mktime(&thisTm);
	time_t compTime = mktime(&compTm);

	if (thisTime > compTime) {
		return true;
	}

	return false;
}

bool SH_Date::operator>=(SH_Date &rSH_Date)
{
	struct tm thisTm = { 0, 0, 0, m_lDay, m_lMonth - 1, m_lYear - 1900 };
	struct tm compTm = { 0, 0, 0, rSH_Date.m_lDay, rSH_Date.m_lMonth - 1, rSH_Date.m_lYear - 1900 };

	time_t thisTime = mktime(&thisTm);
	time_t compTime = mktime(&compTm);

	if (thisTime >= compTime) {
		return true;
	}

	return false;
}

bool SH_Date::operator<(SH_Date &rSH_Date)
{
	struct tm thisTm = { 0, 0, 0, m_lDay, m_lMonth - 1, m_lYear - 1900 };
	struct tm compTm = { 0, 0, 0, rSH_Date.m_lDay, rSH_Date.m_lMonth - 1, rSH_Date.m_lYear - 1900 };

	time_t thisTime = mktime(&thisTm);
	time_t compTime = mktime(&compTm);

	if (thisTime > compTime) {
		return true;
	}
	return false;
}

bool SH_Date::operator<=(SH_Date &rSH_Date)
{
	struct tm thisTm = { 0, 0, 0, m_lDay, m_lMonth - 1, m_lYear - 1900 };
	struct tm compTm = { 0, 0, 0, rSH_Date.m_lDay, rSH_Date.m_lMonth - 1, rSH_Date.m_lYear - 1900 };

	time_t thisTime = mktime(&thisTm);
	time_t compTime = mktime(&compTm);

	if (thisTime <= compTime) {
		return true;
	}
	return false;
}

void SH_Date::print()
{
	cout << "SH_Date print " + to_string(m_lYear) + "/" + to_string(m_lMonth) + "/" + to_string(m_lDay) << endl;
}
```

**テストコード**

```main.cpp
#include "TestMain.h"
#include "SH_Date.h"
#include <iostream>

using namespace std;
int main() {
	SH_Date rToday;
	// 本日日付を設定し表示
	rToday.setToday();
	rToday.print();

	SH_Date rTomorrow;
	rTomorrow = rToday++;
	if (rToday <= rTomorrow) {
		cout << "rTomorrow は rToday 以降です" << endl;
	}

	SH_Date rYesterday;
	rYesterday = rToday--;
	if (rYesterday <= rToday) {
		cout << "rYesterday は rToday 以前です" << endl;
	}

	// 10日後
	(rToday + 10).print();

	// 50日前
	(rToday - 50).print();


	long lInput;
	cin >> lInput;
}
```

**テストコード結果**

```
SH_Date print 2018/7/7
rTomorrow は rToday 以降です
rYesterday は rToday 以前です
SH_Date print 2018/7/17
SH_Date print 2018/5/18
```

現場からは以上です。