UNIX Time

Calendar Time

1. time

 #include <time.h>
time_t time(time_t *tloc);

这是一个系统调用,用来获取从1970-01-01 00:00:00 +0000 (UTC)至今的秒数,称为日历时间

一般tlocNULL

2. gettimeofday

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

这也是一个系统调用,这个系统调用获取的时间精度更高。

timeval 结构如下:

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

tv_sec 的值跟time系统调用的返回值一样

tv_usec 表示微秒

第二个参数已经废弃,传NULL就行

日历时间(用秒数表示的时间)很有用,但是有时候我们需要获取具体的日期时间,即所谓的Broken-Down Time

Broken-Down Time

#include <time.h>
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);

这两个函数将time_t表示的秒数转成日期时间(datetime)

gmtime返回的是UTC(GMT)日期时间

localtime返回的系统本地日期时间

struct tm结构如下:

struct tm {
    int tm_sec;   /* Seconds (0-60) 对应%S格式 */
    int tm_min;   /* Minutes (0-59) 对应%M格式 */
    int tm_hour;  /* Hours (0-23) 对应%H格式 */
    int tm_mday;  /* Day of the month (1-31) 对应%d格式 */
    int tm_mon;   /* Month (0-11) 对应%m格式-1 */
    int tm_year;  /* Year - 1900 对应%Y格式-1900 */
    int tm_wday;  /* Day of the week (0-6, Sunday = 0) 对应%w格式 */
    int tm_yday;  /* Day in the year (0-365, 1 Jan = 0) 对应%j格式-1 */
    int tm_isdst; /* Daylight saving time */
};

注释中指出了对应strftime函数的格式说明符

下面代码可以获取本地日期

time_t t = time(NULL);
struct tm *tm = localtime(&t);
printf("%d-%02d-%02d %02d:%02d:%02d\n",
        1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
// output:
// 2018-12-09 11:16:00

Broken-Down Time与字符串形式的互转

1. struct tm转成字符串

#include <time.h>
size_t strftime(char *outstr, size_t max, const char *format, const struct tm *tm)

下面代码可以获取本地日期

time_t t = time(NULL);
struct tm *tm = localtime(&t);
char str[32];
strftime(str, sizeof(str), "%F %T", tm);
// strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", tm);
printf("%s\n", str);

2. 字符串转struct tm

#include <time.h>
char *strptime(const char *s, const char *format, struct tm *tm);

下面的代码将字符串表示的日期时间转换为struct tm

const char *dtstr = "2018-12-09 11:16:00";
const char *format = "%Y-%m-%d %H:%M:%S";
struct tm tm;
memset(&tm, 0, sizeof(struct tm));
strptime(dtstr, format, &tm);

Broken-Down Time 转日历时间(time_t)

#include <time.h>
time_t mktime(struct tm *tm);

注意:

1. mktime使用系统的时区信息来解释tm参数
2. mktime根据tm->tm_isdst的值,决定是否将tm视为夏令时
    1. 当tm->tm_isdst == 0,将tm视为标准时间
    2. 当tm->tm_isdst > 0,将tm视为夏令时
    3. 当tm->tm_isdst < 0,根据系统的时区信息和tm共同确定是否将tm视为夏令时,并修改tm->tm_isdst的值
3. 如果tm_sec、tm_min、tm_hour、tm_mday、tm_mon、tm_year等字段不在各自的范围内,mktime会调整它们到范围内,这个特性很有用,可以使用这个特性做日期计算
4. 最后mktime会修改tm_wday和tm_yday,使其与其他字段匹配

下面代码将struct tm转换成日历时间(time_t),(特意选了一个夏令时,即:实行夏时制时的时间)

const char *dtstr = "1991-07-01 05:00:00";
const char *format = "%Y-%m-%d %H:%M:%S";
struct tm tm;
memset(&tm, 0, sizeof(struct tm));
strptime(dtstr, format, &tm);
tm.tm_isdst = -1; // Not set by strptime(); tells mktime() to determine if DST is in effect
time_t t = mktime(&tm);
printf("%ld\n", t); // 678312000
printf("%d\n", tm.tm_isdst); // 1 表示这个时间为夏令时

这里如果将 tm.tm_isdst = -1; 这行注释掉,那么转换输出的日历时间是678315600这是错误的

我们通过date命令反转这两个日历时间:

date -d @678312000 '+%F %T'
date -d @678315600 '+%F %T'
// output:
// 1991-07-01 05:00:00
// 1991-07-01 06:00:00

从转换结果看出来差了1小时,实行夏时制的时间比不实行夏时制的时间早了1小时

一个示例

enum option
{
    year    = 1,
    month   = 2,
    day     = 3,
    hour    = 4,
    minute  = 5,
    second  = 6,
};

time_t time_add(time_t t, int x, enum option opt)
{
    struct tm *tm = localtime(&t);
    switch (opt)
    {
    case year:
        tm->tm_year += x;
        break;
    case month:
        tm->tm_mon += x;
        break;
    case day:
        tm->tm_mday += x;
        break;
    case hour:
        tm->tm_hour += x;
        break;
    case minute:
        tm->tm_min += x;
        break;
    case second:
        tm->tm_sec += x;
        break;
    }
    return mktime(tm);
}

const char *datetime_string(time_t t)
{
    static char str[32];
    struct tm *tm = localtime(&t);
    strftime(str, sizeof(str), "%F %T", tm);
    return str;
}

int main()
{
    time_t t = time(NULL);
    const char *s = datetime_string(t);
    printf("%s\n", s);
    t = time_add(t, 2, day);
    t = time_add(t, 1, hour);
    t = time_add(t, 10, minute);
    t = time_add(t, -1, year);
    s = datetime_string(t);
    printf("%s\n", s);
}
// output:
// 2018-12-09 16:18:51
// 2017-12-11 17:28:51

总结

三种时间表示形式

1. 日历时间(time_t)
2. 日期时间(struct tm),又叫Broken-Down Time
3. 字符串表示的日期时间

获取日历时间(time_t)的系统调用

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

从日历时间(time_t)到日期时间(struct tm)的转换

#include <time.h>
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);

从日期时间(struct tm)到日历时间(time_t)的转换

#include <time.h>
time_t mktime(struct tm *tm);

从日期时间(struct tm)到字符串表示的转换

#include <time.h>
size_t strftime(char *outstr, size_t max, const char *format, const struct tm *tm)

从字符串表示到日期时间(struct tm)

#include <time.h>
char *strptime(const char *s, const char *format, struct tm *tm);

其它无用的函数

#include <time.h>
char *ctime(const time_t *timep);   // calendar time
char *asctime(const struct tm *tm); // ascii time
time_t t = time(NULL);
const char *s1 = ctime(&t);
const char *s2 = asctime(localtime(&t));
printf("%s%s", s1, s2);
// output:
// Sun Dec  9 15:43:37 2018
// Sun Dec  9 15:43:37 2018

ctime(&t)与asctime(localtime(&t))等价,它们将日历时间转换为固定格式的时间字符串,因为格式固定,一般不满足我们的需求,所以基本没什么用

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值