获取毫秒级的高精度时间戳是一个很常见的需求,尤其在向日志文件中输出信息时通常需要附带格式化的时间戳, 下面在不同的语言中尝试生成形如[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
16
static 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_slocaltime_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
31
static 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 {};

#if defined(_MSC_VER)
localtime_s(&timeinfo, &now_time_t);
#elif defined(__unix__)
localtime_r(&now_time_t, &timeinfo);
#else
static std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
timeinfo = *localtime(&now_time_t);
}
#endif

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
23
subroutine 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
2
3
from datetime import datetime

timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]

这里[:-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');