Time, Clock Programming in C

Table of Contents

time functions in the Unix-like systems1

int adjtimex(struct timex *);
int adjtime(const struct timeval *, struct timeval *);
unsigned int alarm(unsigned int);
char *asctime(const struct tm *);
char *asctime_r(const struct tm *, char *);
clock_t clock(void);
int clock_getres(clockid_t, struct timespec *);
int clock_gettime(clockid_t, struct timespec *);
int clock_settime(clockid_t, const struct timespec *);
char *ctime(const time_t *);
char *ctime_r(const time_t *, char *);
int ftime(struct timeb *tp);
double difftime(time_t, time_t);
struct tm *getdate(const char *);
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct tm *gmtime(const time_t *);
struct tm *gmtime_r(const time_t *, struct tm *);
struct tm *localtime(const time_t *);
struct tm *localtime_r(const time_t *, struct tm *);
time_t mktime(struct tm *);
int nanosleep(const struct timespec *, struct timespec *);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
unsigned int sleep(unsigned int);
size_t strftime(char *, size_t, const char *, const struct tm *);
char *strptime(const char *, const char *, struct tm *);
time_t time(time_t *);
time_t timegm(struct tm *tm);
time_t timelocal(struct tm *tm);
int timer_create(clockid_t, struct sigevent *, timer_t *);
int timer_delete(timer_t);
int timer_gettime(timer_t, struct itimerspec *);
int timer_getoverrun(timer_t);
int timer_settime(timer_t, int, const struct itimerspec *, struct itimerspec *);
void tzset(void);
useconds_t ualarm(useconds_t, useconds_t);
int usleep(useconds_t);

Unix time and UTC/GMT/Zulu

  • UNIX时间: 从协调世界时1970年1月1日0时0分0秒起至现在的总秒数,不考虑闰秒.2
  • 世界标准时间(UTC)(从英文“Coordinated Universal Time”/法文“Temps Universel Cordonné”而来),以原子时秒长为基础.
  • 格林威治标准时间(GMT,Greenwich Mean Time) 是指位于英国伦敦郊区的皇家格林威治天文台的标准时间,因为本初子午线被定义在通过那里的经线。
  • Zulu: 在军事中,协调世界时区会使用“Z”来表示。而在航空上,所有使用的时间划一规定是协调世界时。而且Z在无线电中应读作“Zulu”. 协调世界时也会被称为“Zulu time”。

Data Structures in Unix

timeval , timespecitimerspec

从1/1/1970到现在的秒和微微秒数

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

POSIX time functions使用这个:

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

interval timers:

struct itimerspec
{
    struct timespec it_interval;
    struct timespec it_value;
};

example:

timeval tim;
gettimeofday(&tim, NULL);

epoch time

旧的系统 time_t 是32位的有符号数,将在 2038-01-19T03:14:07Z 之后回转到0.现在Unix系统使用64位有符号数表示它.

calendar time

struct tm
{
  int    tm_sec;   /* seconds [0,60] (60 for + leap second) */
  int    tm_min;   /* minutes [0,59] */
  int    tm_hour;  /* hour [0,23] */
  int    tm_mday;  /* day of month [1,31] */
  int    tm_mon ;  /* month of year [0,11] */
  int    tm_year;  /* years since 1900 */
  int    tm_wday;  /* day of week [0,6] (Sunday = 0) */
  int    tm_yday;  /* day of year [0,365] */
  int    tm_isdst; /* daylight saving flag */
};
  • tm_isdst is easily misinterpreted as a flag when it’s actually three-valued: 0 = DST off, 1 = DST on, -1 = DST status unknown. (Actually, values < -1 are treated as -1 and values > 1 treated as 1.)
  • The tm_year base value of 1900 rather than zero - easily forgotten and confusing, especially when interpreting negative values. Also, int is too short for this type if sizeof(int) < sizeof(time_t), creating potential overflow issues.
  • Inconsistency about 0- vs. 1-origin in month and day numbers.
  • No timezone offset

Delay and interval-timing functions

sleep(3), usleep(3), and nanosleep(3)

#include <unistd.h>

unsigned int sleep(unsigned int seconds);
int usleep(useconds_t usec);

#include <time.h>

int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

alarm(2|3), ualarm(3), getitimer(2|3), and setitimer(2|3)

#include <unistd.h>

unsigned alarm(unsigned seconds);
useconds_t ualarm(useconds_t usecs, useconds_t interval);

#include <sys/time.h>

int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *restrict value,
              struct itimerval *restrict ovalue);

Clock and time-of-day functions

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

#include <time.h>
double difftime(time_t time1, time_t time0);

#include <time.h>
clock_t clock(void);

#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
int settimeofday(const struct timeval *tv, const struct timezone *tz);

#include <time.h>
int clock_getres(clockid_t clk_id, struct timespec *res);
int clock_gettime(clockid_t clk_id, struct timespec *tp);
int clock_settime(clockid_t clk_id, const struct timespec *tp);

Date and timezone-aware functions

Date formats in the Unix systems:

1414092747                       Unix UTC seconds
Fri Oct 24 15:32:27 EDT 2014     date(1) output
2014-10-24 15:32:27-0400         date(1) output with -rfc-3339 option
Fri, 24 Oct 2014 15:32:27 -0400   e-mail RFC-822/RFC-2822 format
Fri, 24 Oct 2014 19:32:27 GMT     HTTP (RFC-2616/RFC-7231) format
20141024152327.000000Z            LDAP (RFC-2252/X.680/X.208) format
2014-10-24 15:32:27              Modified ISO-8601 local time
2014-10-24T15:32:27              Strict ISO-8601 local time
2014-10-24T19:32:27Z              RFC-3339 time, always UTC and marked Z

tzset(3) and ftime(3)

#include <time.h>

void tzset (void);

extern char *tzname[2]; /* time zone name */
extern long timezone;   /* seconds west of UTC, *not* DST-corrected */
extern int daylight;    /* nonzero if DST is ever in effect here */

gmtime(3) and localtime(3)

#include <time.h>

struct tm *gmtime(const time_t *);
struct tm *gmtime_r(const time_t *, struct tm *);
struct tm *localtime(const time_t *);
struct tm *localtime_r(const time_t *, struct tm *);

mktime(3), timelocal(3), timegm(3)

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

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

strftime

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

/* RFC-3339 format */
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", gmtime(t));

/* ISO-8601 local time */
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", localtime(t));

/* RFC-822/RFC-2822 format */
strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", localtime(t));

strptime(3) and getdate(3)

#include <time.h>

char *strptime(const char *, const char *, struct tm *);
struct tm *getdate(const char *);
int getdate_r(const char *string, struct tm *res);

Convert from struct timeval

  • to local time
    struct tm* out;
    localtime_r(&t_.tv_sec, out);
    
  • to universal time
    struct tm* out;
    gmtime_r(&t_.tv_sec, out);
    
  • to epoch time
    return t_.tv_sec;
    

Good programming practice

convert dates to Unix UTC on input, do all your calculations in that, and convert back to localtime as lare as possible.

Footnotes:

Author: Shi Shougang

Created: 2015-04-01 Wed 20:11

Emacs 24.3.1 (Org mode 8.2.10)

Validate