Linux编程入门-时间

日历时间

时间分为真实时间和进程时间。真实时间分为日历时间和流逝(或挂钟)时间。日历时间的起点时某个标准点,这里是自Epoch以来的秒数。流逝时间的起点是进程生命周期内某个固定时点,如进程启动时。进程时间指一个进程使用的CPU时间总量。

gettimeofday/settimeofday/adjtime

gettimeofday获取日历时间。settimeofday立即修改系统时间。adjtime缓慢逐步调整系统时间,大约每2000秒变化1秒。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <sys/time.h>
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
int gettimeofday(
struct timeval *restrict tv,
struct timezone *_Nullable restrict tz //废弃 置NULL
);
int settimeofday(
const struct timeval *tv,
const struct timezone *_Nullable tz //废弃 置NULL
);
int adjtime(
const struct timeval *delta, //要调整的时间 正值拨快 负值减慢
struct timeval *olddelta //函数返回时还未调整的时间
);

time

获取Epoch以来秒数,与gettimeofday返回的tv_sec数值相同,还可将Epoch以来秒数置为tloc参数所指位置。

1
2
3
4
#include <time.h>
time_t time(
time_t *_Nullable tloc
);

时间转换

ctime/asctime

ctime将time_t转为可打印格式,返回字符串如“Wed Jun 8 14:22:34 2011\n\x00”,其中自动对本地时区和DST设置加以考虑。返回的字符串由静态分配,下一次调用会覆盖,称为非重入。asctime返回格式与ctime相同,但不考虑本地时区,一般调用前搭配localtimegmtime等。这两个函数的可重入版为ctime_rasctime_r

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char *ctime(
const time_t *clock
);
char *ctime_r(
const time_t *clock,
char *buf
);
char *asctime(
const struct tm *timeptr
);
char *asctime_r(
const struct tm *restrict tm,
char *restrict buf
);

gmtime/localtime/mktime

gmtime把time_t日历时间转为对应的UTC分解时间,localtime转为系统本地时间的分解时间。他们对应的可重入版为gmtime_rlocaltime_rmktime将本地时区分解时间转为time_t。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct tm {
int tm_sec; /* Seconds [0, 60] */
int tm_min; /* Minutes [0, 59] */
int tm_hour; /* Hour [0, 23] */
int tm_mday; /* Day of the month [1, 31] */
int tm_mon; /* Month [0, 11] (January = 0) */
int tm_year; /* Year minus 1900 */
int tm_wday; /* Day of the week [0, 6] (Sunday = 0) */
int tm_yday; /* Day of the year [0, 365] (Jan/01 = 0) */
int tm_isdst; /* Daylight savings flag */
long tm_gmtoff; /* Seconds East of UTC */
const char *tm_zone; /* Timezone abbreviation */
};
struct tm *gmtime(
const time_t *timer
);
struct tm *gmtime_r(
const time_t *restrict timer,
struct tm *restrict result
);
struct tm *localtime(
const time_t *timer
);
struct tm *localtime_r(
const time_t *restrict timer,
struct tm *restrict result
);
time_t mktime(
struct tm *timeptr
);

mktime忽略输入的tm_wday和tm_yday字段,超出数值范围的字段会自动更正。tm_isdst字段为0表示忽略夏令时,大于0夏令时生效,小于0自动判断。

strftime/strptime

strftime将分解时间转为打印格式,且提供生成字符串格式的控制。strptimestrftime的逆函数。

1
2
3
4
5
6
7
8
9
10
11
12
size_t strftime(
char *restrict s, //输出字符串 以null结尾 无换行符
size_t maxsize, //最大长度
const char *restrict format, //格式
const struct tm *restrict timeptr
); //超长返回0
#define _XOPEN_SOURCE
char *strptime(
const char *restrict s,
const char *restrict format,
struct tm *restrict tm
); //下一个未处理的字符的指针

时区

/usr/share/zoneinfo目录下每个文件包含一个地区的时区制度信息,如美国东部标准时间EST,欧洲中部时间CET,还可用子目录对某些时区进行分组。系统本地时间由时区文件/etc/localtime定义,链接到/usr/share/zoneinfo目录下的某个文件。

为某个程序指定时区时,可设置TZ环境变量,如:

1
2
3
TZ=":Pacific/Auckland"
TZ="CET-1:00:00CEST-2:00:00,M3.5.0,M10.5.0"
TZ=":Europe/Berlin"

地区

I18N术语意为国际化。地区信息在/usr/share/locale目录中,目录中每个子目录命名如下,language为双字母ISO语言代码,territory为双字母ISO国家代码,codest为字符编码集,modifier用于区分前几字段相同的情况。

1
language[_territory[.codeset]][@modifier]

每个子目录下还有些特殊文件,如:

文件名 用途
LC_CTYPE 字符分类与大小写转换
LC_COLLATE 字符集排序规则
LC_MONETARY 币值格式化规则
LC_NUMERIC 非币值数字的格式化规则
LC_TIME 日期时间格式化规则
LC_MESSAGE “是/否”的格式与数值规则

setlocale

设置或查询程序当前地区:

1
2
3
4
5
#include <locale.h>
char *setlocale(
int category, //要设置或查询地区的哪部分内容 值有上表文件名 LC_ALL为所有部分
const char *locale //空字符串表示获取
);

上表各值还可直接设置到环境变量中,环境变量还有LANG字段可设置,这几者之间有优先级顺序。

软件时钟

时间相关的各种系统调用的精度受限于系统软件时钟的分辨率,度量单位是jiffies。jiffies大小是定义在内核源代码的常量Hz,是内核按照round-robin分时调度算法分配CPU进程的单位。软件时钟频率目前可设为100Hz、250Hz、1000Hz,分别对应jiffy值为10、4、1,默认250Hz。每个时钟中断会消耗CPU时间,不能任意提高时钟频率。此外还可设为300Hz,可被PAL制式(25帧/秒)和NTSC制式(30帧/秒)的视频帧速率整除。

进程时间

进程时间是进程创建或使用的CPU时间数量,分为用户CPU时间和系统CPU时间。用户CPU时间(或虚拟时间)为用户模式下执行所花费的时间,系统CPU时间为内核模式中执行所花费的时间。进程时间统计可用命令行工具time。

times

检索进程时间信息。tms_utime和tms_stime分别是用户和系统CPU时间,tms_cutime和tms_cstime是父进程执行了wait的所有已终止的子进程使用的CPU时间。clock_t是用时钟计时单元为单位度量时间的整型值,可用sysconf的_SC_CLK_TCK获得每秒包含的时钟计时单元数。

1
2
3
4
5
6
7
8
9
struct tms {
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time of children */
clock_t tms_cstime; /* system time of children */
};
clock_t times(
struct tms *buf //返回
);

clock

获取进程时间,是用户和系统CPU时间的总和,单位是常量CLOCKS_PER_SEC。

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