#include <cstdlib>
#include <ctime>
#include <stdexcept>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <chrono>
#include <vector>
#include <system_error>
using namespace std;
using namespace std::chrono;
namespace utils {
//文字列を指定したデリミタで分割する
inline vector<string> split(const string& s, char delim) {
vector<string> r;
istringstream istr(s);
for(string p; istr && getline(istr, p, delim); r.push_back(p));
return r;
}
//文字列を整数に変換する
inline int to_int(const string& s) {
auto r = atoi(s.c_str());
return (errno == 0) ? r : throw system_error();
}
//不完全なtime_tを返す
inline time_t to_time_t(int year, int month, int day, int hour, int minute, int second) {
tm tm;
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = minute;
tm.tm_sec = second;
return mktime(&tm);
}
//tmを正規化する
inline tm normalize(tm* tm) {
auto tt = mktime(tm);
return *localtime(&tt);
}
//tmを正規化する
inline tm normalize(tm& tm) {
return normalize(&tm);
}
}
//日時エラー
class DateTimeError : public range_error {
public:
//エラーメッセージを指定して初期化する
DateTimeError(const string& msg) : range_error(msg) {}
};
//日時クラスにオペレータを実装するテンプレートクラス
template<class T> class DateTimeOperators {
public:
bool operator<(const T& other) const { return static_cast<const T*>(this)->to_time_t() < other.to_time_t(); }
bool operator>(const T& other) const { return static_cast<const T*>(this)->to_time_t() > other.to_time_t(); }
bool operator<=(const T& other) const { return static_cast<const T*>(this)->to_time_t() <= other.to_time_t(); }
bool operator>=(const T& other) const { return static_cast<const T*>(this)->to_time_t() >= other.to_time_t(); }
bool operator==(const T& other) const { return static_cast<const T*>(this)->to_time_t() == other.to_time_t(); }
bool operator!=(const T& other) const { return static_cast<const T*>(this)->to_time_t() != other.to_time_t(); }
};
//年月日を表すクラス
class Date : public DateTimeOperators<Date> {
int m_year;
int m_month;
int m_day;
public:
//1900/01/01で初期化する
Date() : Date(1900, 1, 1) {}
//struct tmから初期化する
Date(const tm* tm) : Date(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday) {}
//年月日を指定して初期化する
Date(int year, int month, int day) {
set_year(year);
set_month(month);
set_day(day);
}
//年を返す
int get_year() const { return m_year; }
//月を返す
int get_month() const { return m_month; }
//日を返す
int get_day() const { return m_day; }
//年を設定する
void set_year(int year) {
if(year < 1900) throw DateTimeError("1900 <= year");
m_year = year;
}
//月を設定する
void set_month(int month) {
if(month <= 0 || 12 < month) throw DateTimeError("0 < month <= 12");
m_month = month;
}
//日を設定する
void set_day(int day) {
if(day <= 0 || 31 < day) throw DateTimeError("0 < day <= 31");
m_day = day;
}
//この年月日をtime_tで返す
time_t to_time_t() const { return utils::to_time_t(m_year, m_month, m_day, 0, 0, 0); }
};
//時分秒を表すクラス
class Time : public DateTimeOperators<Time> {
int m_hour;
int m_minute;
int m_second;
public:
//00:00:00で初期化する
Time() : Time(0, 0, 0) {}
//struct tmから初期化する
Time(const tm* tm) : Time(tm->tm_hour, tm->tm_min, tm->tm_sec) {}
//時分秒を指定して初期化する
Time(int hour, int minute, int second) {
set_hour(hour);
set_minute(minute);
set_second(second);
}
//時を返す
int get_hour() const { return m_hour; }
//分を返す
int get_minute() const { return m_minute; }
//秒を返す
int get_second() const { return m_second; }
//時を設定する
void set_hour(int hour) {
if(hour < 0 || 24 <= hour) throw DateTimeError("0 <= hour < 24");
m_hour = hour;
}
//分を設定する
void set_minute(int minute) {
if(minute < 0 || 60 <= minute) throw DateTimeError("0 <= minute < 60");
m_minute = minute;
}
//秒を設定する
void set_second(int second) {
if(second < 0 || 60 <= second) throw DateTimeError("0 <= second < 60");
m_second = second;
}
//この時分秒をtime_tで返す
time_t to_time_t() const { return utils::to_time_t(1900, 1, 1, m_hour, m_minute, m_second); }
};
//日時クラス
class DateTime : public DateTimeOperators<DateTime> {
Date m_date;
Time m_time;
public:
//1900/01/01 00:00:00で初期化する
DateTime() = default;
//struct tmから初期化する
DateTime(tm* tm) : m_date(tm), m_time(tm) {}
//Date, Timeから初期化する
DateTime(const Date& date, const Time& time) : m_date(date), m_time(time) {}
//年月日時分秒を指定して初期化する
DateTime(int year, int month, int day, int hour, int minute, int second) : m_date(year, month, day), m_time(hour, minute, second) {}
//年月日を返す
const Date& get_date() const { return m_date; }
//時分秒を返す
const Time& get_time() const { return m_time; }
//年月日を設定する
void set_date(const Date& date) { m_date = date; }
//時分秒を設定する
void set_time(const Time& time) { m_time = time; }
//この日時を書式に従って文字列に変換する
string strftime(const string& format) const{
auto tt = to_time_t();
auto tm = localtime(&tt);
char buf[100];
return (std::strftime(buf, 100, format.c_str(), tm) != 0) ? buf : throw DateTimeError("strftime()");
}
//この日時をtime_tで返す
time_t to_time_t() const {
return utils::to_time_t(
m_date.get_year(), m_date.get_month(), m_date.get_day(),
m_time.get_hour(), m_time.get_minute(), m_time.get_second());
}
//この日時をsystem_clock::time_pointで返す
system_clock::time_point to_point() const { return system_clock::from_time_t(to_time_t()); }
//system_clock::time_pointからDateTimeを作成する
static DateTime from_point(const system_clock::time_point& point) {
auto tt = system_clock::to_time_t(point);
auto tm = localtime(&tt);
return tm;
}
//ローカルタイムからDateTimeを作成する
static DateTime local() { return from_point(system_clock::now()); }
};
inline ostream& operator<<(ostream& ostr, const Date& date) {
ostr
<< setw(4) << setfill('0') << date.get_year() << "/"
<< setw(2) << setfill('0') << date.get_month() << "/"
<< setw(2) << setfill('0') << date.get_day();
return ostr;
}
inline istream& operator>>(istream& istr, Date& date) {
vector<int> nums;
{
string in;
istr >> in;
auto strs = utils::split(in, '/');
transform(strs.begin(), strs.end(), back_inserter(nums), utils::to_int);
if(nums.size() != 3) throw DateTimeError("nums.size() != 3");
}
auto it = nums.begin();
date.set_year(*it++);
date.set_month(*it++);
date.set_day(*it++);
return istr;
}
inline ostream& operator<<(ostream& ostr, const Time& time) {
ostr
<< setw(2) << setfill('0') << time.get_hour() << ":"
<< setw(2) << setfill('0') << time.get_minute() << ":"
<< setw(2) << setfill('0') << time.get_second();
return ostr;
}
inline istream& operator>>(istream& istr, Time& time) {
vector<int> nums;
{
string in;
istr >> in;
auto strs = utils::split(in, ':');
transform(strs.begin(), strs.end(), back_inserter(nums), utils::to_int);
if(nums.size() != 3) throw DateTimeError("nums.size() != 3");
}
auto it = nums.begin();
time.set_hour(*it++);
time.set_minute(*it++);
time.set_second(*it++);
return istr;
}
inline ostream& operator<<(ostream& ostr, const DateTime& datetime) {
ostr
<< datetime.get_date() << " "
<< datetime.get_time();
return ostr;
}
inline istream& operator>>(istream& istr, DateTime& datetime) {
Date date;
Time time;
istr >> date;
istr >> time;
datetime.set_date(date);
datetime.set_time(time);
return istr;
}
void test1() {
DateTime datetime;
cin >> datetime;
cout << __FUNCTION__ << " : " << datetime << endl;
}
void test2() {
auto datetime = DateTime::local();
cout << __FUNCTION__ << " : " << datetime << endl;
}
void test3() {
auto datetime = DateTime::local();
datetime = DateTime::from_point(datetime.to_point());
cout << __FUNCTION__ << " : " << datetime << endl;
}
void test4() {
auto datetime = DateTime::local();
cout << __FUNCTION__ << " : " << datetime.strftime("%Y/%m/%d %H:%M:%S (%%c='%c')") << endl;
}
void test5() {
vector<DateTime> datetimes = {
{1995, 11, 11, 5, 50, 22},
{2004, 12, 20, 3, 48, 16},
{2011, 9, 7, 21, 24, 32},
{2011, 9, 7, 21, 24, 31},
{2014, 3, 19, 18, 10, 20},
{2005, 7, 25, 13, 31, 12}};
sort(datetimes.begin(), datetimes.end());
cout << __FUNCTION__ << endl;
for(auto& datetime : datetimes) cout << datetime << endl;
}
int main()
try {
test1();
test2();
test3();
test4();
test5();
return 0;
} catch(const exception& err) {
//cerr << err.what() << endl;
cout << "ERROR " << err.what() << endl;
return 1;
}