【C++】UTC时间戳和datetime
(1)UTC时间与UTC+8
[!NOTE]
UTC(协调世界时) 和 UTC+8(东八区时间) 是两种不同的时间标准,主要区别在于 时区偏移。
UTC 时间 = GMT(格林尼治标准时间)(但 GMT 可能受地球自转影响,UTC 更精确)。UTC 是全球标准时间,基于原子钟计算,不受夏令时影响。
UTC+8 表示比 UTC 快 8 小时,东八区,适用于中国、新加坡、马来西亚、菲律宾等地区。北京时间(CST, China Standard Time)。中国全境统一使用 UTC+8。
如果 UTC 时间是
2025-06-12 00:00:00,那么:UTC+8(北京时间)** 是
2025-06-12 08:00:00。UTC-5(纽约时间) 是
2025-06-11 19:00:00(前一天)。
[!CAUTION]
unix时间戳是UTC时间,单位为s
代码中
uint64_t/time_t一律使用UTC时间戳(标准时间)库表中的
datetime类型一律存当地时间(北京时间),存:FROM_UNIXTIME(uint64_t)获取当地时间,取:UNIX_TIMESTAMP()得到UTC时间戳MySQL会根据服务器所在时区选择UTC+8(服务器在中国),
UNIX_TIMESTAMP(datetime)会认为datetime是北京时间,先减去8小时得到UTC时间再计算时间戳。比如:
UNIX_TIMESTAMP('2025-06-12 10:42:10'),它会认为'2025-06-12 10:42:10'是北京时间,并转换成 UTC 时间(2025-06-12 02:42:10),再计算2025-06-12 02:42:10的时间戳 → 1749696130
-
从UTC unix时间戳得到当地的时间
比如:从
1749696130获得2025-06-12 10:42:10,而不是2025-06-12 02:42:10//timep:指向 time_t 类型的指针,表示从1970年1月1日00:00:00 UTC开始的秒数。 //返回一个指向 struct tm 的指针,该结构体包含转换后的本地时间信息。如果转换失败,返回 NULL。 struct tm* std::localtime(const time_t* timep); //localtime_r 是 localtime 的线程安全版本,localtime 是较早版本的函数 struct tm* std::localtime_r(const time_t* timep, struct tm* result); -
从当地时间得到UTC unix时间戳
比如:从
2025-06-12 10:42:10获得1749696130//timeptr:指向 struct tm 的指针,该结构体包含要转换的本地时间信息。 //返回一个 time_t 类型的时间戳,表示从1970年1月1日00:00:00 UTC开始的秒数。如果输入的 struct tm 无效,返回 -1。 time_t std::mktime(struct tm* timeptr); time_t utc_timestamp = std::mktime(&local_tm); // 将本地时间转换为UTC时间戳
(2)由unix时间戳(uint64_t或time_t)获取datetime
[!NOTE]
datetime在代码中以
std::tm表示#include <ctime> std::tm struct tm { int tm_sec; /* Seconds. [0-60] (1 leap second) */ int tm_min; /* Minutes. [0-59] */ int tm_hour; /* Hours. [0-23] */ int tm_mday; /* Day. [1-31] */ int tm_mon; /* Month. [0-11] */ int tm_year; /* Year - 1900. */ int tm_wday; /* Day of week. [0-6] */ int tm_yday; /* Days in year.[0-365] */ int tm_isdst; /* DST. [-1/0/1]*/ # ifdef __USE_MISC long int tm_gmtoff; /* Seconds east of UTC. */ const char *tm_zone; /* Timezone abbreviation. */ # else long int __tm_gmtoff; /* Seconds east of UTC. */ const char *__tm_zone; /* Timezone abbreviation. */ # endif };//年份 tm.tm_year+1900 //月份 tm.tm_year+1 //日 tm.tm_mday //星期 tm.tm_wday+1
//uint64_t--->std::tm
#include <ctime>
#include <cstdint>
int uint64_to_tm(uint64_t timestamp, struct tm* tm_ptr) //timestamp为秒时间戳
{
// 将时间戳转换为 time_t 类型
time_t time = static_cast<time_t>(timestamp);
// 转换为本地时间
localtime_r(&sec_timestamp, tm_ptr);
return 0;
}
int uint64_to_tm(uint64_t timestamp, struct tm* tm_ptr) //timestamp为秒时间戳
{
// 手动给UTC时间戳+8小时调整时区到东八区(北京时间),得到本地时间戳
int64_t milli = timestamp + (int64_t)8 * 60 * 60 * 1000;
auto mTime = std::chrono::milliseconds(milli);
auto tp = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>(mTime);
auto tt = std::chrono::system_clock::to_time_t(tp);//chrono::time_point转time_t
*tm_ptr = std::gmtime(&tt);
}
//C++20标准
#include <chrono>
#include <format>
void uint64_to_tm(uint64_t timestamp, struct tm* tm_ptr)
{
auto tp = std::chrono::system_clock::from_time_t(timestamp);
zoned_time zt{"Asia/Shanghai", tp}; // 指定时区
*tm_ptr = std::chrono::get_tm(zt);
}
(3)datetime获取unix时间戳(uint64_t或time_t)
//std::tm--->uint64_t
#include <ctime>
#include <chrono>
#include <cstdint>
uint64_t tm_to_uint64(const std::tm& tm_time) //返回秒
{
// 将 std::tm 转换为 time_t
std::time_t time_t_value = mktime(const_cast<std::tm*>(&tm_time));
// 转换为 uint64_t
return static_cast<uint64_t>(time_t_value);
}
// 将 std::chrono::system_clock::time_point 转换为 uint64_t 时间戳(秒为单位)
uint64_t chrono_to_uint64(const std::chrono::system_clock::time_point& time_point)
{
// 转换为秒
auto duration = time_point.time_since_epoch();
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
return static_cast<uint64_t>(seconds.count());
}
(4)由UTC unix毫秒时间戳获取YYYY-MM-DD HH:MM:SS.mmm字符串
// utc unix毫秒时间戳(13位)获取YYYY-MM-DD HH:MM:SS.mmm字符串
std::string timestampToString(int64_t timestamp_ms)
{
// Convert milliseconds to seconds and remainder milliseconds
std::time_t seconds = timestamp_ms / 1000;
int milliseconds = timestamp_ms % 1000;
//使用std::localtime函数将seconds(以秒为单位的时间)转换为本地时间,结果存储在tm结构体中
std::tm *tm = std::localtime(&seconds);
//存储格式化后的时间字符串(不包括毫秒部分)。大小为24,足以存储"YYYY-MM-DD HH:MM:SS"格式的字符串
//将tm结构中的时间信息格式化为"YYYY-MM-DD HH:MM:SS"格式的字符串,并存储在buffer中
char buffer[24];
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm);
//将buffer中的字符串和毫秒部分拼接起来
//std::setfill('0')设置填充字符为'0',std::setw(3)设置字段宽度为3,确保毫秒部分总是三位数字,不足时前面补零。
std::ostringstream oss;
oss << buffer << '.' << std::setfill('0') << std::setw(3) << milliseconds;
return oss.str();
}
(5)HH:MM:SS时间字符串转成ms
//将形如1:30:21格式时间段转换为毫秒数
static uint64_t timeStringToMillis(const std::string &timeString)
{
int hours, minutes, seconds;
sscanf(timeString.c_str(), "%d:%d:%d", &hours, &minutes, &seconds);
return (hours * 3600 + minutes * 60 + seconds) * 1000;
}
(6)YYYY-MM-DD HH:MM:SS.mmm字符串获取UTC unix毫秒时间戳(13位)
//YYYY-MM-DD HH:MM:SS.mmm字符串获取utc unix毫秒时间戳(13位)
int64_t stringToTimestamp(const std::string &datetime_str)
{
std::tm tm = {};
int milliseconds = 0;
// Manually parse the string "YYYY-MM-DD HH:MM:SS.mmm"
if (sscanf(datetime_str.c_str(), "%4d-%2d-%2d %2d:%2d:%2d.%3d", &tm.tm_year,
&tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
&milliseconds) != 7)
{
throw std::runtime_error("Failed to parse date-time string");
}
// Adjust fields for tm structure
tm.tm_year -= 1900; // tm_year is years since 1900
tm.tm_mon -= 1; // tm_mon is 0-based (0 = January)
// Convert to time_t (seconds since epoch) and add milliseconds
std::time_t seconds = std::mktime(&tm);
if (seconds == -1)
{
throw std::runtime_error("Failed to convert to time_t");
}
return static_cast<int64_t>(seconds) * 1000 + milliseconds;
}
(6)将yyyy-MM-dd hh:mm:ss字符串转成yyyyMMddhhmmss字符串
std::string convertDateFormat(const std::string& date_str)
{
if (date_str.empty()) {
throw std::invalid_argument("Input date string is empty");
}
// 检查输入长度是否符合 "YYYY-MM-DD HH:MM:SS"
if (date_str.size() != 19) {
throw std::runtime_error("Invalid date string format: " + date_str);
}
// 提取并验证格式
std::string year = date_str.substr(0, 4);
std::string month = date_str.substr(5, 2);
std::string day = date_str.substr(8, 2);
std::string hour = date_str.substr(11, 2);
std::string minute = date_str.substr(14, 2);
std::string second = date_str.substr(17, 2);
// 确保字符的位置符合标准格式
if (date_str[4] != '-' || date_str[7] != '-' || date_str[10] != ' ' ||
date_str[13] != ':' || date_str[16] != ':') {
throw std::runtime_error("Invalid date string format: " + date_str);
}
// 合并为目标格式
std::string result = year + month + day + hour + minute + second;
return result;
}
(8)获取当前UNIX时间戳
uint64_t nowMS()
{
std::chrono::time_point<std::chrono::system_clock> now =
std::chrono::system_clock::now();
auto duration = now.time_since_epoch();
auto millis =
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
return millis;
}
(9)根据时间戳获取当日零点时间戳
//timestamp(单位ms)
//返回值(单位ms)
time_t midnight(uint64_t timestamp)
{
time_t tmt = timestamp / 1000;
tm* pTM = localtime(&tmt);
pTM->tm_hour = 0;
pTM->tm_min = 0;
pTM->tm_sec = 0;
auto midnight_timet = mktime(pTM) * 1000;
return midnight_timet;
}
uint64_t midnite = midnight(ms_now); // 当天0点时间戳
(10)库表中时间类型的选择
- 日期时间类型:
DATETIME(4)表示时间戳的精度为4位小数(毫秒级)。如果你需要更高的精度(例如微秒级),可以使用DATETIME(6) - 时间戳类型:存储
s/ms/us,使用bigint
(11)c++代码中时间类型
[!NOTE]
uint64_t和time_t可直接强转
std::time_t time_t_value; uint64_t uint64_value static_cast<uint64_t>(time_t_value);
-
日期时间类型:
std::tm或std::chrono::system_clock::time_point -
时间戳类型:
uint64_t或time_t,这两者数值一致。秒时间戳:10位整数。
毫秒时间戳:13位整数。
(12)MySQL语句中时间戳处理
time_t(time_t是时间戳epoch到现在的seconds)或uint_64可表示秒,毫秒,微秒时间戳,精度够字段类型为时间戳:存,
time_t或uint_64格式变量在execute()中执行插入到字段时,都要先转double(秒)或long long(微秒,微秒用long long约定俗成)。取,用getDouble()或getLLong()直接取库表里的字面值。比较时间先后,一律使用时间戳进行比较。datetime也先转成时间戳再比较!
获取日期当天零点
-- 获取指定datetime的当天0点
SELECT DATE_FORMAT(`datetime字段`, '%Y-%m-%d 00:00:00') AS midnight;
-- 获取现在时间的当天0点
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d 00:00:00') AS midnight;
unix时间戳(int64_t或time_t)存取
-
库表字段数据类型假设为
bigint,11位,但存入库中不直接存uint64_t,类型time_t或uint64_t需要转成double或long long才能被libzdb库的函数execute使用//存入 uint64_t tm; auto tmTmp = static_cast<long long>(tm); conn.execute("UPDATE e_warning_Info SET is_sent_user=1 WHERE tm=?", tmTmp); 或 auto tmTmp = static_cast<double>(tm); conn.execute("UPDATE e_warning_Info SET is_sent_user=1 WHERE tm=?", tmTmp); -
用
getDouble()或getLLong()读取库表中unix时间戳字面值getDouble()会不会是使用getTimestamp()?不要用getTimestamp()!!!!!//获取表内字面值,强转long long int。(无法获取字面值) auto rslt = conn.executeQuery("..."); uint64_t tm = rslt.getLLong("tm");//一般用来取ms或us cout<<"tm="<<tm<<endl;//和数据库中所存的值相等 或 uint64_t tm = rslt.getDouble("tm");//用来取秒时间戳 cout<<"tm="<<tm<<endl;//和数据库中所存的值不等 cout<<"tm="<<(double)(tm)<<endl;//和数据库中所存字面值相等
unix时间戳(int64_t或time_t)转成datetime存取
//MySQL会根据服务器所在时区选择UTC+8(服务器在中国)
UNIX_TIMESTAMP(datetime)//datetime转unix时间戳(单位s,拿到datetime先减去8小时得到UTC时间再计算时间戳)
FROM_UNIXTIME(uint64_t)//unix时间戳(s)转datetime(拿到uint64_t转成datetime后加上8小时)
库表字段数据类型设为datetime(4),秒后面4位小数。
调用函数FROM_UNIXTIME()将unix时间戳(单位s)转成datetime插入
datetime类型字段用conn.getDateTime("field")从查询结果中获取,获取结果是struct tm类型
//int64_t或time_t--->datetime后存入
uint64_t tmStmp = dfVec[0]->sampTime();//ms
conn21.execute(
"INSERT INTO "
"e_mining_signaldata_frm_info "
"(dev_id,samp_time,class_id,samp_intvl,valNum,vecSize,outLen,frm_"
"loc,fx,fy,fz,dis)"
"values(?,FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?,?) "//ms转成datetime
" ON DUPLICATE KEY UPDATE samp_intvl= values(samp_intvl),valNum= "
"values(valNum),vecSize= values(vecSize),outLen= values(outLen)",
(uint8_t)devId, // dev_id
(double)tmStmp / 1000.0, // tmStmp是uint64_t毫秒时间戳,转秒,因此要再转double
classId2, // class_id
deltT, // curt_ch
valNum, // channels
vecSize,
pcoParm.outLen, // ch_pnts
(relLocFromTime(tmStmp) / std::to_string(classId2) / std::to_string(tmStmp)).c_str(), // frm_loc
pcoLocParm.fx,
pcoLocParm.fy,
pcoLocParm.fz,
pcoLocParm.dis_y);
//datetime--->int64_t或time_t取出
auto rslt = conn.executeQuery("SELECT UNIX_TIMESTAMP(field) from table");
uint64_t tm = rslt.getLLong("field");
//直接读取datetime类型字段,获取struct tm类型(若需要uint64_t类型可再转)
std::tm = conn.getDateTime("field");
1.
time_t
- 定义:
time_t是 C 和 C++ 标准库中用于表示时间的类型,通常用于表示从 1970 年 1 月 1 日 00:00:00 UTC 到当前时间的秒数(即 Unix 时间戳)。- 类型:
time_t的具体实现依赖于平台和编译器,但通常是long或long long类型。在大多数现代系统中,time_t是一个 64 位有符号整数。- 用途:主要用于时间相关的操作,如获取当前时间、时间间隔计算等。
- 范围:由于
time_t是有符号整数,其范围通常是-2^63到2^63-1(在 64 位系统中)。2.
uint64_t
- 定义:
uint64_t是 C++ 标准库中定义的无符号 64 位整数类型,属于<cstdint>头文件中的固定宽度整数类型。- 类型:
uint64_t是一个无符号 64 位整数。- 用途:用于需要精确表示 64 位无符号整数的场景,如大整数计算、文件大小、内存地址等。
- 范围:
0到2^64-1。对比
特性 time_tuint64_t类型 通常是 64 位有符号整数 64 位无符号整数 范围 -2^63到2^63-10到2^64-1用途 时间相关的操作 大整数计算、文件大小等 标准库 <ctime>或<chrono><cstdint>

浙公网安备 33010602011771号