Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

1. 关键词

C++ 时间处理 日期时间类 跨平台

2. 问题

为什么C++就没有一个方便好用的表示日期时间的类?

同样是高级语言,Java中有Date,C#中有DateTime,Python中有datetime,为什么C++就没有一个方便好用的表示日期时间的类?我觉得这是C++ STL的遗憾,在这个点上做的是挺失败的。C++11之前,处理日期时间一般都会用C语言函数,如:localtime, gmtime, mktime, gettimeofday, put_time等。C++11之后,引入了chrono库,做到了时间处理的跨平台化和标准化,时间精度也支持到了纳秒级,但是chrono库的用法非常累赘,一点也不简洁,如:要以毫秒为单位获取当前时间戳,他的实现要写以下这么一长串的代码。

1
2
3
auto now = std::chrono::system_clock::now();
auto timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
auto ms = static_cast<uint64_t>(timestamp_ms);

那~ 有没有更简洁、漂亮的实现方式呢?

答案是:自己写一个!

3. 设计理念

  • 极简
  • 易用
  • 跨平台

4. 支持的能力

  • 获取当前时间
  • 获取UTC时间
  • 格式化时间
  • 从字符串解析时间
  • 时间差计算
  • 时间精度:毫秒级

5. 代码实现

5.1. datetime.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#pragma once

#include <cstdint>
#include <string>
#include <iostream>
#include <regex>
#include <vector>
#include <utility>

namespace cutl
{
/**
* @brief the string datetime format for parsing and formatting
*
*/
enum class datetime_format
{
/** YYYY-MM-DD HH:MM:SS.sss */
datetime_format_a,
/** YYYY.MM.DD HH:MM:SS */
datetime_format_b,
/** YYYY/MM/DD HH:MM:SS */
datetime_format_c,
/** YYYYMMDD HH:MM:SS */
datetime_format_d,
};

/**
* @brief A simple, feature-rich modern C++ date-time class
*
*/
class datetime
{
public:
/**
* @brief Constants value: second, expressed in milliseconds.
*
*/
static constexpr int second = 1000;
/**
* @brief Constants value: min, expressed in milliseconds.
*
*/
static constexpr int min = 60 * second;
/**
* @brief Constants value: hour, expressed in milliseconds.
*
*/
static constexpr int hour = 60 * min;
/**
* @brief Constants value: day, expressed in milliseconds.
*
*/
static constexpr int day = 24 * hour;

public:
/**
* @brief Construct a new datetime object
*
* @param ms a timestamp in milliseconds for initialize the datetime object
*/
datetime(uint64_t ms);

/**
* @brief Construct a new datetime object
*
* @param other other datetime object to copy
*/
datetime(const datetime &other);

/**
* @brief Destroy the datetime object
*
*/
~datetime();

private:
datetime();

public:
/**
* @brief Get a datetime object for the current system time
*
* @return datetime object for the current system time
*/
static datetime now();

/**
* @brief Constructs a datetime object from a local time string.
*
* Only the following time formats are supported:
* - YYYY-MM-DD HH:MM:SS.sss
* - YYYY-MM-DD HH:MM:SS
* - YYYY.MM.DD HH:MM:SS.sss
* - YYYY.MM.DD HH:MM:SS
* - YYYY/MM/DD HH:MM:SS.sss
* - YYYY/MM/DD HH:MM:SS
* - YYYYMMDD HH:MM:SS.sss
* - YYYYMMDD HH:MM:SS
* @param time_text local time string, use the below formats to construct a datetime object.
* @param isdst the setting of daylight saving time, -1 means system automatically determine, 0 means not in daylight saving time, 1 means in daylight saving time
* @return datetime object constructed from the local time string
*/
static datetime get(const std::string &time_text, int isdst = -1);

public:
/**
* @brief Get the timestamp in milliseconds
*
* @return the timestamp in milliseconds
*/
uint64_t timestamp() const;
/**
* @brief format the datetime object to a string
*
* @param dfmt datetime format, a value of datetime_format enum, default is datetime_format_a
* @param local whether to use local time, default is true. if true means output in local time, otherwise, output in UTC time.
* @param show_milliseconds whether to show milliseconds, default is true. if true means show milliseconds, otherwise, not show milliseconds.
* @return formatted datetime string described by std::string
*/
std::string format(datetime_format dfmt = datetime_format::datetime_format_a, bool local = true, bool show_milliseconds = true) const;
// fmt, usages like std::put_time

/**
* @brief Format the datetime object to a string with a custom format string
*
* @param fmt datetime format string, default is "%Y-%m-%d %H:%M:%S.%f". usages like std::put_time, reference to https://en.cppreference.com/w/cpp/io/manip/put_time
* @param local whether to use local time, default is true. if true means output in local time, otherwise, output in UTC time.
* @param show_milliseconds whether to show milliseconds, default is true. if true means show milliseconds, otherwise, not show milliseconds.
* @return formatted datetime string described by std::string
*/
std::string format(const std::string &fmt, bool local = true, bool show_milliseconds = true) const;

/**
* @brief Get the string of UTC time described by datetime object
*
* @return the string of UTC time in format "YYYY-MM-DD HH:MM:SS.sss"
*/
std::string utctime() const
{
return format(datetime_format::datetime_format_a, false);
}

/**
* @brief Define the assignment operator
*
* @param other other datetime object to copy
* @return datetime& the reference of the current datetime object
*/
datetime &operator=(const datetime &other);

/**
* @brief Define the addition operator
*
* @param ms milliseconds to add
* @return datetime object after adding milliseconds
*/
datetime operator+(uint64_t ms);

/**
* @brief Define the subtraction operator
*
* @param ms milliseconds to subtract
* @return datetime object after subtracting milliseconds
*/
datetime operator-(uint64_t ms);

/**
* @brief Define the addition and assignment operator
*
* @param ms milliseconds to add
* @return datetime& the reference of the current datetime object after adding milliseconds
*/
datetime &operator+=(uint64_t ms);

/**
* @brief Define the subtraction and assignment operator
*
* @param ms milliseconds to subtract
* @return datetime& the reference of the current datetime object after subtracting milliseconds
*/
datetime &operator-=(uint64_t ms);

/**
* @brief Define the subtraction operator between two datetime objects
*
* @param other datetime object to subtract
* @return the duration in milliseconds between current and other datetime objects
*/
int64_t operator-(const datetime &other) const;

private:
using time_regex_type = std::pair<std::string, std::regex>;
using time_regex_vec_type = std::vector<time_regex_type>;
static std::string supported_time_formats(const time_regex_vec_type &fmtlist);
static bool verify_time(const struct tm &time);

private:
uint64_t timestamp_ms_;
};

/**
* @brief Define the output stream operator for datetime object
*
* @param os the std::ostream object
* @param dt the datetime object to be output
* @return std::ostream& the reference of the std::ostream object after outputting the datetime object
*/
std::ostream &operator<<(std::ostream &os, const datetime &dt);

} // namespace

5.2. datetime.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#include "datetime.h"
#include "timeutil.h"
#include "strfmt.h"
#include "inner/logger.h"

namespace cutl
{
datetime::datetime(const datetime &other)
{
timestamp_ms_ = other.timestamp_ms_;
}

datetime::datetime()
{
timestamp_ms_ = 0;
}

datetime::datetime(uint64_t ms) : timestamp_ms_(ms)
{
}

datetime::~datetime()
{
}

datetime datetime::now()
{
return datetime(cutl::timestamp(timeunit::ms));
}

datetime datetime::get(const std::string &time_text, int isdst)
{
std::smatch matchRes;
bool result = false;
static time_regex_vec_type fmt_list = {
// 0/1, 2/3, 4/5, 6/7的顺序不能反,因为不含毫秒数的时间会被优先匹配到
std::make_pair("YYYY-MM-DD HH:MM:SS.sss", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
std::make_pair("YYYY-MM-DD HH:MM:SS", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
std::make_pair("YYYY.MM.DD HH:MM:SS.sss", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
std::make_pair("YYYY.MM.DD HH:MM:SS", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
std::make_pair("YYYY/MM/DD HH:MM:SS.sss", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
std::make_pair("YYYY/MM/DD HH:MM:SS", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
std::make_pair("YYYYMMDD HH:MM:SS.sss", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
std::make_pair("YYYYMMDD HH:MM:SS", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
};
for (size_t i = 0; i < fmt_list.size(); i++)
{
auto &fmt_text = fmt_list[i].first;
auto &fmt_pattern = fmt_list[i].second;
result = std::regex_search(time_text, matchRes, fmt_pattern);
if (result)
{
CUTL_DEBUG("matched regex: " + fmt_text);
break;
}
}

if (!result || matchRes.size() < 7)
{
auto time_fmts = supported_time_formats(fmt_list);
CUTL_ERROR("Only the following time formats are supported:\n" + time_fmts);
return datetime();
}

CUTL_DEBUG("matchRes size:" + std::to_string(matchRes.size()) + ", res:" + matchRes[0].str());
// 解析毫秒值
int ms = 0;
if (matchRes.size() == 8)
{
ms = std::stoi(matchRes[7].str());
}
// 解析tm结构的时间
struct tm time = {};
if (matchRes.size() >= 7)
{
for (size_t i = 1; i < 7; i++)
{
time.tm_year = std::stoi(matchRes[1]);
time.tm_mon = std::stoi(matchRes[2]);
time.tm_mday = std::stoi(matchRes[3]);
time.tm_hour = std::stoi(matchRes[4]);
time.tm_min = std::stoi(matchRes[5]);
time.tm_sec = std::stoi(matchRes[6]);
time.tm_isdst = isdst;
}
}
if (!verify_time(time))
{
return datetime();
}

// 转换为时间戳
time.tm_year -= 1900;
time.tm_mon -= 1;
auto ret = mktime(&time);
if (ret == -1)
{
CUTL_ERROR("mktime() failed");
return datetime();
}
auto s = static_cast<uint64_t>(ret);
return datetime(s2ms(s) + ms);
}

uint64_t datetime::timestamp() const
{
return timestamp_ms_;
}

std::string get_format_str(datetime_format fmt)
{
std::string text;
switch (fmt)
{
case datetime_format::datetime_format_a: // YYYY-MM-DD HH:MM:SS
text = "%Y-%m-%d %H:%M:%S";
break;
case datetime_format::datetime_format_b: // YYYY.MM.DD HH:MM:SS
text = "%Y.%m.%d %H:%M:%S";
break;
case datetime_format::datetime_format_c: // YYYY/MM/DD HH:MM:SS
text = "%Y/%m/%d %H:%M:%S";
break;
case datetime_format::datetime_format_d: // YYYYMMDD HH:MM:SS
text = "%Y%m%d %H:%M:%S";
break;
default:
break;
}

return text;
}

std::string datetime::format(datetime_format fmt, bool local, bool show_milliseconds) const
{
auto fmtstr = get_format_str(fmt);
auto s = timestamp_ms_ / 1000;
auto ms = timestamp_ms_ % 1000;
auto text = fmt_timestamp(s, local, fmtstr);
if (show_milliseconds)
{
text += "." + fmt_uint(ms, 3);
}
return text;
}

std::string datetime::format(const std::string &fmt, bool local, bool show_milliseconds) const
{
auto s = timestamp_ms_ / 1000;
auto ms = timestamp_ms_ % 1000;
auto text = fmt_timestamp(s, local, fmt);
if (show_milliseconds)
{
text += "." + fmt_uint(ms, 3);
}
return text;
}

datetime &datetime::operator=(const datetime &other)
{
if (this == &other)
{
return *this;
}

timestamp_ms_ = other.timestamp_ms_;
return *this;
}

datetime datetime::operator+(uint64_t ms)
{
datetime dt(*this);
dt.timestamp_ms_ += ms;
return dt;
}

datetime datetime::operator-(uint64_t ms)
{
datetime dt(*this);
dt.timestamp_ms_ -= ms;
return dt;
}

datetime &datetime::operator+=(uint64_t ms)
{
timestamp_ms_ += ms;
return *this;
}

datetime &datetime::operator-=(uint64_t ms)
{
timestamp_ms_ -= ms;
return *this;
}

int64_t datetime::operator-(const datetime &other) const
{
int64_t diff = timestamp_ms_ - other.timestamp_ms_;
return diff;
}

std::string datetime::supported_time_formats(const time_regex_vec_type &fmtlist)
{
std::string time_fmts;
for (size_t i = 0; i < fmtlist.size(); i++)
{
time_fmts += fmtlist[i].first + "\n";
}
return time_fmts;
}

bool datetime::verify_time(const struct tm &time)
{
// 校验年
if (time.tm_year < 1900)
{
CUTL_ERROR("the year should be >= 1900");
return false;
}
// 校验月
if (time.tm_mon < 1 || time.tm_mon > 12)
{
CUTL_ERROR("the month should be between 1 and 12");
return false;
}
// 校验日
std::vector<int> large_month = {1, 3, 5, 7, 8, 10, 12};
if (std::find(large_month.begin(), large_month.end(), time.tm_mon) != large_month.end() && (time.tm_mday < 1 || time.tm_mday > 31))
{
CUTL_ERROR("the day should be between 1 and 31 for " + std::to_string(time.tm_mon) + " month");
return false;
}
std::vector<int> small_month = {4, 6, 9, 11};
if (std::find(small_month.begin(), small_month.end(), time.tm_mon) != small_month.end() && (time.tm_mday < 1 || time.tm_mday > 30))
{
CUTL_ERROR("the day should be between 1 and 30 for " + std::to_string(time.tm_mon) + " month");
return false;
}
if (time.tm_mon == 2)
{
auto is_leap_year = [](int year)
{ return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); };
if (is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 29))
{
CUTL_ERROR("the day should be between 1 and 29 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2));
return false;
}
if (!is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 28))
{
CUTL_ERROR("the day should be between 1 and 28 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2));
return false;
}
}

// 校验时分秒
if (time.tm_hour < 0 || time.tm_hour > 23)
{
CUTL_ERROR("the hour should be between 0 and 23");
return false;
}
if (time.tm_min < 0 || time.tm_min > 59)
{
CUTL_ERROR("the minute should be between 0 and 59");
return false;
}
if (time.tm_sec < 0 || time.tm_sec > 59)
{
CUTL_ERROR("the second should be between 0 and 59");
return false;
}

return true;
}

std::ostream &operator<<(std::ostream &os, const datetime &dt)
{
os << dt.format();
return os;
}

} // namespace

6. 测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#pragma once

#include <iostream>
#include "datetime.h"
#include "common.hpp"

void TestDatetimeBasicUsage()
{
PrintSubTitle("TestDatetimeBasicUsage");

auto now = cutl::datetime::now();
std::cout << "current timestamp(ms): " << now.timestamp() << std::endl;
std::cout << "current time(UTC time): " << now.utctime() << std::endl;
std::cout << "current time(local time): " << now.format() << std::endl;
std::cout << "current time(UTC time) format b: " << now.format(cutl::datetime_format::datetime_format_b, false, true) << std::endl;
std::cout << "current time(UTC time) format b, don't show milliseconds: " << now.format(cutl::datetime_format::datetime_format_b, false, false) << std::endl;
std::cout << "current time(UTC time) format c: " << now.format(cutl::datetime_format::datetime_format_c, false, true) << std::endl;
std::cout << "current time(UTC time) format d: " << now.format(cutl::datetime_format::datetime_format_d, false, true) << std::endl;
std::cout << "current time(UTC time) custom format 1: " << now.format("%c %Z", false, true) << std::endl;
std::cout << "current time(UTC time) custom format 2: " << now.format("%m/%d/%Y/ %H:%M:%S", false, false) << std::endl;
}

void TestDatetimeOperator()
{
// 运算符重载
PrintSubTitle("TestDatetimeOperator");

std::cout << "one day == " << cutl::datetime::day << "ms" << std::endl;
std::cout << "one hour == " << cutl::datetime::hour << "ms" << std::endl;
std::cout << "one minute == " << cutl::datetime::min << "ms" << std::endl;

auto now = cutl::datetime::now();
std::cout << "current time: " << now << std::endl;
auto dt1 = now - cutl::datetime::min;
std::cout << "before one minute: " << dt1 << std::endl;
// std::cout << "current time 1: " << now << std::endl;
auto dt2 = now + cutl::datetime::min;
std::cout << "after one minute: " << dt2 << std::endl;
// std::cout << "current time 2: " << now << std::endl;

now -= (2 * cutl::datetime::hour);
std::cout << "before two hours: " << now << std::endl;
now += (4 * cutl::datetime::hour);
std::cout << "after two hours: " << now << std::endl;

auto dt3 = cutl::datetime::get("2024-03-01 10:00:00");
auto dt4 = cutl::datetime::get("2024-03-30 14:18:44");
auto duration1 = dt4 - dt3;
std::cout << "the difference between " << dt3 << " and " << dt4 << " is: " << duration1 << "ms, formatted: " << cutl::fmt_timeduration_ms(duration1) << std::endl;
auto duration2 = dt3 - dt4;
std::cout << "the difference between " << dt4 << " and " << dt3 << " is: " << duration2 << "ms" << std::endl;
}

void TestDatetimeParseString()
{
// 字符串解析成时间
PrintSubTitle("TestDatetimeParseString");
auto dt0 = cutl::datetime::get(" 2024-03-02 14:18:44 ");
std::cout << "dt0: " << dt0 << std::endl;
auto dt1 = cutl::datetime::get(" 2024-03-02 14:18:44.023 ");
std::cout << "dt1: " << dt1 << std::endl;
auto dt2 = cutl::datetime::get(" 2024.03.12 14:18:44");
std::cout << "dt2: " << dt2 << std::endl;
auto dt3 = cutl::datetime::get(" 2024.03.12 14:18:44.003");
std::cout << "dt3: " << dt3 << std::endl;
auto dt4 = cutl::datetime::get("2024/03/22 14:18:44 ");
std::cout << "dt4: " << dt4 << std::endl;
auto dt5 = cutl::datetime::get("2024/03/22 14:18:44.200 ");
std::cout << "dt5: " << dt5 << std::endl;
auto dt6 = cutl::datetime::get("2024/03/23 09:28:04");
std::cout << "dt6: " << dt6 << std::endl;
auto dt7 = cutl::datetime::get("2024/03/23 09:28:04.276");
std::cout << "dt7: " << dt7 << std::endl;
// format error
auto dt8 = cutl::datetime::get(" 2024-0322 14:18:44 ");
std::cout << "dt8: " << dt8 << std::endl;
// mounth error
auto dt9 = cutl::datetime::get(" 2024-13-02 14:18:44 ");
std::cout << "dt9: " << dt9 << std::endl;
// leap year error
auto dt10 = cutl::datetime::get(" 2023-02-29 14:18:44 ");
std::cout << "dt10: " << dt10 << std::endl;
// day error
auto dt11 = cutl::datetime::get(" 2024-03-42 14:18:44 ");
std::cout << "dt11: " << dt11 << std::endl;

// year > 2038
auto dt12 = cutl::datetime::get(" 2044-03-02 14:18:44 ");
std::cout << "dt12: " << dt12 << std::endl;
std::cout << "dt12 timestamp: " << dt12.timestamp() << std::endl;
}

void TestDatetime()
{
PrintTitle("datetime");

TestDatetimeBasicUsage();
TestDatetimeOperator();
TestDatetimeParseString();
}

7. 运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
==============================================datetime==============================================
---------------------------------------TestDatetimeBasicUsage---------------------------------------
current timestamp(ms): 1716129275853
current time(UTC time): 2024-05-19 14:34:35.853
current time(local time): 2024-05-19 22:34:35.853
current time(UTC time) format b: 2024.05.19 14:34:35.853
current time(UTC time) format b, don't show milliseconds: 2024.05.19 14:34:35
current time(UTC time) format c: 2024/05/19 14:34:35.853
current time(UTC time) format d: 20240519 14:34:35.853
current time(UTC time) custom format 1: Sun May 19 14:34:35 2024 UTC.853
current time(UTC time) custom format 2: 05/19/2024/ 14:34:35
----------------------------------------TestDatetimeOperator----------------------------------------
one day == 86400000ms
one hour == 3600000ms
one minute == 60000ms
current time: 2024-05-19 22:34:35.854
before one minute: 2024-05-19 22:33:35.854
after one minute: 2024-05-19 22:35:35.854
before two hours: 2024-05-19 20:34:35.854
after two hours: 2024-05-20 00:34:35.854
the difference between 2024-03-01 10:00:00.000 and 2024-03-30 14:18:44.000 is: 2521124000ms, formatted: 29d:04h:18m:44s.000ms
the difference between 2024-03-30 14:18:44.000 and 2024-03-01 10:00:00.000 is: -2521124000ms
--------------------------------------TestDatetimeParseString---------------------------------------
dt0: 2024-03-02 14:18:44.000
dt1: 2024-03-02 14:18:44.023
dt2: 2024-03-12 14:18:44.000
dt3: 2024-03-12 14:18:44.003
dt4: 2024-03-22 14:18:44.000
dt5: 2024-03-22 14:18:44.200
dt6: 2024-03-23 09:28:04.000
dt7: 2024-03-23 09:28:04.276
[2024-05-19 22:34:35.857][E]]0x7ff844a9b100](cutl) [datetime.cpp:79:get] Only the following time formats are supported:
YYYY-MM-DD HH:MM:SS.sss
YYYY-MM-DD HH:MM:SS
YYYY.MM.DD HH:MM:SS.sss
YYYY.MM.DD HH:MM:SS
YYYY/MM/DD HH:MM:SS.sss
YYYY/MM/DD HH:MM:SS
YYYYMMDD HH:MM:SS.sss
YYYYMMDD HH:MM:SS

dt8: 1970-01-01 08:00:00.000
[2024-05-19 22:34:35.857][E]]0x7ff844a9b100](cutl) [datetime.cpp:241:verify_time] the month should be between 1 and 12
dt9: 1970-01-01 08:00:00.000
[2024-05-19 22:34:35.857][E]]0x7ff844a9b100](cutl) [datetime.cpp:268:verify_time] the day should be between 1 and 28 for 2023-02
dt10: 1970-01-01 08:00:00.000
[2024-05-19 22:34:35.858][E]]0x7ff844a9b100](cutl) [datetime.cpp:248:verify_time] the day should be between 1 and 31 for 3 month
dt11: 1970-01-01 08:00:00.000
dt12: 2044-03-02 14:18:44.000
dt12 timestamp: 2340512324000

8. 源码地址

更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。

推荐阅读
C++ 时间处理6-从字符串中解析日期时间 C++ 时间处理6-从字符串中解析日期时间 C++数据格式化4 - 格式化时间戳 C++数据格式化4 - 格式化时间戳 C++时间处理3-格式化时间戳 C++时间处理3-格式化时间戳

评论