【C/C++】获取当前系统时间(time_t和tm)清晰梳理

C/C++ 专栏收录该内容
16 篇文章 0 订阅

一、代码

实现:获取系统时间,并输出
先上各种实现代码,再详细解析函数,不想详细了解的可直接看第四部分回顾梳理。
1、方法一
按字符串输出,格式已规定好,不可自己改变格式
格式:Thu Feb 28 14:14:17 2019

#include <time.h>

int main()
{
    time_t timep;

    time(&timep); //获取从1970至今过了多少秒,存入time_t类型的timep
    printf("%s", ctime(&timep));//用ctime将秒数转化成字符串格式,输出:Thu Feb 28 14:14:17 2019
    
    return 0;
}

2、方法二
用stuct tm结构体,可自己改变格式
输出:2019/2/28 14:18:31

#include <time.h>

int main()
{
    time_t timep;
    struct tm *p;

    time(&timep); //获取从1970至今过了多少秒,存入time_t类型的timep
    p = localtime(&timep);//用localtime将秒数转化为struct tm结构体

    printf("%d/%d/%d %02d:%02d:%02d\n", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday,p->tm_hour, p->tm_min, p->tm_sec);//2019/2/28 14:18:31

    return 0;
}

若需要输出星期

#include <time.h>

int main()
{
    time_t timep;
    struct tm *p;

    time(&timep); //获取从1970至今过了多少秒,存入time_t类型的timep
    p = localtime(&timep);//用localtime将秒数转化为struct tm结构体

    char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    printf("%s", wday[p->tm_wday]);//Thu

    return 0;
}

3、方法三
效果和方法一相同,按字符串输出,格式已规定好,不可自己改变格式
格式:Thu Feb 28 14:14:17 2019

#include <time.h>

int main()
{
    time_t timep;

    time(&timep); //获取从1970至今过了多少秒,存入time_t类型的timep
    printf("%s", asctime(localtime(&timep)));//用localtime将秒数转化为struct tm结构体,再用asctime将结构体转化成字符串格式

    return 0;
}

具体异同辨析看下面详解

二、大体思路

需要头文件 #include <time.h>
(关于地方时,我在第三部分用到时有简单的介绍,现在说怕待会儿用到时候就忘了hhhh)
这里用最简单的话,大致介绍一下我理解的time_t类型和struct tm结构体。

在计算机中看到的utc时间都是从(1970年01月01日 0:00:00)开始计算秒数的。
我们可以通过函数time()来获取从1970年到现在经过了多少秒,并定义time_t 这种类型(本质上是长整型long)来存储从1970年到现在经过了多少秒
现在我们有了1970年至今的秒数了,但是我们是无法直接通过秒数看出当前的年月日的,所以需要用函数进行转化。(比如直接告诉你现在距离1970年过了1551193610秒,你是不知道今天几号的,得通过函数转化成“Tue Feb 26 20:32:53 2019”这种形式)
这里用于转化的函数,我们暂且称之为时间函数,它们有很多。
我们按照输出参数类型进行分类,一共有两种,
第一种是直接输出字符指针类型,这种函数的好处是可以直接打印字符串(输出如 :Tue Feb 26 20:32:53 2019),但是它的缺点是无法按照想要的格式输出。
第二种函数是输出struct tm结构体类型指针,这种结构体中分别定义了年月日时分秒等,我们可以利用它输出成我们想要的格式(如:2019/2/26 21:01:38)。

【这是我的理解,我感觉有些博文中说的有两种储存方式会略显凌乱,那样子可能会误以为不用定义time_t也可以直接通过struct tm来读取日期,而事实上并不能。我觉得time_t类型和struct tm结构体之间的关系应该如上所述,time_t是用来存放1970至今的秒数的一个长整型而已,存放下来的秒数可以通过各种时间函数来转化成struct tm结构体指针,方便格式化输出,这样子就比较清晰了。】

关于struct tm结构体,以下给出其原型:

struct tm
{
    int tm_sec;  /*秒,正常范围0-59, 但允许至61*/
    int tm_min;  /*分钟,0-59*/
    int tm_hour; /*小时, 0-23*/
    int tm_mday; /*日,即一个月中的第几天,1-31*/
    int tm_mon;  /*月, 从一月算起,0-11*/  1+p->tm_mon;
    int tm_year;  /*年, 从1900至今已经多少年*/  1900+ p->tm_year;
    int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/
    int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/
    int tm_isdst; /*日光节约时间的旗标*/
};

【注意】结构体struct tm的年份是从1900年起至今多少年,月份从0开始的,0表示一月,星期也是从0开始的, 0表示星期日,1表示星期一。

三、具体使用与解析

1、定义time_t类型变量,用来存储1970至今的秒数
本质上time_t是长整型,我用 long 替换后运行没有任何差别。

time_t timep;

2、利用函数time()获取从1970年至今的秒数

 time(&timep);

函数原型 : time_t time(time_t *t);

 time(&timep);
 printf("%d",timep);

输出 : 1551193610

3、使用各种时间函数将time_t类型存储的秒数转换为常见的格式

我们可以用下面几种函数将秒数转化成我们常用的格式:
有点容易混淆,先把表格贴上来,方便对比异同。

函数名称是否是准确时间(加地方时)传入参数类型返回值类型
localtimetime_t类型的地址 const time_t *结构体指针 stuct tm*
ctimetime_t类型的地址 const time_t *字符指针 char *
gmtime×time_t类型的地址 const time_t *结构体指针 stuct tm*
asctime加不加地方时取决于传入的结构体有没有加地方时(与上列函数不同类,在此仅作对比辨析)struct tm结构体类型的指针 const struct tm*字符指针 char *

asctime()函数其作用是将结构中的信息转换字符串格式,加不加地方时取决于传入的结构体有没有加地方时,传入用 localtime生成的结构体加地方时,传入用gmtime生成的结构体不加地方时。asctime()与上列函数不同类,localtime、ctime、gmtime是将存在 time_t类型中的秒数转化为字符串或stuct tm结构体类型,而asctime则是将stuct tm结构体转化为字符串,因此在此仅作对比辨析,详细的我在第4点中细说。

【UTC就是0时区的时间,UTC加上地方时为本地时间】
这里出现了一个新名词:地方时,因为咱们存在time_t中的总秒数是以0时区为准的,要加上地方时才是当前所在地的真实时间。(至于时区的概念可以参考高中还是初中的地理书)
简单来说:想要获取当前电脑显示的时间,请选用localtime,ctime这两个加过地区时的函数。

【例如我所在区域(真正时间为Tue Feb 26 21:15:20 2019)
用加地方时的函数输出:Tue Feb 26 21:15:20 2019
不加地方时的函数输出:Tue Feb 26 13:15:20 2019
相差8个小时(北京为东八区)】

(1) localtime
【加地方时】将timep转换为真实世界的时间,传入一个time_t类型变量的地址,返回一个struct tm结构体类型指针,优点是可以自行控制输出格式,缺点是不能直接当作字符串输出,得用指针访问结构体内部输出。

函数原型 : stuct tm* localtime(const time_t *timep);

    struct tm *p;
    p = localtime(&timep);
    printf("%d/%d/%d %02d:%02d:%02d\n", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday,p->tm_hour, p->tm_min, p->tm_sec);

输出 : 2019/2/26 21:01:38

如果要输出星期的话,还要加上

    char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    printf("%s", wday[p->tm_wday]);

输出 : Tue

(2)ctime
【加地方时】将timep转换为真实世界的时间,传入一个time_t类型变量的地址,返回一个字符数组指针,优点是可以直接按字符串输出,缺点是不能自行控制输出格式。

函数原型 : char *ctime(const time_t *timep);

printf("%s", ctime(&timep));

输出 : Tue Feb 26 20:32:53 2019

--------------------------------
以上都是加地方时的:localtime,ctime
以下都是不加地方时(UTC)的:gmtime
--------------------------------
(3)gmtime
【不加地方时】传入一个time_t类型变量的地址,返回一个struct tm结构体类型指针,优点是可以自行控制输出格式,缺点是不能直接当作字符串输出,得用指针访问结构体内部输出。
localtime类似,区别是gmtime不加地方时

函数原型 : struct tm* gmtime(const time_t *timep);

    struct tm *p;
    p = gmtime(&timep);
    printf("%d/%d/%d %02d:%02d:%02d\n", 1900 + p->tm_year, 1+ p->tm_mon, p->tm_mday,p->tm_hour, p->tm_min, p->tm_sec);

输出 : 2019/2/28 05:07:07

【实际时间:2019/2/28 13:07:07】
如果要输出星期的话,还要加上

    char *wday[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
    printf("%s", wday[p->tm_wday]);

输出 : Thu

4、将struct tm结构体转化为字符串
asctime函数
传入一个struct tm结构体类型的指针,返回一个字符数组指针。
我们用localtime或者gmtime将秒数转化成struct tm结构体类型就是为了可以自己定义输出方式,这个函数的作用是将我们好不容易转化的struct tm结构体类型按照字符串的格式输出,嗯~ o( ̄▽ ̄)o有点迷……只能说函数给的很全面,作用就是这么个作用。

函数原型 : char * asctime(const struct tm* timeptr);

(1)用localtime转化成的结构体是加地方时的。
asctime(localtime(&timep))与ctime(&timep)效果完全相同。
前者先将秒数转化成结构体再转化成字符串,后者直接将秒数转化成字符串格式。

printf("%s", asctime(localtime(&timep)));

输出 : Thu Feb 28 13:38:41 2019

(2)用gmtime转化成的结构体是不加地方时的。

printf("%s", asctime(gmtime(&timep)));

输出 : Thu Feb 28 05:38:41 2019

再友情提醒一遍,当前真实时间是Thu Feb 28 13:38:41 2019哦~

5、一些不常用的其他函数
(1)difftime返回两个时间相差的秒数

double difftime(time_t time1, time_t time2);

(2)gettimeofday返回当前距离1970年的秒数和微妙数,后面的tz是时区,一般不用

int gettimeofday(struct timeval *tv, struct timezone *tz);

(3)mktime将struct tm 结构的时间转换为从1970年至今的秒数
(果然函数给的很全,这种都有……)

time_t mktime(struct tm* timeptr);

四、回顾与梳理

在计算机中时间都是从(1970年01月01日 0:00:00)开始计算秒数的。
1、我们首先定义time_t 这种类型(本质上是长整型long)来存储从1970年到现在经过了多少秒

2、再通过函数time()来获取从1970年到现在经过了多少秒

3、为了便于阅读,我们采用函数将“过了多少秒”进行转化
可以用以下函数,这里再次辨析一遍

函数名称是否是准确时间(加地方时)区别
localtime准确时间传入秒数,输出结构体,方便自定义格式输出
ctime准确时间传入秒数,输出字符指针,方便直接输出
gmtime非本地时间,是0时区时间传入秒数,输出结构体,方便自定义格式输出

4、一些其他函数
主要是asctime函数,它的作用是将struct tm结构体转化为字符串,加不加地方时完全取决于传入的结构体有没有加地方时。有的博文将他归类为生成不加地方时的函数,是不合理的,大家注意辨析。

【这块儿很简单,但是用的时候发现参考了一堆文章,发现网上有的思路不是很清晰,本来想写简明,结果啰啰嗦嗦一大堆……第一次写博文,写的不好的地方大家多担待,也欢迎大家提出建议意见】

©️2021 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值