LoginSignup
1
1

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-05-26

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

現場からは以上です。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1