Linux 编程实践-时间与时区 时间的表现形式与解析


时间的三种表现形式

1. 时间戳(timestamp, seconds since the Epoch) 即可 197011000 秒起的 UTC(Universal Coordinated Time)时间的经过的秒数. (UTC 之前也叫 GMT Greenwich Mean Time)
2. 时间结构体 struct tm

    struct tm { 
    				int tm_sec; /* seconds after the minute [0-60] */ 
    				int tm_min; /* minutes after the hour [0-59] */ 
    				int tm_hour; /* hours since midnight [0-23] */ 
    				int tm_mday; /* day of the month [1-31] */ 
    				int tm_mon; /* months since January [0-11] */ 
    				int tm_year; /* years since 1900 */ 
    				int tm_wday; /* days since Sunday [0-6] */ 
    				int tm_yday; /* days since January 1 [0-365] */ 
    				int tm_isdst; /* Daylight Savings Time flag */ 
    				long tm_gmtoff; /* offset from UTC in seconds */ 
    				char *tm_zone; /* timezone abbreviation */
    				}

1. 字符串如 2019-06-14 23:04:59

关于调用方式的简单的说明

注意取值函数调用结果的两种方式.

1. 使用返回值,主要用于标量.
2. 使用 inout 参数,主要用于数组,结构体或字符串等需要动态内存分配的数据结构.

一部分函数属于 C 语言标准,<time.h> 头文件中声明. 一部分函数属于 系统标准如 POSIX,<sys/time.h> 中声明.(如 gettimeofday,settimeofday,adjtime)

- gmtime 的可重入版本(或者说线程安全版本)为 gmtime_r

- localtime 的可重入版本为 localtime_r 

当前时间

操作系统提供了以下两个系统调用用来获得当前时间. 主要是得到时间戳形式的时间.

1. time_t time(NULL) 返回当前时间戳 (精度秒), 原完整声明为 time_t time(time_t *tloc);但是建议使用返回值,所以一般传 NULL 参数.
2. int getimeofday(struct timeval *tv,NULL),原完整声明为 int gettimeofday(struct timeval *tv, struct timezone *tz);,但是 struct timezone 结构体已不推荐使用了,所以第进一个参数一般也传 NULL

    struct timeval{ time_t tv_sec;// 秒 suseconds_t tv_usec;// 微秒,精度取决于硬件,现代硬件一般都支持微秒及精度.}

1. int settimeofday(const struct timeval *tv, const struct timezone *tz); 设置当前时间,需要 root 权限 .简单粗暴.
2. int adjtime(const struct timeval *delta, struct timeval *olddelta); 系统时间会慢慢的赶上来.

时间的转换.

时间戳 与 struct tm 结构体之间的转换

1. struct tm* gmtime(time_t *) 将时间戳转化为 UTC 时间的结构体. (gm 是 Greewhich Median 的缩写)
2. struct tm* localtime(time_t *) 根据当前生效时区及夏令时(DST)相关设置转换成时间结构体.
3. time_t mktime(struct tm*) 将 时间结构体转换为时间戳.

struct tm 结构体 与字符串之间的转换

1. char *asctime(struct tm*)struct tm 结构体,转换成固定格式的字符串表示.类似 Fri Jun 14 23:46:03 2019, 注意不可重入.
2. strftime(char* outstr,size_t maxsize, char *format, struct tm*) 根据格式化字符串 format 的参数的配置,转化成对应字符串表示.
3. char *strptime(char *str,char *format, struct tm*) 根据格式化字符串 format 的配置,将 str 所表示的时间转换成 struct tm 结构体.

时间戳与字符串

1. char *ctime(time_t*) 用于将时间戳转换成固定格式的字符串表示,格式同 asctime.(同样不重入)
   

时间的格式化指示符

时间格式化指示符以 % 开头.

指示符 说明 示例 记忆技巧

%y year 年份,2 位数 19 小写位数比较少

%Y Year 年份,4 位数 2019 大写位数比较多

%C Century 世纪 ,2 位数 20 世纪是大单位用大写

%m month 月份,2 位数(01-12) 01 月数比较少用小写

%M Minute 分钟,2 位数 48 分钟数范围比较大用大写

%d day of month,2 位数 15 day of month

%D 美国日期格式,相当于%m/%d/%y 06/15/19 Date 美国人约会的日子叫 Date

%e day of month,2 位数 15 day of month

%h 月份名缩写同 %b Feb

%H Hour 24 小时制时间 ,2 位数 19 大写表示数值比较大的

%I Hour 12 小时制时间 ,2 位数 05 mIddle 从一天中间开始循环

%S Second 00-60 59 秒数范围比较大用大写

%s second 时间戳 1560557151

%a 缩写的星期名 Tue a 字母第 1,美国人日期习惯星期在前

%A 完整的星期名 Tuesday 大写表示名称比较完整

%b 缩写的月份名 Feb b 字母第 2,美国人日期习惯月分在第 2%B 月份名 February 大写表示名称比较完整

%h 月份名缩写同 %b Feb 方便记忆重复列出

%p AM/PM AM pm 是 post meridiem 的缩写

%j day of year(000-366) 166

%w day of week(0-6) sunday=0 3

%u day of week(1-7) sunday=7 3

%W 一年中的周数,按一周始于周一 52 大写表示周数值范围比较大

%U 一年中的周数,按一周始于周日 52 大写表示周数值范围比较大

%V 一年中的周数,争议周那边多归哪边 52 ISO 8601:1988 规定

%G 4 位数年份,配合 %V 的周次 2010 ISO 8601:1988 规定

%g 2 位数年份,配合 %V 的周次 2010 ISO 8601:1988 规定

%z 标准时区声明格式 +0800 根据 RFC-822/ISO 8601

%Z timeZone name 时区名 CST,UTC 时间名是大写的

%c current date time,时区相关 20190615 日 星期六 091538%D 相当于 %m/%d/%y

%F 相当于 %Y-%m-%d 2019-06-15 Full date ,也是 ISO 8601 格式

%R 相当于 %H:%M 19:24

%T 相当于 %H:%M:%S 19:24:38

%x 当前日期表示,时区相关 20190615%X 当前时间表示,时区相关 091538%t tab 符,parse 时表示空白符

%n 换行符,parse 时表示空白符

%% 表示%符号

此外

1. 加 E 修饰的如 %Ec, %EC,%Ex,%EX,%Ey,%EY 表示可能包含对应区域其他可选表示.
2. 加 O 修饰的如 %Od,%Oe, %OH,%OI,%Om,%OM,%OS,%OU,%Ow,%OW,%Oy 表示可能包含对应区域其他可选表示.
3. 其他不识别的指示符可能会被忽略,输出时则一般会原样输出

date 命令

1. 指定格式输出当前时间的表示. date +FORMAT 如 date +%c
       # date +%c
       Sun 11 Apr 2021 07:13:13 PM CST
   
2. -d,--date 指定要解析的时间 --date '2019-01-01' 实际上 --date 支持任意合法的日期时间表示.'next monday' ,'3 days ago'
       # date --date '2010-01-01' +%g
       09
       #date --date '2010-01-01' +%c
       Fri 01 Jan 2010 12:00:00 AM CST
   
3. 输入的日期字符串,日期和时间可以通过空格或者 T 字符分隔.
       # date +'%x %A %T %Z'
       04/11/2021 Sunday 19:20:38 CST
   
4. 解析时间戳在时间戳前面加 @ 符号如 date --date '@1566666666'
       # date +%s //获取时间戳
       1618139856
       # date --date '@1618139856' +%c //解析时间戳
       Sun 11 Apr 2021 07:17:36 PM CST
   

code:

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>

void dump_timeval(const struct timeval *tv)
{

    printf("struct timeval {\n");
    printf("\t tv_sec=%ld\n",tv->tv_sec);
    printf("\t tv_usec=%ld\n",tv->tv_usec);
    printf("}\n");
}

void dump_time(const struct tm *t)
{
        printf ("struct tm {\n");
        printf ("\t  tm_sec=%d,\n", t->tm_sec); 
        printf ("\t  tm_min=%d,\n", t->tm_min); 
        printf ("\t  tm_hour=%d,\n",t->tm_hour); 
        printf ("\t  tm_mday=%d,\n",t->tm_mday); 
        printf ("\t  tm_mon=%d,\n", t->tm_mon);  
        printf ("\t  tm_year=%d,\n",t->tm_year); 
        printf ("\t  tm_wday=%d,\n",t->tm_wday);
        printf ("\t  tm_yday=%d,\n",t->tm_yday);  
        printf ("\t  tm_isdst=%d,\n",t->tm_isdst); 
        printf ("\t  tm_gmtoff=%ld,\n",t->tm_gmtoff); 
        printf ("\t  tm_zone=%s,\n",t->tm_zone); 
		printf("}\n");


}


int main()
{
    const time_t t =time(NULL);
    struct timeval tv;
    gettimeofday(&tv, NULL);
    printf("time_t t = %ld\n",t);
    dump_timeval(&tv);
    
    time_t now = time(NULL);
    struct tm* lt = localtime(&now);
    printf("localtime:\n");
    dump_time(lt);

    
    const time_t now_ret = mktime(lt);//将时间结构体转换为时间戳.
    //date --date '@now_ret' +%c linux comamnd 进行验证
    printf("mktime:%ld\n",now_ret);

    const struct tm* gm = gmtime(&now);
    printf("gmtime:\n");
    dump_time(gm);

    sleep(3);
    printf("sleep gmtime:\n");
    time_t sec3 = time(NULL);
    gmtime(&sec3);
    dump_time(gm);

    return 0;
}

程序输出

[root@localhost cpp]# gcc -Wall -g learn_time.c -o learn && ./learn
time_t t = 1618146432
struct timeval {
         tv_sec=1618146432
         tv_usec=717347
}
localtime:
struct tm {
          tm_sec=12,
          tm_min=7,
          tm_hour=21,
          tm_mday=11,
          tm_mon=3,
          tm_year=121,
          tm_wday=0,
          tm_yday=100,
          tm_isdst=0,
          tm_gmtoff=28800,
          tm_zone=CST,
}
mktime:1618146432
gmtime:
struct tm {
          tm_sec=12,
          tm_min=7,
          tm_hour=13,
          tm_mday=11,
          tm_mon=3,
          tm_year=121,
          tm_wday=0,
          tm_yday=100,
          tm_isdst=0,
          tm_gmtoff=0,
          tm_zone=GMT,
}
sleep gmtime:
struct tm {
          tm_sec=15,//sleep 3s
          tm_min=7,
          tm_hour=13,
          tm_mday=11,
          tm_mon=3,
          tm_year=121,
          tm_wday=0,
          tm_yday=100,
          tm_isdst=0,
          tm_gmtoff=0,
          tm_zone=GMT,
}
//验证mktime:1618146432
[root@localhost cpp]# date --date '@1618146432' +%c
Sun 11 Apr 2021 09:07:12 PM CST
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值