linux clock_settime


原文链接: linux clock_settime
#include <stdio.h>
#include <time.h>

int main ()
{

// 获取时间戳
    time_t seconds = time(NULL); //The function time(NULL) returns the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds.
	sprintf(timestamp, "%-llu", (unsigned long long int)seconds);


   time_t start_t, end_t;
   double diff_t;

   printf("程序启动...\n");
   time(&start_t);

   printf("休眠 5 秒...\n");
   sleep(5);

   time(&end_t);
   diff_t = difftime(end_t, start_t);

   printf("执行时间 = %f\n", diff_t);
   printf("程序退出...\n");

   return(0);
}

方法一: long clock_t

#include
clock_t start = clock();
需要计时的代码段
clock_t end = clock();
运行时间t = end - start; (单位ms)

本方法有一定缺陷,在32bit机器上,运行时间较长达到(超过1小时),有可能出现计时错误。
clock()文档说明如下:
Note that the time can wrap around. On a 32-bit system where CLOCKS_PER_SEC equals 1000000 this function will return the same value approximately every 72 minutes.

因此,当出现计时为负数或者很小的数时,需要人为凭经验加上若干个72minutes。。。

方法二: timeval gettimeofday

显然方法一有一定局限性,方法二解决了长时间计时的问题。

#include <time.h>
timeval start, end; 
gettimeofday(&start, null);
...
gettimeofday(&end, null);

diffTime(start,end) * 0.001

struct timeval tv_begin;
struct timeval tv_end;
int passed_milliseconds;
gettimeofday (&tv_begin, NULL);
temp = quickSort (temp);
gettimeofday (&tv_end, NULL);
passed_milliseconds = (tv_end.tv_sec - tv_begin.tv_sec) * 1000 + (tv_end.tv_usec - tv_begin.tv_usec) / 1000;
    
printf("master_load_file %.3f s \n", diffTime(start,end) * 0.001 );

运行时间 t = 1000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)/1000; (单位ms)

时间函数介绍

Linux c/c++中提供了很多操作时间的库函数,这里简要介绍。

常用的时间函数包括以下:

  • time()

    • 原型:#include <time.h> time_t time(time_t *t);
    • 返回从公元1970-1-1 0:0:0的UTC时间到现在所经过的秒数
    • 如果t 并非空指针的话,此函数也会将返回值存到t指针所指的内存
    • 成功则返回秒数,失败则返回((time_t)-1)值,错误原因存于errno中
    • 用time()函数结合其他函数(如:localtime、gmtime、asctime、ctime)可以获得当前系统时间或是标准时间。
    • 如果需要更高的时间精确度,就需要struct timespec 和 struct timeval来处理:

  • localtime_r()

    • 原型:struct tm *localtime_r(const time_t * t);
    • 将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回
    • 成功则返回0,失败返回-1,错误代码存于errno
    • 结构tm的定义如下,此函数返回的时间日期已经转换成当地时区

    struct tm {
            int tm_sec;
            int tm_min;
            int tm_hour;
            int tm_mday;
            int tm_mon;
            int tm_year;
            int tm_wday;
            int tm_yday;
            int tm_isdst;
        };
    
    • gettimeofday
    • 原型:int gettimeofday ( struct timeval * tv , struct timezone * tz )
    • 把目前的时间由tv所指的结构返回,当地时区的信息则放到tz所指的结构中
    • timeval结构定义为:

    struct timeval {
        long tv_sec; /*秒*/
        long tv_usec; /*微秒*/
      };
    
    • timezone 结构定义为:

    struct timezone {
        int tz_minuteswest; /*和Greenwich 时间差了多少分钟*/
        int tz_dsttime; /*日光节约时间的状态*/
      };
    
    • clock_settime
    • 系统调用可以设置系统时间秒数与纳秒数。
    • 返回值。0成功,-1失败
      ```cpp
      #include
      int clock_settime(clockid_t clk_id, const struct timespec *tp);

    clockid_t clk_id 用于指定计时时钟的类型,有以下4种:

        CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户该成其他,则对应的时间相应改变  
        CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响  
        CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间  
        CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间  
    

    struct timespec *tp 用来存储当前的时间,其结构如下:

    struct timespec  
    {  
        time_t tv_sec; /* seconds */  
        long tv_nsec; /* nanoseconds */  
    };  
    

    ```

  • ctime

    • 原型:char *ctime(const time_t *timep);
    • 将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回
    • 此函数已经由时区转换成当地时间,字符串格式为Wed Jun 30 21 :49 :08 1993

  • asctime

    • 原型:char * asctime(const struct tm * timeptr);
    • 将参数timeptr所指的tm结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回
    • 此函数已经由时区转换成当地时间,字符串格式为: Wed Jun 30 21:49:08 1993\n
    • 若再调用相关的时间日期函数,此字符串可能会被破坏。此函数与ctime不同处在于传入的参数是不同的结构

  • gmtime

    • 原型:struct tm* gmtime(const time_t*timep);
    • 将参数timep 所指的time_t 结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回

  • settimeofday

    • 原型:int settimeofday ( const struct timeval *tv,const struct timezone *tz);
    • 把目前时间设成由tv所指的结构信息,当地时区信息则设成tz所指的结构
    • 注意,只有root权限才能使用此函数修改时间

更多详细信息请使用man手册。

struct tm ----> asctime() ----> string
time_t ----> ctime() ----> string

struct tm ---> strftime() ----> formatted string
time_t ----> gmtime() / localtime() ----> struct tm

获取精确到毫秒的时间


可以结合time, localtime, strftime得到本地时间,精确到秒。代码如下:

static string CurrentLocalTime(void)
{
    time_t t;  //秒时间
    tm *local; //本地时间
    char buf[128] = {0};

    t = time(NULL); //获取目前秒时间

    local = localtime(&t); //转为本地时间,注意,该函数非线程安全,下面的例子会使用线程安全函数localtime_r
    strftime(buf, 64, "%Y-%m-%d %H:%M:%S", local); //根据需要自定义格式

    return buf;
}

要想得到精确到毫秒的时间,就需要使用gettimeofday了。代码如下:

/**
 * @name: GetLocalTimeWithMs
 * @msg: 获取本地时间,精确到毫秒
 * @param {type} 
 * @return: string字符串,格式为YYYYMMDDHHMMSSsss,如:20190710130510368
 */
static string GetLocalTimeWithMs(void)
{
    string defaultTime = "19700101000000000";
    try
    {
        struct timeval curTime;
        gettimeofday(&curTime, NULL);
        int milli = curTime.tv_usec / 1000;

        char buffer[80] = {0};
        struct tm nowTime;
        localtime_r(&curTime.tv_sec, &nowTime);//把得到的值存入临时分配的内存中,线程安全
        strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", &nowTime);

        char currentTime[84] = {0};
        snprintf(currentTime, sizeof(currentTime), "%s%03d", buffer, milli);

        return currentTime;
    }
    catch(const std::exception& e)
    {
        return defaultTime;
    }
    catch (...)
    {
        return defaultTime;
    }
}

得到字符串表示的本地时间信息后,可根据需要对字符串进行操作,简单方便。

本地时间的获取在各种程序中使用率较高,可以放在项目的util中,供所有代码使用。

void test_clock_settime()
{
    int rc;
    struct timespec tp, request = { 1, 0 }, remain;

    rc = clock_gettime(CLOCK_REALTIME, &tp);
    assert(rc == 0);
    printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec);
    
    rc = clock_settime(CLOCK_MONOTONIC, &tp);
    assert(rc == -1 && (errno == EINVAL));
    
    rc = clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tp);
    assert(rc == -1 && (errno == EINVAL));
    
    rc = clock_settime(CLOCK_THREAD_CPUTIME_ID, &tp);
    assert(rc == -1 && (errno == EINVAL));
    
    rc = clock_settime(CLOCK_REALTIME, &tp);
    assert(rc == 0 || (errno == EPERM));

    rc = clock_gettime(CLOCK_REALTIME, &tp);
    assert(rc == 0);
    printf("[%10"PRId64".%09d] clock_gettime (CLOCK_REALTIME)\n", (__int64) tp.tv_sec, (int) tp.tv_nsec);
}
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <error.h>

int main()
{
        struct timespec tpset, tsreset;

        if (clock_gettime(CLOCK_REALTIME, &tsreset) != 0) {
                perror("clock_gettime() did not return success\n");
        }

        tpset.tv_sec = 0;
        tpset.tv_nsec = 0;

        clock_settime(CLOCK_REALTIME, &tpset);
        perror("clock_settime");
}

//  直接的结果会在调用clock_settime的时候提示非法参数,原因如下:
// clock_settime->kc->clock_set(which_clock, &new_tp)->posix_clock_realtime_set->do_sys_settimeofday->do_sys_settimeofday64->do_settimeofday64
int do_settimeofday64(const struct timespec64 *ts)
{
    struct timekeeper *tk = &tk_core.timekeeper;
    struct timespec64 ts_delta, xt;
    unsigned long flags;
    int ret = 0;

    if (!timespec64_valid_strict(ts))
        return -EINVAL;

    raw_spin_lock_irqsave(&timekeeper_lock, flags);
    write_seqcount_begin(&tk_core.seq);

    timekeeping_forward_now(tk);

    xt = tk_xtime(tk);
    ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
    ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
// 这里就换返回failed,从这里看到调用clock_settime 是设置和当前时间的差值,像上面的case,如果tpset.tv_sec = 0 和 tpset.tv_nsec = 0 都是零的话,这个差值会非常大,例如:clock_gettime(CLOCK_REALTIME, {1498723813, 202715700})
//因此在调用timespec64_compare时候就提示failed
    if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
        ret = -EINVAL;
        goto out;
    }
}
#define _XOPEN_SOURCE
#define _POSIX_C_SOURCE 199309L

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/rtc.h> 
#include <sys/ioctl.h>


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

/*
time_t : type long int ,用来存储从1970到现在过了多少秒;
更精确一点,可以使用 struct timeval
struct timeval{
long tv_sec;    //秒
long tv_usec;   //微秒
}
struct timeval有两个成员,一个是秒,一个是微秒, 所以最高精确度是微秒。
一般由函数int gettimeofday(struct timeval *tv, struct timezone *tz)获取系统的时间 
struct timespec {
time_t tv_sec; // seconds
long tv_nsec; // and nanoseconds
};
struct timespec有两个成员,一个是秒,一个是纳秒, 所以最高精确度是纳秒。
eg:
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC,&ts);
CLOCK_REALTIME 统当前时间,从1970年1.1日算起
CLOCK_MONOTONIC 系统的启动时间,不能被设置
CLOCK_PROCESS_CPUTIME_ID 本进程运行时间
CLOCK_THREAD_CPUTIME_ID 本线程运行时间
*/

/*
int clock_gettime(clockid_t clk_id, struct timespec *tp);
    Return 0 on success, or –1 on error
clock_gettime ——>struct timespec s ——> struct tm ——>format string
*/

void nowtime_ns()
{
    struct timespec ts;
    struct tm tm_time;
    time_t t;
     printf("---------------------------struct timespec---------------------------------------\n"); 
     printf("[time(NULL)]     :     %ld\n", time(NULL)); 
    if(clock_gettime(CLOCK_MONOTONIC,&ts)<0)
    {
        printf("clock_gettime failed \n");
        perror("clock_gettime");
        return;
    }
    printf("clock_gettime : tv_sec=%ld, tv_nsec=%ld\n", ts.tv_sec, ts.tv_nsec);
    localtime_r(&(ts.tv_sec),&tm_time);
    char date_time[50]={0};
    strftime(date_time,sizeof(date_time),"%Y-%m-%d %H:%M:%S",&tm_time);
    printf("clock_gettime : date_time=%s, tv_nsec=%ld\n", date_time, ts.tv_nsec);
}

/*
    gettimeofday ——>struct timeval s ——>struct tm ——>format string
    int gettimeofday(struct timeval *tv, struct timezone *tz);
    int settimeofday(const struct timeval *tv, const struct timezone *tz);
    gettimeofday() and settimeofday() return 0 for success, or -1 for failure (in which case errno is set appropriately).
*/

void nowtime_us()
{
    struct timeval tv;
    struct tm tm_time;
    printf("---------------------------struct timeval----------------------------------------\n"); 
    printf("[time(NULL)]     :     %ld\n", time(NULL)); 
    if(gettimeofday(&tv,NULL)<0)
    {
        perror("gettimeofday");
        return;
    }
    printf("gettimeofday: tv_sec=%ld, tv_usec=%ld\n", tv.tv_sec, tv.tv_usec);
    localtime_r(&(tv.tv_sec),&tm_time);
    char date_time[50]={0};
    strftime(date_time,sizeof(date_time),"%Y-%m-%d %H:%M:%S",&tm_time);
    printf("clock_gettime : date_time=%s, tv_usec=%ld\n", date_time, tv.tv_usec);
}


int main()
{
    nowtime_ns();
    printf("\n");
    nowtime_us();
    printf("\n");
    return 0;
}
`