高精度时间戳的获取
获取毫秒级的高精度时间戳是一个很常见的需求,尤其在向日志文件中输出信息时通常需要附带格式化的时间戳,
下面在不同的语言中尝试生成形如[2024-07-30 00:52:47.379]
的高精度时间戳。
C++
对于C++,标准库chrono
可以获取高精度的时间,
然后通过localtime
函数进行格式化,由于它不支持毫秒部分的格式化,我们还需要对毫秒进行额外处理。
下面是一个生成时间戳的示例函数 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16static std::string time_stamp() { // unsafe
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch())
% 1000;
char buffer[32]{};
std::strftime(static_cast<char *>(buffer), sizeof(buffer),
"[%Y-%m-%d %H:%M:%S", localtime(&now_time_t));
std::snprintf(static_cast<char *>(buffer) + 20, 7, ".%03d]",
static_cast<int>(now_ms.count()));
return std::string{static_cast<char *>(buffer)};
}
我们使用的localtime
函数无法保证线程安全,在Windows和Linux平台上分别为其提供了线程安全的版本:localtime_s
和localtime_r
,都需要传入两个指针参数,尤其注意两个平台提供的参数顺序还是反的!
我们可以通过条件编译来支持不同的平台,在其它情况下则通过加锁来保证线程安全。
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
31static std::string time_stamp() {
auto now = std::chrono::system_clock::now();
auto now_time_t = std::chrono::system_clock::to_time_t(now);
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch())
% 1000;
char buffer[32]{};
struct tm timeinfo {};
localtime_s(&timeinfo, &now_time_t);
localtime_r(&now_time_t, &timeinfo);
static std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
timeinfo = *localtime(&now_time_t);
}
std::strftime(static_cast<char *>(buffer), sizeof(buffer),
"[%Y-%m-%d %H:%M:%S", &timeinfo);
std::snprintf(static_cast<char *>(buffer) + 20, 6, ".%03d]",
static_cast<int>(now_ms.count()));
return std::string{static_cast<char *>(buffer)};
}
这里没有考虑C++20或者更新的语法标准,期待后续可以有更简洁的写法吧。
Fortran
对于Fortran这个老古董语言,要获取时间戳就比C++还困难了,我们只能手动地实现格式化的部分,下面是一个示例子程序,使用mingw-w64 gfortran
可以顺利编译运行,其它平台和编译器并没有测试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23subroutine get_timestamp(timestamp)
character(len=30) :: timestamp
character(len=8) :: time_str
character(len=10) :: date_str
character(len=4) :: year
character(len=2) :: month, day, hour, minute, second
integer :: millis
call date_and_time(date=date_str, time=time_str)
call system_clock(count=millis)
! Extract parts of the date and time
year = date_str(1:4)
month = date_str(5:6)
day = date_str(7:8)
hour = time_str(1:2)
minute = time_str(3:4)
second = time_str(5:6)
! Format the timestamp
write(timestamp, '("[",A,"-",A,"-",A," ",A,":",A,":",A,".",I3.3,"] ")') &
year, month, day, hour, minute, second, mod(millis, 1000)
end subroutine get_timestamp
Python
在Python中获取指定格式的高精度时间戳是非常简单的,需要先导入datetime
模块中的datetime
类,然后一行代码就可以搞定
1 | from datetime import datetime |
这里[:-3]
是为了只截取毫秒部分的前三个数字。
MATLAB
在MATLAB中获取指定格式的高精度时间戳同样非常简单,基于datestr
函数即可实现
1 | timestamp = datestr(now, 'yyyy-mm-dd HH:MM:SS.FFF'); |
这里datastr
函数在较新的版本中被逐渐废弃了,MATLAB建议改用datetime
函数来实现
1
timestamp = datetime('now','Format','yyyy-MM-dd HH:mm:ss.SSS');