c++直到20标准才提供了日期类型,在c++20以前只能使用c语言的相关接口,c语言的日期接口在头文件中ctime中,此外还有一个格式化日期的函数位于头文件iomanip中。
§ctime一览
下面是头文件ctime的部分声明,此处已经添加了一些注释用来简单说明结构体和函数的功能。
|
|
§clock_t
clock_t是函数clock返回的类型,用于保存进程从关联到程序执行的实现定义时期开始,所用的粗略处理器时间。为转换结果为秒,可将它除以CLOCKS_PER_SEC。clock返回的时间不一定是精确的进程运行时间,因此只有两个clock_t的差才是有意义的。例如下面使用clock计算代码执行时间:
|
|
§time_t
time_t类型表示自1970年1月1日以来经过的秒数,对时间和日期的处理一般通过time_t类型进行。c++中的system_clock提供了一个静态成员函数to_time_t用来将某个时间点转换成time_t类型,用from_time_t来将一个time_t类型转换成时间点类型,它们的声明为:
|
|
time_t类型向用户可读的格式转换可以使用ctime函数来完成。ctime函数用于将time_t对象转换成一个字符串,这个字符串拥有这样的格式:
Www Mmm dd hh:mm:ss yyyy\n
其中
- Www - 星期。Mon、Tue、Wed、Thu、Fri、Sat、Sun之一。
- Mmm - 月份。Jan、Feb、Mar、Apr、May、Jun、Jul、Aug、Sep、Oct、Nov、Dec之一。
- dd - 几号
- hh - 时
- mm - 分
- ss - 秒
- yyyy - 年
因此如果需要向用户输出当前时间,可以使用system_clock::now()来获得当前的时间,然后转换成time_t类型的对象,也可以直接由函数time返回一个time_t对象,然后使用acstime将它转换成文本后输出,也可以使用gmtime或者localtime来获得不同时区的时间结果,如:
|
|
结果为:
Thu Aug 20 16:35:10 2020
UTC: Thu Aug 20 08:35:10 2020
local: Thu Aug 20 16:35:10 2020
注意:gmtime和localtime返回的指针指向一个内部静态变量,因此返回后必须马上使用,或者拷贝到一个新的tm对象内,否则下一次调用后就被覆盖了。比如
|
|
可能的输出:
Thu Aug 20 16:33:06 2020
Thu Aug 20 16:33:06 2020
两者输出的都是本地时间!
§tm
tm是表示日期和时间的组合的结构体,定义为:
|
|
tm使我们可以比较方便地对日期和时间进行修改,而不是只从时钟获取时间。同时,标准库中提供了一组函数用于对时间和日期的格式进行定制:
|
|
asctime之于tm相当于ctime之于time_t,它们都返回一个指向静态空终止字符串的指针,这个字符串可能在asctime和ctime内共享。这两个函数都不是线程安全的,posix标准将它们标记为过时的,应当使用strftime来代替。
strftime函数将按照字符串format描述的格式,将tm对象转换成空终止字符串,放入str所指向的内存,最多写入count个字节。put_time将tm对象按照format所描述的格式输出。
格式化字符串format由普通字符串构成,其中含有像%Y这样的格式化字符串的将会按下表处理:
转换 指定符 | 解释 | 使用的域 |
---|---|---|
% | 写字面的%。完整转换指定必须是%%。 | |
n | 写换行符 | |
t | 写水平制表符 | |
年 | ||
Y | 以 4 位十进制数写年。 | tm_year |
EY | 以替用方式写年。例如在 ja_JP 本地环境中,以“平成23年”取代“2011年”。 | tm_year |
y | 写年的末 2 位十进制数(范围[00, 9])。 | tm_year |
Oy | 以替用数字系统写年的末 2 位数字。例如在 ja_JP 本地环境中以“十一”取代“11”。 | tm_year |
Ey | 将年写作从本地环境的替用时期 %EC 的偏移(本地环境依赖)。 | tm_year |
C | 写年的首 2 位十进制数(范围[00, 99])。 | tm_year |
EC | 以本地环境的替用表示写年份基底(时期),例如 ja_JP 中的“平成”。 | tm_year |
G | 写基于ISO 8601的年,即是包含指定星期的年份。IS0 8601中星期以星期一开始,而且一年的首星期必须满足下列要求:包含 1 月 4 日包含一年的首个星期四 | tm_yea, tm_wday, tm_yday |
g | 写基于ISO 8601的年,即是包含指定星期年份,的后 2 位数(范围[00, 99])。IS0 8601 中星期以星期一开始,而且一年的首星期必须满足下列要求:包含 1 月 4 日包含一年的首个星期四 | tm_year, tm_wday, tm_yday |
月 | ||
b | 写缩略月名,例如Oct(本地环境依赖)。 | tm_mon |
h | 与b同意。 | tm_mon |
B | 写完整月名,例如October(本地环境依赖)。 | tm_mon |
m | 将月写作十进制数(范围[01,12])。 | tm_mon |
Om | 以替用数字系统写月。例如 ja_JP 本地环境中“十二”取代“12”。 | tm_mon |
星期 | ||
U | 以十进制数写年的星期(星期日是星期的首日)(范围[00, 53])。 | tm_year, tm_wday, tm_yday |
OU | 以替用数值系统写如同用%U的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 | tm_year, tm_wday, tm_yday |
W | 以十进制数写年的星期(星期一是星期的首日)(范围[00, 53])。 | tm_year, tm_wday, tm_yday |
OW | 以替用数值系统写如同用%W的年的第几星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 | tm_year, tm_wday, tm_yday |
V | 写 ISO 8601的年的星期(范围[00, 53])。IS0 8601中星期以星期一开始,而且一年的首星期必须满足下列要求:包含 1 月 4 日包含一年的首个星期四 | tm_year, tm_wday, tm_yday |
OV | 以替用数值系统写如同用%V的年的星期。例如“五十二”在 ja_JP 本地环境中取代“52”。 | tm_year, tm_wday, tm_yday |
日 | ||
j | 以十进制数写年的第几日(范围[001, 366])。 | tm_yday |
d | 以十进制数写月的第几日(范围[01, 31])。 | tm_mday |
Od | 以替用数字系统写零基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“ 27 ”。单字符前加空格。 | tm_mday |
e | 以十进制数写月的第几日(范围[01, 31])。单数字前加空格。 | tm_mday |
Oe | 以替用数字系统写一基的月的第几日。例如 ja_JP 本地环境中“二十七”取代“27”。单字符前加空格。 | tm_mday |
星期几 | ||
a | 写缩略的星期日期名,例如 Fri (本地环境依赖)。 | tm_wday |
A | 写完整的星期日期名,例如 Friday (本地环境依赖)。 | tm_wday |
w | 以十进制数写星期日期,其中星期日是 0 (范围[0, 6])。 | tm_wday |
Ow | 用替用数字系统写星期日期,其中星期日是 0 。例如 ja_JP 本地环境中“二”取代“2”。 | tm_wday |
u | 十进制数写星期日期,其中星期一是 1(ISO 8601格式)(范围[1, 7])。 | tm_wday |
Ou | 用替用数字系统写星期日期,其中星期一是 1 。例如 ja_JP 本地环境中“二”取代“2”。 | tm_wday |
时、分、秒 | ||
H | 以十进制数写时, 24 小时制(范围[00, 23])。 | tm_hour |
OH | 以替用数字系统写 24 小时制的时。例如 ja_JP 本地环境中“十八”取代“18”。 | tm_hour |
I | 以十进制数写时, 12 小时制(范围[01, 12])。 | tm_hour |
OI | 以替用数字系统写 12 小时制的时。例如 ja_JP 本地环境中“六”取代“6”。 | tm_hour |
M | 以十进制数写分(范围[00, 59])。 | tm_min |
OM | 以替用数字系统写分。例如 ja_JP 本地环境中“二十五”取代“25”。 | tm_min |
S | 以十进制数写秒(范围[00, 60])。 | tm_sec |
OS | 以替用数字系统写秒。例如 ja_JP 本地环境中“二十四”取代“24”。 | tm_sec |
其他 | ||
c | 写标准日期时间字符串。例如 Sun Oct 17 04:41:13 2010 (本地环境依赖)。 | 全部 |
Ec | 写替用日期时间字符串。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 | 全部 |
x | 写本地化的日期表示(本地环境依赖)。 | 全部 |
Ex | 写替用日期表示。例如 ja_JP 本地环境中“平成23年”取代“2011年”。 | 全部 |
X | 写本地化的时间表示(本地环境依赖)。 | 全部 |
EX | 写替用时间表示(本地环境依赖)。 | 全部 |
D | 等价于**"%m/%d/%y"**。 | tm_mon, tm_mday, tm_year |
F | 等价于**"%Y-%m-%d"**(ISO 8601日期格式)。 | tm_mon, tm_mday, tm_year |
r | 写本地化的 12小时制时间(本地环境依赖)。 | tm_hour, tm_min, tm_sec |
R | 等价于"%H:%M"。 | tm_hour, tm_min |
T | 等价于"%H:%M:%S"( ISO 8601 时间格式)。 | tm_hour, tm_min, tm_sec |
p | 写本地化的 a.m. 或 p.m. (本地环境依赖)。 | tm_hour |
z | 以 ISO 8601 格式(例如-0430)写距UTC的偏移,或者倘若时区信息不可用则不写字符。 | tm_isdst |
Z | 写依赖本地环境的时区名或缩写,或者若时区信息不可用则不写字符。 | tm_isdst |
例如以中文输出当前日期和时间:
|
|
也可以使用strftime将它保存到字符串中:
|
|
它们的结果为:
2020年08月20日 星期四 21时32分29秒
2020年08月20日 21时32分29秒
需要注意,strftime的本地环境由std::locale::global指定,而put_time在输出时必须使用out << put_time的形式将out绑定的本地环境传递给put_time的结果(put_time的返回值是未定义的,可以返回一个迭代器,使用cout输出时将结果转换成本地环境结果)。
§参考
[1] https://zh.cppreference.com/w/cpp/io/manip/put_time.
[2] https://zh.cppreference.com/w/cpp/chrono/c/strftime.
[3] https://zh.cppreference.com/w/cpp/header/ctime.
有关协调世界时、闰秒等信息可以参考以下链接:
[4] 世界协调时(UTC).
[5] 格林尼治标准时间(GMT).
[6] 国际原子时
[7] 闰秒.