1 #include "lib/datetime.hpp"
2 #include "lib/log.hpp"
3 
4 #define LOCALE_TIME_FORMAT "%X"
5 #define LOCALE_DATE_FORMAT "%x"
6 #define ISO_DATE_FORMAT "%Y-%m-%d"
7 #define ISO_DATE_TIME_FORMAT "%Y-%m-%dT%H:%M:%SZ"
8 
date_time(const date_time & date)9 lib::date_time::date_time(const date_time &date)
10 {
11 	tm = date.tm;
12 }
13 
date_time(int year,int month,int day,int hour,int minute,int second)14 lib::date_time::date_time(int year, int month, int day, int hour, int minute, int second)
15 {
16 	tm.tm_year = year - c_year_offset;
17 	tm.tm_mon = month - 1;
18 	tm.tm_mday = day;
19 	tm.tm_hour = hour;
20 	tm.tm_min = minute;
21 	tm.tm_sec = second;
22 }
23 
parse(const std::string & value)24 auto lib::date_time::parse(const std::string &value) -> lib::date_time
25 {
26 	lib::date_time date;
27 
28 	// First try to parse as full date and time
29 	date.parse(value, ISO_DATE_TIME_FORMAT);
30 
31 	// Then try to pars as date only
32 	if (!date.is_valid())
33 	{
34 		date.parse(value, ISO_DATE_FORMAT);
35 	}
36 
37 	// If it's still invalid, something is wrong
38 	if (!date.is_valid())
39 	{
40 		log::warn("Failed to parse \"{}\" as a date", value);
41 	}
42 
43 	return date;
44 }
45 
now()46 auto lib::date_time::now() -> lib::date_time
47 {
48 	lib::date_time date;
49 	auto time = std::time(nullptr);
50 	date.tm = *std::localtime(&time);
51 
52 	return date;
53 }
54 
now_utc()55 auto lib::date_time::now_utc() -> lib::date_time
56 {
57 	lib::date_time date;
58 	auto time = std::time(nullptr);
59 	date.tm = *std::gmtime(&time);
60 
61 	return date;
62 }
63 
seconds_since_epoch()64 auto lib::date_time::seconds_since_epoch() -> long
65 {
66 	return std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now()
67 		.time_since_epoch()).count();
68 }
69 
is_valid() const70 auto lib::date_time::is_valid() const -> bool
71 {
72 	return tm.tm_year > 0
73 		|| tm.tm_mon > 0
74 		|| tm.tm_mday > 0;
75 }
76 
parse(const std::string & value,const char * format)77 void lib::date_time::parse(const std::string &value, const char *format)
78 {
79 	std::istringstream ss(value);
80 	ss >> std::get_time(&tm, format);
81 }
82 
to_time() const83 auto lib::date_time::to_time() const -> std::string
84 {
85 	return format(LOCALE_TIME_FORMAT);
86 }
87 
to_date() const88 auto lib::date_time::to_date() const -> std::string
89 {
90 	return format(LOCALE_DATE_FORMAT);
91 }
92 
to_iso_date() const93 auto lib::date_time::to_iso_date() const -> std::string
94 {
95 	return format(ISO_DATE_FORMAT);
96 }
97 
to_iso_date_time() const98 auto lib::date_time::to_iso_date_time() const -> std::string
99 {
100 	return format(ISO_DATE_TIME_FORMAT);
101 }
102 
format(const char * format) const103 auto lib::date_time::format(const char *format) const -> std::string
104 {
105 	if (!is_valid())
106 	{
107 		return std::string();
108 	}
109 
110 	constexpr size_t buffer_size = 64;
111 	std::array<char, buffer_size> buffer;
112 	std::strftime(buffer.data(), buffer.size(), format, &tm);
113 	return std::string(buffer.data());
114 }
115 
get_second() const116 auto lib::date_time::get_second() const -> int
117 {
118 	return is_valid()
119 		? tm.tm_sec
120 		: 0;
121 }
122 
get_minute() const123 auto lib::date_time::get_minute() const -> int
124 {
125 	return is_valid()
126 		? tm.tm_min
127 		: 0;
128 }
129 
get_hour() const130 auto lib::date_time::get_hour() const -> int
131 {
132 	return is_valid()
133 		? tm.tm_hour
134 		: 0;
135 }
136 
get_day() const137 auto lib::date_time::get_day() const -> int
138 {
139 	return is_valid()
140 		? tm.tm_mday
141 		: 0;
142 }
143 
get_month() const144 auto lib::date_time::get_month() const -> int
145 {
146 	return 1 + (is_valid()
147 		? tm.tm_mon
148 		: 0);
149 }
150 
get_year() const151 auto lib::date_time::get_year() const -> int
152 {
153 	return c_year_offset + (is_valid()
154 		? tm.tm_year
155 		: 0);
156 }
157