• muduo 库解析之二:TimeStamp


    PRId64

    int64_t 用来表示64位整数,在32位系统中是 long long int,在64位系统中是 long int,所以打印 int64_t 的格式化方法是:

    printf("%ld", value); //@ 64bit OS
    printf("%lld", value); //@ 32bit OS
    

    跨平台的方法:

    #include <inttypes.h>
    
    printf("%" PRId64 "
    ", value); 
    
    //@ 相当于64位的:
    printf("%" "ld" "
    ", value); 
    //@ 或32位的:
    printf("%" "lld" "
    ", value); 
    

    这个是定义给 C 用的,C++要用它,就要定义一个 __STDC_FORMAT_MACROS 宏显示打开它。

    Linux 下时间

    术语

    • Coordinated Universal Time(UTC):协调世界时,又称为世界标准时间,也就是大家所熟知的格林威治标准时间(Greenwich Mean Time,GMT)。比如,中国内地的时间与UTC的时差为+8,也就是UTC+8。美国是UTC-5。
    • Calendar Time: 日历时间,是用“从一个标准时间点到此时的时间经过的秒数”来表示的时间。这个标准时间点对不同的编译器来说会有所不同,但对一个编译系统来说,这个标准时间点是不变的,该编译系统中的时间对应的日历时间都通过该标准时间点来衡量,所以可以说日历时间是“相对时间”,但是无论你在哪一个时区,在同一时刻对同一个标准时间点来说,日历时间都是一样的。
    • epoch:时间点。时间点在标准C/C++中是一个整数,它用此时的时间和标准时间点相差的秒数(即日历时间)来表示。
    • clock tick:时钟计时单元(而不把它叫做时钟滴答次数),一个时钟计时单元的时间长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位。

    数据结构

    struct tm

    ANSI C标准称使用 tm 结构的这种时间表示为分解时间(broken-down time)。

    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代表一月) - 取值区间为[0,11] */
        int tm_year;      /* 年份,其值等于实际年份减去1900 */
        int tm_wday;      /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
        int tm_yday;      /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
        int tm_isdst;     /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。*/
     };
    

    time_t

    time_t 表示的时间(日历时间)是从一个时间点(例如:1970年1月1日0时0分0秒)到此时的秒数。

    typedef long time_t;           /* 时间值 */
    

    time_t 数据类型的值来说,它所表示的时间不能晚于2038年1月18日19时14分07秒。为了能够表示更久远的时间,一些编译器厂商引入了64位甚至更长的整形数来保存日历时间。比如微软在 Visual C++ 中采用了 __time64_t 数据类型来保存日历时间,并通过 _time64() 函数来获得日历时间,这样就可以通过该数据类型保存3001年1月1日0时0分0秒(不包括该时间点)之前的时间。

    struct timeval

     struct timeval
     {
       __time_t tv_sec;  /* 秒*/
       __suseconds_t tv_usec;  /* 微秒*/
     }; 
    
    • tv_sec 为 Epoch 到创建 struct timeval 时的秒数,tv_usec 为微秒数。

    clock_t

    typedef long clock_t;
    

    struct timespec

    struct timespec
    {
        time_t tv_sec; /* 秒*/
        long tv_nsec; /* 纳秒*/
    };
    

    相关函数

    获得日历时间

    time_t time(time_t * timer);
    
    • 参数为空(NULL),函数将只通过返回值返回现在的日历时间。
    • 参数不为空(NULL),函数将通过返回值返回现在的日历时间或者通过 timer 获取现在的日历时间。

    分解时间转化为日历时间

    time_t mktime(struct tm * timeptr);
    

    日历时间转换成分解时间

    struct tm *gmtime(const time_t *timep); //@ 线程不安全
    struct tm *gmtime_r(const time_t *timep, struct tm *result); //@ 线程安全
    
    struct tm *localtime(const time_t *timep); // 线程不安全
    struct tm *localtime_r(const time_t *timep, struct tm *result); //@ 线程安全
    
    • gmtime() 函数是将日历时间转化为世界标准时间(即格林尼治时间)。
    • localtime() 函数是将日历时间转化为本地时间,即包含了时区。

    固定的时间格式

    char * asctime(const struct tm * timeptr);
    char * ctime(const time_t *timer);
    
    • asctime() 函数是通过tm结构来生成具有固定格式的保存时间信息的字符串。
    • ctime() 函数需要先参照本地的时间设置,把日历时间转化为本地时间,然后再生成格式化后的字符串。
    • 返回的时间格式为:星期几 月份 日期 时:分:秒 年

    自定义时间格式

    size_t strftime(char *strDest,size_t maxsize,const char *format,const struct tm *timeptr);
    
    • 根据 format 指向字符串中格式命令把 timeptr 中保存的时间信息放在 strDest 指向的字符串中,最多向 strDest 中存放 maxsize 个字符。该函数返回向strDest 指向的字符串中放置的字符数。
    • 格式命令列在下面,它们是区分大小写的:
    %a 星期几的简写
    %A 星期几的全称
    %b 月份的简写
    %B 月份的全称
    %c 标准的日期的时间串
    %C 年份的后两位数字
    %d 十进制表示的每月的第几天
    %D 月/天/年
    %e 在两字符域中,十进制表示的每月的第几天
    %F 年-月-日
    %g 年份的后两位数字,使用基于周的年
    %G 年分,使用基于周的年
    %h 简写的月份名
    %H 24小时制的小时
    %I 12小时制的小时
    %j 十进制表示的每年的第几天
    %m 十进制表示的月份
    %M 十时制表示的分钟数
    %n 新行符
    %p 本地的AM或PM的等价显示
    %r 12小时的时间
    %R 显示小时和分钟:hh:mm
    %S 十进制的秒数
    %t 水平制表符
    %T 显示时分秒:hh:mm:ss
    %u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
    %U 第年的第几周,把星期日做为第一天(值从0到53)
    %V 每年的第几周,使用基于周的年
    %w 十进制表示的星期几(值从0到6,星期天为0)
    %W 每年的第几周,把星期一做为第一天(值从0到53)
    %x 标准的日期串
    %X 标准的时间串
    %y 不带世纪的十进制年份(值从0到99)
    %Y 带世纪部分的十制年份
    %z,%Z 时区名称,如果不能得到时区名称则返回空字符。
    %% 百分号
    

    计算持续的时间长度

    double difftime(time_t time1, time_t time0);
    
    • 只能精确到秒。

    获取时间和时区

    int gettimeofday (struct timeval *__restrict __tv, __timezone_ptr_t __tz);
    
    • 得到当前时间和时区,分别写到 tvtz 中,如果 tzNULL 则不向 tz 写入。
    • 可以精确到微秒。

    clock

    clock_t clock(void) ;
    
    • 表示进程运行时间,单位是CPU时钟计时单元(clock tick)数,或者说滴答数(ticks)。
    • CLOCKS_PER_SEC 是一个常数,表示一秒钟有多少个时钟计时单元。
    • 只能精确到秒。
    • 线程不安全,因为 clock() 返回进程总的时钟计时单元数量,而不是当前线程的。

    clock_gettime

    int clock_gettime(clockid_t clk_id, struct timespec* tp);
    
    • clk_id : 检索和设置的 clk_id 指定的时钟时间:
      • CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从 UTC1970-1-1 0:0:0 开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变。
      • CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响。
      • CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统 CPU 花费的时间。
      • CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统 CPU 花费的时间。

    计时函数总结

    源码实现

    TimeStamp.h

    #pragma once
    #include <cstdint>
    #include <string>
    
    #include "Copyable.h"
    
    namespace muduo
    {
        //@ 源代码还继承自  boost::equality_comparable<Timestamp>, boost::less_than_comparable<Timestamp>
        class TimeStamp : public Copyable
        {
        public:
            static const int kMicroSecondsPerSecond = 1000 * 1000;
    
            TimeStamp() : micro_seconds_since_epoch_(0) {}
            explicit TimeStamp(int64_t micro_seconds) : micro_seconds_since_epoch_(micro_seconds) {}
    
            void swap(TimeStamp &that)
            {
                std::swap(micro_seconds_since_epoch_, that.micro_seconds_since_epoch_);
            }
    
            std::string to_string() const;
            std::string to_formatted_string(bool show_micro_seconds = true) const;
    
            bool valid() const { return micro_seconds_since_epoch_ > 0; }
            int64_t micro_seconds_since_epoch() const { return micro_seconds_since_epoch_; }
            int64_t secnods_since_epoch() const
            {
                return static_cast<time_t>(micro_seconds_since_epoch_ / kMicroSecondsPerSecond);
            }
    
            static TimeStamp now();
            static TimeStamp invalid()
            {
                return TimeStamp(); //@ 获取一个无效的时间戳
            }
    
            static TimeStamp from_unix_time(time_t t)
            {
                return from_unix_time(t, 0);
            }
    
            static TimeStamp from_unix_time(time_t t, int micro_seconds)
            {
                return TimeStamp(static_cast<int64_t>(t) * kMicroSecondsPerSecond + micro_seconds);
            }
    
        private:
            int64_t micro_seconds_since_epoch_;
        };
    
        inline bool operator<(TimeStamp lhs, TimeStamp rhs)
        {
            return lhs.micro_seconds_since_epoch() < rhs.micro_seconds_since_epoch();
        }
    
        inline bool operator==(TimeStamp lhs, TimeStamp rhs)
        {
            return lhs.micro_seconds_since_epoch() == rhs.micro_seconds_since_epoch();
        }
    
        inline double time_difference(TimeStamp high, TimeStamp low)
        {
            int64_t diff = high.secnods_since_epoch() - low.secnods_since_epoch();
            return static_cast<double>(diff) / TimeStamp::kMicroSecondsPerSecond;
        }
    
        inline TimeStamp add_time(TimeStamp time_stamp, double seconds)
        {
            int64_t delta = static_cast<int64_t>(seconds * TimeStamp::kMicroSecondsPerSecond);
            return TimeStamp(time_stamp.secnods_since_epoch() + delta);
        }
    }
    

    TimeStamp.cc

    #include "TimeStamp.h"
    
    #include <sys/time.h>
    #include <inttypes.h> //@ PRId64
    
    namespace muduo
    {
        static_assert(sizeof(TimeStamp) == sizeof(int64_t), "TimeStamp should be same size as int64_t");
    
        std::string TimeStamp::to_string() const
        {
            char buf[32] = {0};
            int64_t seconds = micro_seconds_since_epoch_ / kMicroSecondsPerSecond;
            int64_t micro_seconds = micro_seconds_since_epoch_ % kMicroSecondsPerSecond;
            snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, micro_seconds);
            return buf;
        }
    
        std::string TimeStamp::to_formatted_string(bool show_micro_seconds) const
        {
            char buf[64] = {0};
            time_t seconds = static_cast<time_t>(micro_seconds_since_epoch_ / kMicroSecondsPerSecond);
            struct tm tm_time;
            gmtime_r(&seconds, &tm_time); //@ utc 时间
    
            if (show_micro_seconds)
            {
                int micro_seconds = static_cast<int>(micro_seconds_since_epoch_ % kMicroSecondsPerSecond);
                snprintf(buf, sizeof(buf), "%04d%02d%02d %02d:%02d:%02d.%06d", 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, micro_seconds);
            }
            else
            {
                snprintf(buf, sizeof(buf), "%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);
            }
            return buf;
        }
    
        TimeStamp TimeStamp::now()
        {
            struct timeval tv;       //@ 精确到微秒
            gettimeofday(&tv, NULL); //@ 忽略时区
            int64_t seconds = tv.tv_sec;
            return TimeStamp(seconds * kMicroSecondsPerSecond + tv.tv_usec);
        }
    
    }
    
  • 相关阅读:
    Class加载顺序
    Java中9大内置基本数据类型Class实例和数组的Class实例(转载)
    java配置日志总结
    Java格式化CST时间(mysql date类型)
    对称二叉树
    模拟--滑动窗口最大值
    group by两个条件
    P1996 约瑟夫问题
    C++命名空间、标准库(std,全局命名空间)
    java中引用对比C++指针
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/14693418.html
Copyright © 2020-2023  润新知