Linux中的日历时间

  • time函数和gettimeofday系统调用

早期UNIX上是实现了time的系统调用的,在4.3BSD上补充了更为精确的gettimeofday系统调用(虽然这个函数名字感觉很奇怪),但是这个调用可以提供微秒级别的精度。所以将time作为系统调用就显得有点多余,目前的做法是将time封装到C语言的time.h中,实现为一个调用了gettimeofday的库函数。

测试代码如下:

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

#include <time.h>

int main()
{
    time_t tt;
    struct timeval tv;
    

    printf("Time Ret: %ld\n",time(NULL));
    printf("Time Ret: %ld\n",time(&tt));
    printf("Time Arg: %ld\n",tt);

    int ret=gettimeofday(&tv,NULL);
    printf("tv.tv_sec: %ld\n",tv.tv_sec);
    printf("tv.tv_usec: %ld\n",tv.tv_usec);
    return 0;
}

运行效果见下图:

 

 这里要说明几个注意点:

1. time函数,返回自Epoch以来的秒数,这是肯定的,同时可以接受一个time_t*类型的指针作为形参,执行该函数将会把这个秒数放入到指针所指向的位置 ,如果为NULL当然不用管了;

2. time函数和gettimeofday系统调用返回的结果是相同的,都是秒数,但是后者还可以返回微秒数,这两个值都是通过结构体timeval传递出来的,该结构体定义如下:

/* A time value that is accurate to the nearest
   microsecond but also has a range of years.  */
struct timeval
{
  __time_t tv_sec;        /* Seconds.  */
  __suseconds_t tv_usec;    /* Microseconds.  */
};

3. 有gettimeofday,同样也有对应的settimeofday函数。

有时候我们需要打印程序运行的时间,可以简单写一个函数:

void print_now()
{
    struct timeval tv;
    int ret=gettimeofday(&tv,NULL);
    printf("[%ld.%ld]\t",tv.tv_sec,tv.tv_usec);
}
  • 时间转换

有几种时间转换函数,最简单的是ctime函数,直接给返回一个长达26字节的字符串,包含了标准格式的日期和时间,测试代码如下:

int main()
{
    time_t tt;   
    tt=time(NULL);
    printf("%s\n",ctime(&tt));
    return 0;
}

运行效果如下,下方是作为对比的date命令。

 

  • 时间的分解和合成

有时候我们并不需要这么多的时间信息,例如我只想检查一下现在时间是否介于晚上7点到早上6点之间,然后决定是否打开路灯这样的工作,显然这个就需要提取时间中的各个不同要素。

首先是结构体tm(感觉早期写程序语言的人起名字好随意啊~):

/* ISO C `broken-down time' structure.  */
struct tm
{
  int tm_sec;            /* Seconds.    [0-60] (1 leap second) */
  int tm_min;            /* Minutes.    [0-59] */
  int tm_hour;            /* Hours.    [0-23] */
  int tm_mday;            /* Day.        [1-31] */
  int tm_mon;            /* Month.    [0-11] */
  int tm_year;            /* Year    - 1900.  */
  int tm_wday;            /* Day of week.    [0-6] */
  int tm_yday;            /* Days in year.[0-365]    */
  int tm_isdst;            /* DST.        [-1/0/1]*/

# ifdef    __USE_MISC
  long int tm_gmtoff;        /* Seconds east of UTC.  */
  const char *tm_zone;        /* Timezone abbreviation.  */
# else
  long int __tm_gmtoff;        /* Seconds east of UTC.  */
  const char *__tm_zone;    /* Timezone abbreviation.  */
# endif
};

可以看到这个结构体中包含了最基本的年月日、时分秒、星期,还有DST(夏令时)等,另外还受到宏的影响,可能有其他的一些信息。更有意思的是,秒并不是从0~59,而是从0~60,这是为了考虑闰秒的问题。另外,年并不是直接是年,而是有个1900的偏移量,所以如果今年是2022年的话,这个字段得到的结果是122。

测试代码如下:

int main()
{
    time_t tt;   
    struct tm* ptm;
    tt=time(NULL);
    printf("%s",ctime(&tt));
    ptm=gmtime(&tt);
    printf("Hour: %d\n",ptm->tm_hour);
    return 0;
}

运行效果如下:

 

 等等,怎么上面显示的是23点,下面居然是7点?

这个地方存在GMT和LocalTime的问题。首先我们是东八区,比GMT快了8小时,所以时间上是23(周五晚上)+8=7(周六上午)。

GMT可以作为基准,这是很不错的,但是通常大家都是使用的本地时间,这个还有一个和gmtime类似的函数:localtime,把上面的测试代码中gmtime函数名改为localtime就可以得到23了。

在介绍完了tm结构体以后,再引入另一个时间格式化函数asctime,这个函数接收一个tm的结构体,然后输出时间格式的字符串,与ctime类似,但是与ctime函数不同的是,它不会受到本地时间的影响。

事实上,ctime函数的原型是这么注释的:

/* Equivalent to `asctime (localtime (timer))'.  */
extern char *ctime (const time_t *__timer) ;

可见时间上是将GMT时间转化为了本地时间以后输出。

时间的合成是时间的分解的逆向操作,所使用的函数是mktime,可以猜到,这个函数的参数是一个tm的结构体(或指针),返回值是time_t类型,函数原型如下:

/* Return the `time_t' representation of TP and normalize TP.  */
extern time_t mktime (struct tm *__tp) ;

 

posted @ 2022-02-19 16:11  castor_xu  阅读(195)  评论(0编辑  收藏  举报