当前位置: 首页 > news >正文

日志1--时间戳类型设计

本文章先进行讲解c++实现日志系统的第一部分实现时间戳类型

先进行讲解涉及的相应知识点

1.获取当前时间到gettimeofday()精确到微秒

gettimeofday() 是 Unix/Linux 系统中用于获取当前时间(精确到微秒)的系统调用,定义在 <sys/time.h> 头文件中,常用于计时、日志时间戳等场景。

#include <sys/time.h>int gettimeofday(struct timeval *tv, struct timezone *tz);

参数讲解:

struct timeval tv;结构体存储秒和微秒

struct timezone通常使用nullptr指针默认系统时间

// 存储时间(秒和微秒)
struct timeval {time_t      tv_sec;   // 秒数(自 1970-01-01 00:00:00 UTC 起)suseconds_t tv_usec;  // 微秒数(0 ~ 999999)
};// 存储时区信息(通常不使用)
struct timezone {int tz_minuteswest;  // 与 UTC 的分钟差(西为正)int tz_dsttime;      // 夏令时相关(已废弃)
};
  1. 精度:提供微秒级精度(1 秒 = 1,000,000 微秒),比 time() 函数(秒级)更高。
  2. 时间基准tv_sec 基于 Unix 时间戳(从 1970-01-01 00:00:00 UTC 开始计算的秒数)。
  3. 时区转换:需配合 localtime() 或 gmtime() 将 UTC 时间转换为本地时间或格林威治时间。

2.将秒转为年月日特定格式

 C 语言中,localtime_r 是一个用于将时间戳(从 1970 年 1 月 1 日 00:00:00 UTC 起的秒数)转换为本地时间的函数。

#include <time.h>struct tm *localtime_r(const time_t *timep, struct tm *result);

参数说明

  • timep:指向要转换的时间戳(time_t 类型,本质是表示秒数的整数)的指针。
  • result:指向用于存储转换后本地时间结果的 struct tm 结构体的指针,需要预先分配好内存。
  • 返回值:成功时返回指向 result 的指针,失败时返回 NULL (不过通常情况下不会失败,除非传入的指针无效)。

struct tm 结构体

struct tm {int tm_sec;    // 秒(0 - 59)int tm_min;    // 分钟(0 - 59)int tm_hour;   // 小时(0 - 23)int tm_mday;   // 一月中的第几天(1 - 31)int tm_mon;    // 月份(0 - 11,0 代表一月)int tm_year;   // 年份 - 1900(例如2024年,这里的值是124)int tm_wday;   // 一周中的第几天(0 - 6,0 代表星期日)int tm_yday;   // 一年中的第几天(0 - 365)int tm_isdst;  // 是否为夏令时(正数表示夏令时,0 表示不是,负数表示未知)
};

从 1970 年 1 月 1 日 00:00:00 UTC(协调世界时)开始到当前时间的秒数(有时也精确到毫秒或微秒),数据类型通常是 time_t(本质是一个整数类型,在 32 位系统上通常是 int,在 64 位系统上通常是 long) 或表示更精确时间的扩展类型(如 long long 表示毫秒级时间戳,struct timeval 包含秒和微秒字段)。

3.格式化写入字符串

printf 是 C 语言中用于格式化字符串并写入字符数组的标准库函数,定义在 <stdio.h> 头文件中。它与 printf 功能类似,但 printf 将结果输出到标准输出(如控制台),而 sprintf 将结果写入指定的字符数组,常用于动态构建字符串。

#include <stdio.h>int sprintf(char *str, const char *format, ...);

参数说明

  • str:指向目标字符数组的指针,用于存储格式化后的字符串。
  • format:格式化字符串(与 printf 的格式字符串规则相同),包含普通字符和格式说明符(如 %d%s 等)。
  • ...:可变参数列表,对应格式字符串中的格式说明符。

返回值

  • 成功:返回写入字符数组的字符总数(不包括结尾的 \0)。
  • 失败:返回负数(通常为 -1),并可能设置 errno

具体时间戳类型类型设计讲解

1.首先我们定义一个时间戳的类Timestamp.hpp,设置私有成员微秒成员为无符号64位整形 uint64_t micr_(需包含头文件<stdint.h>,设置静态成员 static const uint32_t KMicPerSec=1000*1000便于进行秒到微秒的转换。

2.设置公有静态函数 static Timestamp Now();获取当前时间,返回类成员变量,并用成员函数Timestamp::now()在内部用this指针接受。

3.类型转换设计,我们定义了三种类型转换的成员函数

  • string toString()const;直接返回秒+微秒
  • string toFormattedString(bool showmicto=true)const;showmicto判断微妙是否为0。返回格式为:年/月/日 时:分:秒.微妙
  • string toFormattedFile()cosnt;返回格式:年月日时分秒.微妙

4.diffsecond函数返回秒差值,diffMicro返回微妙差值。

        string toString()const;//"123.32z"string toFormattedString(bool showmicto=true)const;//"2025/10/11 15:29:23"//"2025/10/11 15:29:23.32z"string toFormattedFile()const;//20251011152923.32

时间戳类型头文件设计如下:

#ifndef TIMESTAMP_HPP
#define TIMESTAMP_HPP
#include<stdint.h>//uint64_t
#include<string>
#include<sys/time.h>
#include<ctime>
using namespace std;
namespace wangt{class Timestamp{private:uint64_t micr_;//微秒public:Timestamp();Timestamp(uint64_t ms);~Timestamp();void swap(Timestamp &other);string toString()const;//"123.32z"string toFormattedString(bool showmicto=true)const;//"2025/10/11 15:29:23"//"2025/10/11 15:29:23.32z"string toFormattedFile()const;//20251011152923.32bool valid()const;//确保微秒有效uint64_t getmicro()const;uint64_t getsecond()const;const Timestamp&now();operator uint64_t()const;static Timestamp Now();//现在时间static Timestamp Invalid();static const uint32_t KMicPerSec=1000*1000;};inline time_t diffSecond(const Timestamp &a,const Timestamp &b){return a.getsecond()-b.getsecond();}inline time_t diffMicro(const Timestamp &a,const Timestamp &b){return a.getmicro()-b.getmicro();}
}
#endif
成员类型具体成员作用说明
私有成员uint64_t micr_存储时间的核心变量(单位:微秒),用 uint64_t 避免溢出
静态常量static const uint32_t KMicPerSec秒与微秒的转换系数(1000*1000),简化计算
构造函数Timestamp()Timestamp(uint64_t ms)- 默认构造:初始化 micr_=0(无效时间)- 带参构造:用指定微秒数初始化
静态成员函数static Timestamp Now()static Timestamp Invalid()Now():获取当前系统时间(核心函数)- Invalid():返回无效时间戳(micr_=0
成员函数toString()toFormattedString()toFormattedFile()三种时间格式转换:- 秒。微秒(如 1728678000.123456Z)- 标准格式(如 2024/10/12 15:00:00.123456Z)- 文件名格式(如 20241012150000.12
工具函数valid()getmicro()getsecond()valid():判断时间戳是否有效(micr_>0)- getmicro()/getsecond():获取微秒 / 秒级时间
友元 / 全局函数diffSecond()diffMicro()计算两个时间戳的 “秒差” 和 “微秒差”(内联函数,提升效率)

具体时间戳类型类型具体实现讲解

1.设置公有静态函数 static Timestamp Now();获取当前时间,返回类成员变量,并用成员函数Timestamp::now()在内部用this指针接受。

如下:

我们利用::gettimeofday(tv,nullptr)获取当前时间存储到struct timeval结构体tv中,并用成员函数Timestamp::now()在内部用this指针接受。

2.类型转换设计,我们定义了三种类型转换的成员函数。

  • string toString()const;直接返回秒+微秒

slen定义为128,永內部私有成员micr_进行秒和微秒的转换,后用sprintf进行写入到buff中

string wangt::Timestamp::toString() const
{char buff[slen]={};time_t sec=micr_/KMicPerSec;time_t mic=micr_-KMicPerSec*sec;sprintf(buff,"%lu.%luZ",sec,mic);return string(buff);
}
  • string toFormattedString(bool showmicto=true)const;showmicto判断微妙是否为0。返回格式为:年/月/日 时:分:秒.微妙

slen定义为128,用內部私有成员micr_进行秒和微秒的转换,用localtime_r函数对sec进行格式转换存储到struct tm 结构体中,后用sprintf按格式进行写入到buff中。

如果showmicto不为0将其写入buff_pos后面。

string wangt::Timestamp::toFormattedString(bool showmicto) const
{char buff[slen]={};time_t sec=micr_/KMicPerSec;time_t mic=micr_-KMicPerSec*sec;struct tm tm_time;localtime_r(&sec,&tm_time);
// tm_year 是“年份-1900”,需加回
// tm_mon 是 0-11,需加 1int pos=sprintf(buff,"%04d/%02d/%02d/%02d:%02d:%02d",tm_time.tm_year+1900,tm_time.tm_mon+1,tm_time.tm_mday,tm_time.tm_hour,tm_time.tm_min,tm_time.tm_sec);if(showmicto){sprintf(buff+pos,".%04luZ",mic);}return string(buff);
}
  • string toFormattedFile()cosnt;返回格式:年月日时分秒.微妙

同上思想一样。

wangt::Timestamp wangt::Timestamp::Now()
{struct timeval tv;::gettimeofday(&tv,nullptr);return Timestamp(tv.tv_sec*KMicPerSec+tv.tv_usec);
}
const wangt::Timestamp &wangt::Timestamp::now()
{*this=wangt::Timestamp::Now();return *this;
}

时间戳类型类型源文件如下:

#include "Timestamp.hpp"
static uint32_t slen=128;
wangt::Timestamp::Timestamp():micr_(0)
{//构造函数并初始化micr_为0
}wangt::Timestamp::Timestamp(uint64_t ms):micr_(ms)
{//构造函数并初始化micr_为ms
}wangt::Timestamp::~Timestamp()
{//析构函数
}void wangt::Timestamp::swap(Timestamp &other)
{//交换函数Timestamp a=*this;*this=other;other=a;
}string wangt::Timestamp::toString() const
{char buff[slen]={};time_t sec=micr_/KMicPerSec;time_t mic=micr_-KMicPerSec*sec;sprintf(buff,"%lu.%luZ",sec,mic);return string(buff);
}string wangt::Timestamp::toFormattedString(bool showmicto) const
{char buff[slen]={};time_t sec=micr_/KMicPerSec;time_t mic=micr_-KMicPerSec*sec;struct tm tm_time;localtime_r(&sec,&tm_time);int pos=sprintf(buff,"%04d/%02d/%02d/%02d:%02d:%02d",tm_time.tm_year+1900,tm_time.tm_mon+1,tm_time.tm_mday,tm_time.tm_hour,tm_time.tm_min,tm_time.tm_sec);if(showmicto){sprintf(buff+pos,".%04luZ",mic);}return string(buff);
}string wangt::Timestamp::toFormattedFile() const
{//20251011152923.32char buff[slen]={};time_t sec=micr_/KMicPerSec;time_t mic=micr_-KMicPerSec*sec;struct tm tm_time;localtime_r(&sec,&tm_time);int pos=sprintf(buff,"%04d%02d%02d%02d%02d%02d.%02lu",tm_time.tm_year+1900,tm_time.tm_mon+1,tm_time.tm_mday,tm_time.tm_hour,tm_time.tm_min,tm_time.tm_sec,mic);return string(buff);
}bool wangt::Timestamp::valid() const
{return micr_>0;
}uint64_t wangt::Timestamp::getmicro() const
{//获取当前微妙时间return micr_;
}uint64_t wangt::Timestamp::getsecond() const
{//获取当前妙时间return micr_/KMicPerSec;
}const wangt::Timestamp &wangt::Timestamp::now()
{*this=wangt::Timestamp::Now();return *this;
}wangt::Timestamp::operator uint64_t() const
{//将参数转为uint64_t类型return micr_;
}wangt::Timestamp wangt::Timestamp::Now()
{struct timeval tv;::gettimeofday(&tv,nullptr);return Timestamp(tv.tv_sec*KMicPerSec+tv.tv_usec);
}wangt::Timestamp wangt::Timestamp::Invalid()
{return Timestamp(0);
}

运行代码如下:

注意事项与优化点

  1. 缓冲区大小:代码中 slen=128 是保守值,实际时间字符串最长约 30 字符(如 2024/10/12 15:00:00.123456Z),无需过大,但需避免溢出。
  2. 跨平台兼容性gettimeofday() 是 Unix/Linux 特有函数,Windows 需替换为 QueryPerformanceCounter() 或 GetSystemTimePreciseAsFileTime(),需做跨平台适配。
  3. 微秒显示精度toFormattedFile() 中取微秒前 2 位(mic/10000),可根据需求调整(如取前 3 位则改为 mic/1000)。
  4. 线程安全localtime_r() 已确保线程安全,但需注意 sprintf() 的缓冲区是栈上局部变量,无线程安全问题。

总结

Timestamp 类是日志系统的 “时间基石”,通过封装 gettimeofday() 等底层函数,实现了 “高精度时间获取” 和 “多格式转换” 的核心能力。其设计遵循 “底层存储统一(微秒)、上层格式多样” 的原则,既保证了时间精度,又适配了日志内容、文件名等不同场景的需求。后续日志系统可直接依赖此类,为每条日志添加精确的时间戳,提升日志的可追溯性。

http://www.dtcms.com/a/474497.html

相关文章:

  • 手机网站 qq代码免费app制作工具
  • MyBatis-Plus 全方位使用指南:从基础 CRUD 到复杂查询
  • avalonia的hello示例及mvvm实现
  • 天津网站建设优化如何建网站费用多少
  • 网站建设泉州效率网络企业网站建设基本原则
  • 41.Shell Case选择 While循环
  • 基于单片机的智能水箱温度液位控制系统设计
  • 数字化转型—AI+制造业的十大应用场景
  • Java-集合练习
  • 新民正规网站建设价格咨询广州app开发价格表
  • 适合用struts2做的网站钦州教育论坛网站建设
  • 关于节约化建设网站的表态发言企业推广方式力荐隐迅推
  • 北京备案网站莱芜58同城网
  • JavaSE面向对象(中)
  • 保健品网站源代码代理平台什么意思
  • 做网站签了合同后不想做了办公室装修公司哪里好
  • 网站建设和网络优化网站建设对网络营销有哪些影响
  • wordpress导入网站文章西安seo专员
  • 大学城网站开发公司深圳企业网页设计公司
  • commons-configuration2(配置管理库)
  • 处理Git错误:“invalid object [hash]”和“unable to read tree [hash]”
  • MySQL数据库 常用命令整理
  • 前端开发 - 实时智能回复
  • 对电子商务网站建设与维护的总结wordpress多选展示表单
  • 从零起步学习MySQL || 第二章:DDL语句定义及常见用法示例
  • Oracle REST Data Services是什么?
  • [吾爱大神原创工具] windows 多窗口同步软件(键+鼠) 20251011 更新
  • TDengine 数学函数 COS 用户手册
  • qfd 网站开发wordpress 上传主题 ftp
  • 算法与数据结构——排序算法大全