文章目录

  • 1. 前言
  • 2. 日期和时间
    • 2.1. 时间基础
    • 2.2. 时间类型
    • 2.3. 计算经过时间
    • 2.4. 处理器和 CPU 时间
      • 2.4.1. CPU时间查询
      • 2.4.2. 处理器时间查询
    • 2.5. 日历时间
      • 2.5.1. 获得时间
      • 2.5.2. 设置和调整时间
      • 2.5.3. 故障时间
      • 2.5.4. 格式化日历时间
      • 2.5.5. 将文本时间和日期信息转换回来
        • 2.5.5.1. 根据给定格式解释字符串
        • 2.5.5.2. 一种更加用户友好的时间和日期解析方式
      • 2.5.6. 用 TZ 指定时区
      • 2.5.7. 时区的函数和变量
      • 2.5.8. 时间函数示例
    • 2.6. 设置警报
    • 2.7. 睡眠
  • 3. 参考

1. 前言

The GNU C Library Reference Manual for version 2.35

2. 日期和时间

Date and Time

本章介绍了用于操作日期和时间的函数,包括用于确定现在是什么时间以及在不同时间表示之间进行转换的函数。

2.1. 时间基础

在技​​术手册中讨论时间可能很困难,因为英语中的“时间”一词指的是很多不同的东西。在本手册中,为了避免混淆,我们使用了严格的术语,而我们唯一使用简单的“时间”一词是为了谈论抽象的概念。

日历时间是时间连续体中的一个点,例如 1990 年 11 月 4 日 18:02.5 UTC。有时这被称为“绝对时间”。

我们不说“日期”,因为这是日历时间所固有的。

间隔是两个日历时间之间连续的时间部分,例如 1980 年 7 月 4 日 9:00 到 10:00 之间的小时。

经过时间是间隔的长度,例如 35 分钟。人们有时会草率地使用“间隔”一词来指代某个间隔的经过时间。

时间量是经过时间的总和,不需要具有任何特定间隔。例如,阅读一本书所花费的时间可能是 9 个小时,这与阅读它的时间和次数无关。

周期是两个事件之间的间隔时间,特别是当它们是一系列有规律重复的事件的一部分时。

一个简单的日历时间是一个日历时间,它表示为自称为纪元的固定的、特定于实现的日历时间以来经过的时间。这种表示便于对日历时间进行计算,例如查找两个日历时间之间的经过时间。简单的日历时间与时区无关;无论计算机在地球上的哪个位置,它们都代表同一时刻。

POSIX 表示简单日历时间不包括闰秒,但一些(否则符合 POSIX 标准的)系统可以配置为在简单日历时间中包括闰秒。

细分时间是由其在公历中的组成部分表示的日历时间:年、月、日、小时、分钟和秒。细分的时间值是相对于特定时区的,因此有时也称为本地时间。分解时间对于输入和输出最有用,因为它们更容易让人理解,但更难计算。

CPU 时间衡量单个进程主动使用 CPU 执行计算的时间量。它不包括进程等待外部事件所花费的时间。系统分别跟踪每个进程使用的 CPU 时间。

处理器时间衡量任何 CPU 已被任何进程使用的时间量。它是一种基本的系统资源,因为在任何给定的时间间隔内可以存在多少资源是有限制的(时间间隔的经过时间乘以计算机中的 CPU 数量)

人们经常将此称为 CPU 时间,但我们在本手册中将后一个术语保留为上述定义。

2.2. 时间类型

Time Types

ISO C 和 POSIX 定义了几种数据类型来表示经过时间、简单日历时间和细分时间。

数据类型:clock_t

clock_t 用于测量处理器和 CPU 时间。它可以是整数或浮点类型。它的值是自过去某个任意事件以来的时钟滴答计数。每秒时钟滴答数是系统特定的。有关更多详细信息,请参阅处理器和 CPU 时间。

数据类型:time_t

time_t 是用于表示简单日历时间的最简单的数据类型。

在 ISO C 中,time_t 可以是整数或浮点类型,time_t 值的含义没有指定。一个严格遵守的程序可以对 time_t 值做的唯一事情是:将它们传递给 difftime 以获取两个简单日历时间之间的经过时间(请参阅计算经过时间),并将它们传递给将它们转换为分解时间的函数(见故障时间)。

在符合 POSIX 的系统上,time_t 是一个整数类型,它的值表示自 1970 年 1 月 1 日协调世界时的 00:00:00 纪元以来经过的秒数。

GNU C 库还保证 time_t 是有符号类型,并且它的所有函数都可以在负 time_t 值上正确运行,这些值被解释为纪元之前的时间。

数据类型:struct timespec

struct timespec 表示一个简单的日历时间,或经过的时间,具有亚秒级分辨率。它在 time.h 中声明并具有以下成员:

time_t tv_sec

自纪元(对于简单的日历时间)或自某个其他起点(对于经过的时间)以来经过的整秒数。

long int tv_nsec

自 tv_sec 成员给出的时间以来经过的纳秒数。

当 GNU C 库函数生成 struct timespec 值时,此字段中的值将始终大于或等于 0,并且小于 1,000,000,000。当 struct timespec 值提供给 GNU C 库函数时,此字段中的值必须在同一范围内。

数据类型:struct timeval

struct timeval 是一种较旧的类型,用于表示简单的日历时间或经过的时间,具有亚秒级分辨率。它与 struct timespec 几乎相同,但仅提供微秒分辨率。它在 sys/time.h 中声明并具有以下成员:

time_t tv_sec

自纪元(对于简单的日历时间)或自某个其他起点(对于经过的时间)以来经过的整秒数。

long int tv_usec

自 tv_sec 成员给出的时间以来经过的微秒数。

当 GNU C 库函数生成 struct timeval 值时,此字段中的值将始终大于或等于 0,并且小于 1,000,000。当 struct timeval 值提供给 GNU C 库函数时,此字段中的值必须在同一范围内。

数据类型:struct tm

这是用于表示细分时间的数据类型。它具有年、月、日等单独的字段。有关详细信息,请参阅故障时间。

2.3. 计算经过时间

Calculating Elapsed Time

通常,人们希望将经过时间计算为两个简单日历时间之间的差。GNU C 库为此目的只提供了一个函数。

函数:double difftime (time_t end, time_t begin)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

difftime 函数返回从日历时间开始到日历时间结束所经过的秒数,作为 double 类型的值。

在符合 POSIX 的系统上,使用“difftime (end, begin)”而不是“end - begin”的优势在于,即使 end 和 begin 相距太远,简单的减法就会溢出,它也会产生数学上正确的结果。但是,如果它们相距太远以至于双精度不能准确表示差异,则结果将不准确。

在其他系统上,time_t 值的编码方式可能会阻止减法直接起作用,然后 difftime 将是计算它们差异的唯一方法。

GNU C 库不提供任何函数来计算 struct timeval 或 struct timespec 类型的两个值之间的差异。这是手动进行此计算的推荐方法。它甚至可以在 tv_sec 成员具有无符号类型的某些特殊操作系统上工作。

/* Subtract the ‘struct timeval’ values X and Y,storing the result in RESULT.Return 1 if the difference is negative, otherwise 0. */int
timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
{/* Perform the carry for the later subtraction by updating y. */if (x->tv_usec < y->tv_usec) {int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;y->tv_usec -= 1000000 * nsec;y->tv_sec += nsec;}if (x->tv_usec - y->tv_usec > 1000000) {int nsec = (x->tv_usec - y->tv_usec) / 1000000;y->tv_usec += 1000000 * nsec;y->tv_sec -= nsec;}/* Compute the time remaining to wait.tv_usec is certainly positive. */result->tv_sec = x->tv_sec - y->tv_sec;result->tv_usec = x->tv_usec - y->tv_usec;/* Return 1 if result is negative. */return x->tv_sec < y->tv_sec;
}

2.4. 处理器和 CPU 时间

Processor And CPU Time

如果您正在尝试优化程序或衡量其效率,了解它使用了多少处理器时间非常有用。为此,日历时间和经过的时间是无用的,因为一个进程可能会花时间等待 I/O 或其他进程使用 CPU。但是,您可以使用本节中的函数获取信息。

CPU 时间(请参阅时间基础知识)由数据类型 clock_t 表示,它是时钟滴答数。它给出了自某个任意事件以来进程主动使用 CPU 的总时间。在 GNU 系统上,该事件是进程的创建。虽然通常是任意的,但对于任何特定进程,事件始终是相同的事件,因此您始终可以通过检查计算前后进程的 CPU 时间来测量特定计算在 CPU 上花费的时间。

在 GNU/Linux 和 GNU/Hurd 系统上,clock_t 等价于 long int,而 CLOCKS_PER_SEC 是一个整数值。但在其他系统中,clock_t 和宏 CLOCKS_PER_SEC 都可以是整数或浮点类型。如上例所示,将 CPU 时间值转换为双倍可确保算术和打印等操作正确且一致地工作,无论底层表示是什么。

请注意,时钟可以环绕。在 CLOCKS_PER_SEC 设置为一百万的 32 位系统上,此函数将大约每 72 分钟返回相同的值。

有关检查进程对处理器时间的使用并对其进行控制的其他功能,请参阅资源使用和限制。

2.4.1. CPU时间查询

CPU Time Inquiry

要获取进程的 CPU 时间,可以使用时钟功能。该工具在头文件 time.h 中声明。

在典型用法中,您在要计时的间隔的开始和结束时调用时钟函数,减去这些值,然后除以 CLOCKS_PER_SEC(每秒时钟滴答数)以获得处理器时间,如下所示:

#include <time.h>clock_t start, end;
double cpu_time_used;start = clock();
… /* Do the work. */
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;

不要使用单个 CPU 时间作为时间量;它不是那样工作的。如上所示进行减法或直接查询处理器时间。请参阅处理器时间查询。

不同的计算机和操作系统在跟踪 CPU 时间的方式上差异很大。内部处理器时钟的分辨率通常在百分之一到百万分之一秒之间。

宏:int CLOCKS_PER_SEC

该宏的值是时钟函数测量的每秒时钟滴答数。POSIX 要求这个值是一百万,与实际分辨率无关。

函数:clock_t clock (void)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

该函数返回调用进程的当前 CPU 时间。如果 CPU 时间不可用或无法表示,则时钟返回值 (clock_t)(-1)。

2.4.2. 处理器时间查询

Processor Time Inquiry

除了进程的 CPU 时间之外,times 函数还返回有关进程在 struct tms 对象中消耗的处理器时间的信息。请参阅时间基础。您应该包含头文件 sys/times.h 以使用此工具。

数据类型:struct tms

tms 结构用于返回有关处理时间的信息。它至少包含以下成员:

clock_t tms_utime

这是调用进程在执行其程序指令时使用的总处理器时间。

clock_t tms_stime

这是系统代表调用进程使用的处理器时间。

clock_t tms_cutime

这是调用进程的所有已终止子进程的tms_utime值和tms_cutime值之和,其状态已通过wait或waitpid报告给父进程;请参阅流程完成。换句话说,它表示执行调用进程的所有已终止子进程的指令所用的总处理器时间,不包括尚未被wait或waitpid报告的子进程。

clock_t tms_cstime

这类似于 tms_cutime,但代表系统已代表调用进程的所有已终止子进程使用的总处理器时间。

所有时间都以时钟滴答数给出。与 CPU 时间不同,这些是实际的时间量;与任何事件无关。请参阅创建流程。

宏:int CLK_TCK

这是每秒时钟滴答数的过时名称。请改用 sysconf (_SC_CLK_TCK)。

函数:clock_t times (struct tms *buffer)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

times 函数将调用进程的处理器时间信息存储在缓冲区中。

返回值是自过去任意点以来的时钟滴答数,例如自系统启动以来。times 返回 (clock_t)(-1) 表示失败。

可移植性说明:CPU 时间查询中描述的时钟功能由 ISO C 标准指定。时间函数是 POSIX.1 的一个特性。在 GNU 系统上,CPU 时间被定义为等于时间返回的 tms_utime 和 tms_stime 字段的总和。

2.5. 日历时间

Calendar Time

本节介绍获取、设置和操作日历时间的功能。

2.5.1. 获得时间

Getting the Time

GNU C 库提供了多种获取当前日历时间的函数,具有不同级别的分辨率。

函数:time_t time (time_t *result)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

这是获取当前日历时间的最简单功能。它将日历时间作为 time_t 类型的值返回;在 POSIX 系统上,这意味着它的分辨率为一秒。当时钟可用时,它使用与“clock_gettime (CLOCK_REALTIME_COARSE)”相同的时钟,否则使用与“clock_gettime (CLOCK_REALTIME)”相同的时钟。

如果参数 result 不是空指针,则日历时间值也存储在 *result 中。

此功能不能失败。

有些应用程序需要比单独使用 time_t 更精确的计时。一些应用程序还需要对“当前时间”的含义进行更多控制。对于这些应用程序,POSIX 提供了一个函数clock_gettime,它可以从各种不同的时钟中以高达纳秒的精度检索时间。时钟可以是系统范围的,所有进程的时间测量相同;或者它们可以是每个进程或每个线程,测量特定进程或其他类似资源消耗的 CPU 时间。每个时钟都有自己的分辨率和历元。您可以使用函数clock_getres 找到时钟的分辨率。没有获取时钟历元的功能;它要么是固定的并记录在案,要么时钟不用于测量绝对时间。

数据类型:clockid_t

clockid_t 类型用于指示希望使用几个系统时钟中的哪一个的常量。

所有支持这一系列函数的系统都将至少定义这个时钟常数:

宏:clockid_t CLOCK_REALTIME

该时钟使用 POSIX 纪元,即 1970 年 1 月 1 日 00:00:00,协调世界时。它与时间(上)和 gettimeofday(下)的时钟接近,但不一定同步。

第二个时钟常数不是通用的,但仍然很常见,用于测量单调时间的时钟。单调时间对于测量经过的时间很有用,因为它保证这些测量不受系统时钟更改的影响。

宏:clockid_t CLOCK_MONOTONIC

系统范围的时钟,持续测量日历时间的提前,忽略系统绝对日历时间设置的不连续变化。

这个时钟的时代是过去的一个未指定的时间点。如果系统重新启动或挂起,epoch 可能会发生变化。因此,CLOCK_MONOTONIC 不能用于测量绝对时间,只能用于测量经过的时间。

系统可能支持的不仅仅是这两个时钟。

函数:int clock_gettime (clockid_t clock, struct timespec *ts)

根据clock标识的时钟获取当前时间,以秒和纳秒的形式存储在*ts中。有关 struct timespec 的描述,请参阅时间类型。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EINVAL

不支持clock标识的时钟。

clock_gettime 将时间报告为秒和纳秒,但每个时钟的实际分辨率可能不如一纳秒,并且可能不会对所有时钟都相同。POSIX 还提供了一个函数来找出时钟的实际分辨率:

函数:int clock_getres (clockid_t clock, struct timespec *res)

获取clock标识的时钟的实际分辨率,存储在*ts中。

例如,如果 CLOCK_REALTIME 的时钟硬件使用以 32.768 kHz 振荡的石英晶体,则其分辨率将为 30.518 微秒,并且“clock_getres (CLOCK_REALTIME, &r)”会将 r.tv_sec 设置为 0,将 r.tv_nsec 设置为 30518。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EINVAL

不支持clock标识的时钟。

这些函数以及标识特定时钟的常量在 time.h 中声明。

可移植性注意:在某些系统上,包括使用旧版本 GNU C 库的系统,使用 clock_gettime 或 clock_setres 的程序必须与 -lrt 库链接。从 2.17 版开始,GNU C 库就不需要这样做了。

GNU C 库还提供了一个较旧但仍被广泛使用的函数,用于以微秒为分辨率获取当前时间。该函数在 sys/time.h 中声明。

函数:int gettimeofday (struct timeval *tp, void *tzp)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

获取当前日历时间,将其以秒和微秒的形式存储在 *tp 中。有关 struct timeval 的描述,请参阅时间类型。gettimeofday 的时钟接近但不一定与时间时钟和“clock_gettime (CLOCK_REALTIME)”时钟同步(见上文)。

在某些历史系统上,如果 tzp 不是空指针,则有关系统范围的时区的信息将被写入 *tzp。此功能已过时且不受 GNU 系统支持。您应该始终为此参数提供一个空指针。相反,使用时区的函数和变量和分解时间中描述的工具来处理时区。

此函数不能失败,其返回值始终为 0。

可移植性说明:在 POSIX 的 2008 年修订版中,此功能被认为已过时。GNU C 库将继续无限期地提供此功能,但新程序应改为使用 clock_gettime。

2.5.2. 设置和调整时间

Setting and Adjusting the Time

现代计算机内部的时钟硬件非常可靠,但它仍然可能是错误的。此部分的功能允许您设置系统对当前日历时间的想法,并调整系统以秒计的速率,从而使日历时间既准确又保持准确。

本节中的功能需要特殊权限才能使用。请参阅用户和组。

函数:int clock_settime (clockid_t clock, const struct timespec *ts)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

根据clock标识的时钟,将当前日历时间更改为*ts中的简单日历时间。

并非所有系统时钟都可以更改。例如,可以更改 CLOCK_REALTIME 时钟(使用适当的权限),但不能更改 CLOCK_MONOTONIC 时钟。

因为简单的日历时间与时区无关,所以当时区发生变化时(例如,如果计算机从一个区域移动到另一个区域),则不应使用此功能。相反,请使用时区的函数和变量中描述的工具。

clock_settime 导致时钟向前或向后跳跃,这可能会导致各种问题。使用 clock_settime 更改 CLOCK_REALTIME 时钟不会影响计时器何时到期(请参阅设置警报)或睡眠进程何时唤醒(请参阅睡眠),从而避免了一些问题。尽管如此,对于在系统运行时进行的小改动,最好使用 ntp_adjtime(如下)从一个时间平滑过渡到另一个时间。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EINVAL

不支持或根本无法设置clock标识的时钟,或者*ts中的简单日历时间无效(例如ts->tv_nsec为负数或大于999,999,999)。

EPERM

该进程没有设置由clock标识的时钟所需的权限。

可移植性注意:在某些系统上,包括使用旧版本 GNU C 库的系统,使用 clock_settime 的程序必须与 -lrt 库链接。从 2.17 版开始,GNU C 库就不需要这样做了。

对于长时间保持正常运行的系统,只设置一次时间是不够的;人们还应该规范时钟,使其不会偏离真正的日历时间。

ntp_gettime 和 ntp_adjtime 函数提供了一个接口来监视和规范系统时钟。例如,您可以通过暂时加快或减慢时钟来微调时钟“滴答”的速度,并对当前报告的日历时间进行平滑的小调整。

这些函数的名称以“ntp_”开头,因为它们是为实现网络时间协议的程序设计的,用于将系统时钟与其他系统时钟和/或外部高精度时钟硬件同步。

这些函数,以及它们使用的常量和结构,在 sys/timex.h 中声明。

数据类型:struct ntptimeval

此结构用于报告有关系统时钟的信息。它包含以下成员:

struct timeval time

当前日历时间,就像通过 gettimeofday 检索的一样。struct timeval 数据类型在时间类型中描述。

long int maxerror

这是最大误差,以微秒为单位。除非通过 ntp_adjtime 定期更新,否则此值将达到某个特定于平台的最大值。

long int esterror

这是估计的误差,以微秒为单位。该值可以由 ntp_adjtime 设置,以指示系统时钟与真实日历时间的估计偏移量。

函数:int ntp_gettime (struct ntptimeval *tptr)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

ntp_gettime 函数将 tptr 指向的结构设置为当前值。之后结构的元素包含内核中的计时器实现所假定的值。它们可能正确也可能不正确。如果不是,则需要调用 ntp_adjtime。

成功时返回值为 0,失败时返回其他值。为此函数定义了以下 errno 错误条件:

TIME_ERROR

精密时钟模型目前没有正确设置,因此时钟必须被认为是不同步的,并且应该小心处理这些值。

数据类型:struct timex

该结构用于控制和监视系统时钟。它包含以下成员:

unsigned int modes

此变量控制是否设置以及设置哪些值。几个符号常量必须与二进制组合或指定有效模式。这些常量以 MOD_ 开头。

long int offset

该值表示系统时钟与真实日历时间的当前偏移量。该值以微秒为单位。如果在模式中设置了位 MOD_OFFSET,则可以设置偏移量(以及可能的其他相关值)。偏移量的绝对值不得超过 MAXPHASE。

long int frequency

该值表示真实日历时间和系统时钟之间的频率差异。该值表示为按比例缩放的 PPM(百万分之几,0.0001%)。缩放比例为 1 << SHIFT_USEC。该值可以通过位 MOD_FREQUENCY 设置,但绝对值不得超过 MAXFREQ。

long int maxerror

这是最大误差,以微秒为单位。可以使用位 MOD_MAXERROR 设置新值。除非通过 ntp_adjtime 定期更新,否则此值将稳步增加并达到某个特定于平台的最大值。

long int esterror

这是估计的误差,以微秒为单位。该值可以使用位 MOD_ESTERROR 设置。

int status

这个变量反映了时钟机器的各种状态。有效位有符号常量,以 STA_ 开头。其中一些标志可以使用 MOD_STATUS 位更新。

long int constant

该值表示内核中实现的 PLL(锁相环)的带宽或刚度。可以使用位 MOD_TIMECONST 更改该值。

long int precision

该值表示读取系统时钟时的精度或最大误差。该值以微秒为单位。

long int tolerance

该值表示系统时钟的最大频率误差,以 PPM 为单位。此值用于每秒增加 maxerror。

struct timeval time

当前日历时间。

long int tick

时钟滴答之间经过的时间(以微秒为单位)。时钟滴答是系统时钟所基于的周期性定时器中断。

long int ppsfreq

这是几个可选变量中的第一个,仅当系统时钟可以使用 PPS(每秒脉冲)信号来控制系统时钟时才会出现。该值以按比例缩放的 PPM 表示,它表示系统时钟和 PPS 信号之间的频率差。

long int jitter

该值表示 PPS 信号分散的中值滤波平均值(以微秒为单位)。

int shift

该值是 PPS 校准间隔持续时间的二进制指数,范围从 PPS_SHIFT 到 PPS_SHIFTMAX。

long int stabil

该值表示 PPS 频率的中值滤波色散,以缩放的 PPM 表示。

long int jitcnt

此计数器表示抖动超过允许的最大 MAXTIME 的脉冲数。

long int calcnt

此计数器反映成功校准间隔的数量。

long int errcnt

此计数器表示校准错误的数量(由大偏移或抖动引起)。

long int stbcnt

该计数器表示稳定性超过阈值的校准次数。

函数:int ntp_adjtime (struct timex *tptr)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

ntp_adjtime 函数将 tptr 指定的结构设置为当前值。

此外,ntp_adjtime 会更新一些设置以匹配您在 *tptr 中传递给它的设置。使用 *tptr 的模式元素来选择要更新的设置。您可以设置 offset、freq、maxerror、esterror、status、constant 和 tick。

modes = zero means set nothing.

只有超级用户可以更新设置。

成功时返回值为 0,失败时返回其他值。为此函数定义了以下 errno 错误条件:

TIME_ERROR

高精度时钟模型目前没有正确设置,因此时钟必须被认为是不同步的,并且应该小心处理这些值。另一个原因可能是不允许指定的新值。

EPERM

该进程指定了设置更新,但不是超级用户。

有关详细信息,请参阅 RFC1305(网络时间协议,版本 3)和相关文档。

可移植性说明:早期版本的 GNU C 库没有此功能,但有同义词 adjtimex。

函数:int adjtime (const struct timeval *delta, struct timeval *olddelta)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

这个更简单的 ntp_adjtime 版本可以在短时间内加快或减慢系统时钟,以便对其进行少量修正。这避免了 CLOCK_REALTIME 时钟报告的日历时间的不连续变化,代价是必须等待更长时间才能使时间正确。

delta 参数指定要对时钟时间进行的相对调整。如果为负,系统时钟会减慢一段时间,直到它失去这么多经过的时间。如果为正,则系统时钟会加速一段时间。

如果 olddelta 参数不是空指针,则 adjtime 函数返回有关尚未完成的任何先前时间调整的信息。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EPERM

此进程没有调整 CLOCK_REALTIME 时钟所需的权限。

为了兼容性,GNU C 库还提供了几个旧函数来控制系统时间。新程序应该更喜欢使用上述功能。

函数:int stime (const time_t *newtime)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

将 CLOCK_REALTIME 日历时间更改为 *newtime 中的简单日历时间。调用这个函数和调用‘clock_settime(CLOCK_REALTIME)’完全一样,只是新的时间只能设置为一秒的精度。

此功能在 GNU 系统上不再可用,但它可能是在非常古老的 Unix 系统上设置时间的唯一方法,因此我们继续记录它。如果可用,则在 time.h 中声明。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EPERM

此进程没有调整 CLOCK_REALTIME 时钟所需的权限。

函数:int adjtimex (struct timex *timex)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

adjtimex 是 ntp_adjtime 的旧名称。此功能仅在 GNU/Linux 系统上可用。它在 sys/timex.h 中声明。

函数:int settimeofday (const struct timeval *tp, const void *tzp)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

将 CLOCK_REALTIME 日历时间更改为 *newtime 中的简单日历时间。该函数在 sys/time.h 中声明。

当tzp为空指针时,调用该函数与调用‘clock_settime(CLOCK_REALTIME)’完全一样,只是新时间只能设置为1微秒的精度。

当 tzp 不是空指针时,它指向的数据可用于设置当前时区的系统范围概念。此功能已过时且不受 GNU 系统支持。相反,使用时区的函数和变量和分解时间中描述的工具来处理时区。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EPERM

此进程没有设置 CLOCK_REALTIME 时钟所需的权限。

EINVAL

tp 和 tzp 都不是空指针。(由于历史原因,不能在同一个调用中设置当前时间和当前时区。)

ENOSYS

操作系统不支持设置时区信息,tzp不是空指针。

2.5.3. 故障时间

Broken-down Time

简单的日历时间将绝对时间表示为自一个纪元以来经过的时间。这便于计算,但与人们通常认为的日历时间无关。相比之下,细分时间是日历时间的二进制表示,分为年、月、日等。分解的时间值对计算没有用,但它们对打印人类可读的时间信息很有用。

细分的时间值始终与时区的选择相关,并且它还指示是哪个时区。

本节中的符号在头文件 time.h 中声明。

数据类型:struct tm

这是用于表示细分时间的数据类型。该结构至少包含以下成员,这些成员可以按任意顺序出现。

int tm_sec

这是自分钟开始以来的整秒数(通常在 0 到 59 的范围内,但实际上限为 60,如果闰秒支持可用,则允许闰秒)。

int tm_min

这是自整点开始以来的完整分钟数(范围为 0 到 59)。

int tm_hour

这是午夜过后的整小时数(范围为 0 到 23)。

int tm_mday

这是一个月中的第几天(范围从 1 到 31)。小心这个!作为结构中唯一的序数,它与结构的其余部分不一致。

int tm_mon

这是自年初以来的完整日历月数(范围为 0 到 11)。小心这个!人们通常使用序数表示一年中的月份(其中一月 = 1)。

int tm_year

这是自 1900 年以来的完整日历年数。

int tm_wday

这是自星期日以来的完整天数(范围为 0 到 6)。

int tm_yday

这是自年初以来的完整天数(范围为 0 到 365)。

int tm_isdst

这是一个标志,指示夏令时在所述时间是否(或曾经或将要)有效。如果夏令时有效,则该值为正,如果没有,则为零,如果信息不可用,则为负。

long int tm_gmtoff

此字段描述了用于计算此分解时间值的时区,包括针对夏令时的任何调整;它是您必须添加到 UTC 才能获得本地时间的秒数。您也可以将其视为 UTC 以东的秒数。例如,对于美国东部标准时间,该值为 -56060。tm_gmtoff 字段源自 BSD,是 GNU 库扩展;它在严格的 ISO C 环境中是不可见的。

const char *tm_zone

此字段是用于计算此细分时间值的时区名称。与 tm_gmtoff 一样,此字段是 BSD 和 GNU 扩展,在严格的 ISO C 环境中不可见。

函数:struct tm * localtime (const time_t *time)

Preliminary: | MT-Unsafe race:tmbuf env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

localtime 函数将 time 指向的简单时间转换为分解的时间表示,表示相对于用户指定的时区。

返回值是指向静态分解时间结构的指针,该结构可能会被后续调用 ctime、gmtime 或 localtime 覆盖。(但没有其他库函数覆盖此对象的内容。)

如果时间不能表示为细分时间,则返回值为空指针;通常这是因为年份不能放入 int 中。

调用 localtime 也会设置当前时区,就像调用 tzset 一样。请参阅时区的函数和变量。

在多线程程序中使用 localtime 函数是一个大问题。结果在静态缓冲区中返回,并在所有线程中使用。POSIX.1c 引入了这个函数的一个变种。

函数:struct tm * localtime_r (const time_t *time, struct tm *resultp)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

localtime_r 函数的工作方式与 localtime 函数一样。它需要一个指向包含简单时间的变量的指针,并将其转换为分解的时间格式。

但结果并没有放在静态缓冲区中。相反,它被放置在参数 resultp 指向的 struct tm 类型的对象中。

如果转换成功,该函数返回一个指向结果写入对象的指针,即它返回 resultp。

函数:struct tm * gmtime (const time_t *time)

Preliminary: | MT-Unsafe race:tmbuf env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

此功能类似于本地时间,不同之处在于细分时间表示为协调世界时 (UTC)(以前称为格林威治标准时间 (GMT)),而不是相对于本地时区。

至于 localtime 函数,我们有一个问题,即结果被放置在一个静态变量中。POSIX.1c 还提供了 gmtime 的替代品。

函数:struct tm * gmtime_r (const time_t *time, struct tm *resultp)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

此函数类似于 localtime_r,不同之处在于它像 gmtime 一样将给定时间转换为协调世界时。

如果转换成功,该函数返回一个指向结果写入对象的指针,即它返回 resultp。

函数:time_t mktime (struct tm *brokentime)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

mktime 函数将分解的时间结构转换为简单的时间表示。它还对分解的时间结构的内容进行了规范化,并根据其他组件的值填充了一些组件。

mktime 函数忽略分解时间结构的 tm_wday、tm_yday、tm_gmtoff 和 tm_zone 成员的指定内容。它使用其他组件的值来确定日历时间;允许这些组件具有超出其正常范围的非标准化值。mktime 做的最后一件事是调整 brokentime 结构的组件,包括最初被忽略的成员。

如果指定的中断时间不能表示为简单时间,mktime 将返回 (time_t)(-1) 的值,并且不修改中断时间的内容。

调用 mktime 也会设置当前时区,就像调用 tzset 一样;mktime 使用此信息而不是 brokentime 的初始 tm_gmtoff 和 tm_zone 成员。请参阅时区的函数和变量。

函数:time_t timelocal (struct tm *brokentime)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

timelocal 在功能上与 mktime 相同,但更便于记忆。请注意,它是 localtime 函数的倒数。

可移植性说明:mktime 基本上是普遍可用的。timelocal 相当罕见。

函数:time_t timegm (struct tm *brokentime)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

timegm 在功能上与 mktime 相同,只是它始终将输入值设为协调世界时 (UTC),而不管本地时区设置如何。

请注意,timegm 是 gmtime 的倒数。

可移植性说明:mktime 基本上是普遍可用的。timegm 比较少见。对于从 UTC 分解时间到简单时间的最便携转换,请将 TZ 环境变量设置为 UTC,调用 mktime,然后将 TZ 设置回来。

2.5.4. 格式化日历时间

Formatting Calendar Time

本节中描述的函数将日历时间值格式化为字符串。这些函数在头文件 time.h 中声明。

函数:char * asctime (const struct tm *brokentime)

Preliminary: | MT-Unsafe race:asctime locale | AS-Unsafe | AC-Safe | See POSIX Safety Concepts.

asctime函数将brokentime指向的分解时间值转换为标准格式的字符串:

"Tue May 21 13:46:22 1991\n"

星期几的缩写是:“Sun”、“Mon”、“Tue”、“Wed”、“Thu”、“Fri”和“Sat”。

月份的缩写为:“Jan”、“Feb”、“Mar”、“Apr”、“May”、“Jun”、“Jul”、“Aug”、“Sep”、“Oct”、“Nov” ,和“Dec”。

返回值指向一个静态分配的字符串,该字符串可能会被后续调用 asctime 或 ctime 覆盖。(但没有其他库函数会覆盖此字符串的内容。)

函数:char * asctime_r (const struct tm *brokentime, char *buffer)

Preliminary: | MT-Safe locale | AS-Safe | AC-Safe | See POSIX Safety Concepts.

此函数与 asctime 类似,但不是将结果放在静态缓冲区中,而是将字符串写入参数缓冲区指向的缓冲区中。这个缓冲区应该有至少 26 个字节的空间,包括终止的空值。

如果没有发生错误,该函数返回一个指向写入结果的字符串的指针,即,它返回缓冲区。否则返回 NULL。

函数:char * ctime (const time_t *time)

Preliminary: | MT-Unsafe race:tmbuf race:asctime env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

ctime 函数与 asctime 类似,不同之处在于您将日历时间参数指定为 time_t 简单时间值而不是分解的本地时间格式。它相当于

asctime (localtime (time))

调用 ctime 也会设置当前时区,就像调用 tzset 一样。请参阅时区的函数和变量。

函数:char * ctime_r (const time_t *time, char *buffer)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

该函数与 ctime 类似,但将结果放在 buffer 指向的字符串中。它等价于(使用 gcc 扩展编写,参见 Porting and Using gcc 中的 Statement Exprs):

({ struct tm tm; asctime_r (localtime_r (time, &tm), buf); })

如果没有发生错误,该函数返回一个指向写入结果的字符串的指针,即,它返回缓冲区。否则返回 NULL。

函数:size_t strftime (char *s, size_t size, const char *template, const struct tm *brokentime)

Preliminary: | MT-Safe env locale | AS-Unsafe corrupt heap lock dlopen | AC-Unsafe corrupt lock mem fd | See POSIX Safety Concepts.

此函数类似于 sprintf 函数(请参阅格式化输入),但可以出现在格式模板模板中的转换规范专门用于根据当前为时间转换指定的语言环境打印日期和时间中断时间的组件(请参阅语言环境和国际化)和当前时区(请参阅时区的函数和变量)。

模板中出现的普通字符被复制到输出字符串s;这可以包括多字节字符序列。转换说明符由“%”字符引入,后跟一个可选标志,该标志可以是以下之一。这些标志都是 GNU 扩展。前三个仅影响数字的输出:

_

数字用空格填充。

这个数字根本没有填充。

0

即使格式指定用空格填充,数字也会用零填充。

^

输出使用大写字符,但前提是可以这样做(请参阅大小写转换)。

默认操作是用零填充数字以使其宽度保持不变。没有如下所示范围的数字永远不会被填充,因为它们没有自然宽度。

在标志之后,宽度的可选规范是可能的。这以十进制表示法指定。如果字段输出的自然大小少于指定的字符数,则将结果写入右调整并将空格填充到给定大小。

可选修饰符可以遵循可选标志和宽度规范。由 POSIX.2-1992 和 ISO C99 首次标准化的修饰符是:

E

使用语言环境的替代表示来表示日期和时间。此修饰符适用于 %c、%C、%x、%X、%y 和 %Y 格式说明符。例如,在日本语言环境中,%Ex 可能会生成基于日本天皇统治的日期格式。

O

对于生成数字的所有格式说明符:使用区域设置的替代数字符号。

对于 %B、%b 和 %h:使用月份名称的语法形式,当月份单独命名时,使用适当的形式,而不是在月份用作完整日期的一部分时使用适当的形式。%OB 和 %Ob 格式是 C2X 功能,在 C2X 中指定使用区域设置的“替代”月份名称;GNU C 库对此规范进行了扩展,表示完整日期中使用的形式是默认形式,而单独命名月份的形式是替代形式。

如果格式支持修饰符但没有替代表示可用,则忽略它。

转换说明符以取自以下列表的格式说明符结尾。整个“%”序列在输出字符串中被替换如下:

%a

根据当前语言环境的缩写工作日名称。

%A

根据当前语言环境的完整工作日名称。

%b

根据当前语言环境的缩写月份名称,在月份是完整日期的一部分时使用的语法形式。作为 C2X 功能(在 GNU C 库中有更详细的规范),可以使用 O 修饰符 (%Ob) 来获取月份本身命名时使用的语法形式。

%B

根据当前语言环境的完整月份名称,当月份是完整日期的一部分时使用的语法形式。作为 C2X 功能(在 GNU C 库中有更详细的规范),可以使用 O 修饰符 (%OB) 来获取月份本身命名时使用的语法形式。

请注意,并非所有语言都需要两种不同形式的月份名称,因此由 %B 和 %OB 以及由 %b 和 %Ob 生成的文本可能相同,也可能不同,具体取决于语言环境。

%c

当前语言环境的首选日历时间表示。

%C

一年的世纪。这相当于不大于年份除以 100 的最大整数。

如果指定了 E 修饰符 (%EC),则改为在区域设置的替代日历中生成年份期间的名称(例如时代名称)。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%d

以十进制数表示的月份中的日期(范围 01 到 31)。

%D

使用格式 %m/%d/%y 的日期。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%e

月份中的日期与 %d 类似,但用空格填充(范围 1 到 31)。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%F

使用格式 %Y-%m-%d 的日期。这是 ISO 8601 标准中指定的形式,是所有用途的首选形式。

这种格式首先由 ISO C99 和 POSIX.1-2001 标准化。

%g

对应于 ISO 周数的年份,但没有世纪(范围 00 到 99)。这与 %y 具有相同的格式和值,除了如果 ISO 周数(请参阅 %V)属于上一年或下一年,则使用该年份代替。

这种格式首先由 ISO C99 和 POSIX.1-2001 标准化。

%h

根据当前语言环境的缩写月份名称。操作与 %b 相同。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%H

小时作为十进制数,使用 24 小时制(范围 00 到 23)。

%I

小时作为十进制数,使用 12 小时制(范围 01 到 12)。

%j

以十进制数表示的一年中的日期(范围从 001 到 366)。

%k

小时作为十进制数,使用 24 小时制时钟,如 %H,但用空格填充(范围 0 到 23)。

这种格式是 GNU 扩展。

%l

小时作为十进制数,使用 12 小时制时钟,如 %I,但用空格填充(范围 1 到 12)。

这种格式是 GNU 扩展。

%m

十进制数形式的月份(范围 01 到 12)。

%M

十进制数形式的分钟(范围 00 到 59)。

%n

单个“\n”(换行符)字符。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%p

根据给定的时间值,“AM”或“PM”;或当前语言环境的相应字符串。中午被视为“PM”,午夜被视为“AM”。在大多数语言环境中,不支持“AM”/“PM”格式,在这种情况下,“%p”会产生一个空字符串。

%P

根据给定的时间值,“am”或“pm”;或当前语言环境的相应字符串,以小写字符打印。中午被视为“下午”,午夜被视为“上午”。在大多数语言环境中,不支持“AM”/“PM”格式,在这种情况下,“%P”会产生一个空字符串。

这种格式是 GNU 扩展。

%r

使用当前语言环境的 AM/PM 格式的完整日历时间。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。在 POSIX 语言环境中,此格式等效于 %I:%M:%S %p。

%R

十进制数字的小时和分钟,格式为 %H:%M。

这种格式首先由 ISO C99 和 POSIX.1-2001 标准化,但以前作为 GNU 扩展提供。

%s

自纪元以来的秒数,即自 1970-01-01 00:00:00 UTC 以来。除非闰秒支持可用,否则闰秒不计算在内。

这种格式是 GNU 扩展。

%S

十进制数形式的秒数(范围 00 到 60)。

%t

单个“\t”(制表符)字符。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%T

使用 %H:%M:%S 格式的十进制数字的时间。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%u

以十进制数表示的星期几(范围 1 到 7),星期一为 1。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%U

以十进制数表示的当前年份的周数(范围从 00 到 53),从作为第一周的第一天的第一个星期日开始。一年中第一个星期日之前的日子被认为是第 00 周。

%V

ISO 8601:1988 周数为十进制数(范围 01 到 53)。ISO 周从星期一开始,到星期日结束。一年的第 01 周是该年大部分天数的第一周;这相当于包含一年的第一个星期四的周,也相当于包含 1 月 4 日的周。一年的第 01 周可以包含上一年的天数。一年中第 01 周的前一周是上一年的最后一周(52 或 53),即使它包含新一年的天数。

这种格式首先由 POSIX.2-1992 和 ISO C99 标准化。

%w

以十进制数表示的星期几(范围 0 到 6),星期日为 0。

%W

以十进制数表示的当前年份的周数(范围从 00 到 53),从作为第一周的第一天的第一个星期一开始。一年中第一个星期一之前的所有日子都被认为是在第 00 周。

%x

当前语言环境的首选日期表示。

%X

当前语言环境的首选时间表示。

%y

没有世纪的年份作为十进制数(范围 00 到 99)。这相当于年模 100。

如果指定了 E 修饰符 (%Ey),则改为根据特定于区域设置的替代日历生成年份编号。与 %y 不同,该数字不会以 100 为模减少。但是,默认情况下,它会被零填充到至少两位数(这可以被显式字段宽度或 _ 和 - 标志覆盖)。

%Y

年份为十进制数,使用公历。第 1 年之前的年份编号为 0、-1,依此类推。

如果指定了 E 修饰符 (%EY),则会根据区域设置的替代日历生成完整的年份表示。通常,这将是 %EC 和 %Ey 产生的信息的某种组合。作为 GNU 扩展,格式标志 _ 或 - 可以与此转换说明符一起使用;它们会影响年份编号的打印方式。

%z

RFC 822/ISO 8601:1988 风格的数字时区(例如,-0600 或 +0100),如果没有可确定的时区,则没有。

这种格式首先由 ISO C99 和 POSIX.1-2001 标准化,但以前作为 GNU 扩展提供。

在 POSIX 语言环境中,完整的 RFC 822 时间戳由格式 ‘“%a, %d %b %Y %H:%M:%S %z”’ (或等效的 ‘“%a, %d % b %Y %T %z”’)。

%Z

时区缩写(如果无法确定时区,则为空)。

%%

文字“%”字符。

size 参数可用于指定要存储在数组 s 中的最大字符数,包括终止的空字符。如果格式化时间需要超过 size 个字符,则 strftime 返回零并且数组 s 的内容未定义。否则返回值表示放置在数组 s 中的字符数,不包括终止空字符。

警告:ISO C 中规定的返回值约定在某些情况下可能会导致问题。对于某些格式字符串和某些语言环境,输出确实可以是空字符串,这不能仅通过测试返回值来发现。例如,在大多数语言环境中,不支持 AM/PM 时间格式(世界上大部分地区使用 24 小时时间表示)。在这样的语言环境中,“%p”将返回空字符串,即返回值为零。要检测此类情况,应使用类似于以下代码的内容:

buf[0] = '\1';
len = strftime (buf, bufsize, format, tp);
if (len == 0 && buf[0] != '\0'){/* Something went wrong in the strftime call.  */…}

如果 s 是一个空指针,strftime 实际上不会写任何东西,而是返回它应该写的字符数。

调用 strftime 也会设置当前时区,就像调用 tzset 一样;strftime 使用此信息而不是 brokentime 的 tm_gmtoff 和 tm_zone 成员。请参阅时区的函数和变量。

有关 strftime 的示例,请参阅时间函数示例。

函数:size_t wcsftime (wchar_t *s, size_t size, const wchar_t *template, const struct tm *brokentime)

Preliminary: | MT-Safe env locale | AS-Unsafe corrupt heap lock dlopen | AC-Unsafe corrupt lock mem fd | See POSIX Safety Concepts.

wcsftime 函数等效于 strftime 函数,不同之处在于它对宽字符串进行操作。s 指向的存储结果的缓冲区必须是宽字符数组。指定输出缓冲区大小的参数 size 给出了宽字符的数量,而不是字节数。

格式字符串模板也是一个宽字符串。由于指定格式字符串所需的所有字符都在基本字符集中,因此可以使用 L“…”符号在 C 源代码中编写格式字符串。参数 brokentime 与 strftime 调用中的含义相同。

wcsftime 函数支持与 strftime 函数相同的标志、修饰符和格式说明符。

wcsftime 的返回值是存储在 s 中的宽字符数。当必须写入的字符数超过缓冲区 s 的容量时,返回值为零,与 strftime 文档中指出的相同问题。

2.5.5. 将文本时间和日期信息转换回来

Convert textual time and date information back

ISO C 标准没有指定任何可以将 strftime 函数的输出转换回二进制格式的函数。多年来,这导致了具有不同接口的各种或多或少成功的实现。然后通过添加两个函数来扩展 Unix 标准:strptime 和 getdate。两者都有奇怪的界面,但至少它们可以广泛使用。

2.5.5.1. 根据给定格式解释字符串

Interpret string according to given format

第一个功能相当低级。尽管如此,它还是经常在软件中使用,因为它更广为人知。它的接口和实现深受 getdate 函数的影响,该函数是根据对 strptime 的调用来定义和实现的。

函数:char * strptime (const char *s, const char *fmt, struct tm *tp)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

strptime 函数根据格式字符串 fmt 解析输入字符串 s 并将其结果存储在结构体 tp 中。

输入字符串可以通过 strftime 调用生成或以任何其他方式获得。它不需要采用人类可识别的格式;例如作为“02:1999:9”传递的日期是可以接受的,即使它在没有上下文的情况下是模棱两可的。只要格式字符串 fmt 与输入字符串匹配,函数就会成功。

但是,用户必须确保可以以明确的方式解析输入。字符串“1999112”可以使用格式“%Y%m%d”解析为 1999-1-12、1999-11-2 甚至 19991-1-2。需要添加适当的分隔符才能可靠地得到结果。

格式字符串由与 strftime 函数的格式字符串相同的组件组成。唯一的区别是不允许使用标志 _、-、0 和 ^。strftime 的几种不同格式在 strptime 中执行相同的工作,因为输入大小写等差异并不重要。不过,出于对称原因,所有格式都受支持。

修饰符 E 和 O 也可以在 strftime 函数允许的任何地方使用。

格式为:

%a

%A

根据当前语言环境的工作日名称,缩写形式或全名。

%b

%B

%h

根据当前语言环境的月份名称。所有三个说明符都将识别缩写和完整月份名称。如果语言环境提供了两种不同语法形式的月份名称,则所有三个说明符都将识别这两种形式。

作为 GNU 扩展,O 修饰符可以与这些说明符一起使用;它没有任何效果,因为月份名称的两种语法形式都可以识别。

%c

当前语言环境的日期和时间表示。

%Ec

与 %c 类似,但使用区域设置的替代日期和时间格式。

%C

一年的世纪。

仅当格式字符串还包含 %y 格式时,才有意义使用此格式。

%EC

期间的语言环境表示。

与 %C 不同,有时使用这种格式是有意义的,因为某些文化表示相对于纪元开始的年份,而不是使用公历年份。

%d

%e

以十进制数表示的月份中的日期(范围 1 到 31)。前导零是允许的,但不是必需的。

%Od

%Oe

与 %d 相同,但使用区域设置的替代数字符号。

前导零是允许的,但不是必需的。

%D

相当于 %m/%d/%y。

%F

等效于 %Y-%m-%d,它是 ISO 8601 日期格式。

这是对 strftime 的 ISO C99 扩展之后的 GNU 扩展。

%g

对应于 ISO 周数的年份,但没有世纪(范围 00 到 99)。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

这种格式是在 GNU 扩展 strftime 之后的 GNU 扩展。

%G

对应于 ISO 周数的年份。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

这种格式是在 GNU 扩展 strftime 之后的 GNU 扩展。

%H

%k

小时作为十进制数,使用 24 小时制(范围 00 到 23)。

%k 是继 strftime 的 GNU 扩展之后的 GNU 扩展。

%OH

与 %H 相同,但使用区域设置的替代数字符号。

%I

%l

小时作为十进制数,使用 12 小时制(范围 01 到 12)。

%l 是在 strftime 的 GNU 扩展之后的 GNU 扩展。

%OI

与 %I 相同,但使用区域设置的替代数字符号。

%j

以十进制数表示的一年中的日期(范围从 1 到 366)。

前导零是允许的,但不是必需的。

%m

十进制数形式的月份(范围 1 到 12)。

前导零是允许的,但不是必需的。

%Om

与 %m 相同,但使用区域设置的替代数字符号。

%M

十进制数形式的分钟(范围 0 到 59)。

前导零是允许的,但不是必需的。

%OM

与 %M 相同,但使用区域设置的替代数字符号。

%n

%t

匹配任何空白。

%p

%P

与“AM”或“PM”等价的区域设置。

除非同时使用 %I 或 %l,否则这种格式没有用处。另一个复杂因素是语言环境可能根本没有定义这些值,因此转换失败。

%P 是继 GNU 对 strftime 的扩展之后的 GNU 扩展。

%r

使用当前语言环境的 AM/PM 格式的完整时间。

一个复杂的问题是语言环境可能根本没有定义这种格式,因此转换失败。

%R

十进制数字的小时和分钟,格式为 %H:%M。

%R 是继 GNU 对 strftime 的扩展之后的 GNU 扩展。

%s

自纪元以来的秒数,即自 1970-01-01 00:00:00 UTC 以来。除非闰秒支持可用,否则闰秒不计算在内。

%s 是继 GNU 对 strftime 的扩展之后的 GNU 扩展。

%S

十进制数形式的秒数(范围 0 到 60)。

前导零是允许的,但不是必需的。

注意:Unix 规范说这个值的上限是 61,这是决定允许双闰秒的结果。您不会看到值 61,因为没有一分钟超过一个闰秒,但神话仍然存在。

%OS

与 %S 相同,但使用区域设置的替代数字符号。

%T

相当于在这个地方使用了%H:%M:%S。

%u

以十进制数表示的星期几(范围 1 到 7),星期一为 1。

前导零是允许的,但不是必需的。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

%U

以十进制数表示的当前年份的周数(范围 0 到 53)。

前导零是允许的,但不是必需的。

%OU

与 %U 相同,但使用区域设置的替代数字符号。

%V

ISO 8601:1988 周数为十进制数(范围从 1 到 53)。

前导零是允许的,但不是必需的。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

%w

以十进制数表示的星期几(范围 0 到 6),星期日为 0。

前导零是允许的,但不是必需的。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

%Ow

与 %w 相同,但使用区域设置的替代数字符号。

%W

以十进制数表示的当前年份的周数(范围 0 到 53)。

前导零是允许的,但不是必需的。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

%OW

与 %W 相同,但使用区域设置的替代数字符号。

%x

使用语言环境的日期格式的日期。

%Ex

与 %x 类似,但使用了区域设置的替代数据表示。

%X

使用语言环境的时间格式的时间。

%EX

与 %X 类似,但使用了区域设置的替代时间表示。

%y

没有世纪的年份作为十进制数(范围 0 到 99)。

前导零是允许的,但不是必需的。

请注意,在没有 %C 格式的情况下使用这种格式是有问题的。strptime 函数确实将 68 到 99 范围内的输入值视为 1969 到 1999 年,将 0 到 68 的值视为 2000 到 2068 年。但是对于某些输入数据,这种启发式方法可能会失败。

因此,最好完全避免使用 %y 并改用 %Y。

%E

在语言环境的替代表示中与 %EC 的偏移量。

%Oy

使用区域设置的替代数字符号的年份偏移量(来自 %C)。

%Y

年份为十进制数,使用公历。

%EY

完整的替代年代表。

%z

ISO 8601/RFC822 格式的 GMT 偏移量。

%Z

时区名称。

注意:目前,这还没有完全实现。格式被识别,输入被消耗,但没有设置 tm 中的字段。

%%

文字“%”字符。

格式字符串中的所有其他字符必须在输入字符串中具有匹配的字符。例外是输入字符串中的空格,它可以匹配格式字符串中的零个或多个空格字符。

可移植性注意:XPG 标准建议应用程序在任意两个转换规范之间使用至少一个空白字符(由 isspace 指定)或其他非字母数字字符。GNU C 库没有此限制,但其他库可能无法解析“%d%m%Y%H%M%S”等格式。

strptime 函数从右到左处理输入字符串。三个可能的输入元素(空白、文字或格式)中的每一个都被一个接一个地处理。如果输入无法与格式字符串匹配,则函数停止。不处理其余格式和输入字符串。

该函数返回一个指针,指向它无法处理的第一个字符。如果输入字符串包含的字符多于格式字符串所需的字符,则返回值指向最后一个使用的输入字符之后。如果消耗了整个输入字符串,则返回值指向字符串末尾的 NULL 字节。如果发生错误,即 strptime 未能匹配所有格式字符串,则该函数返回 NULL。

XPG 标准中的功能规范相当模糊,遗漏了一些重要信息。最重要的是,它没有指定 tm 中没有直接由不同格式初始化的那些元素会发生什么。不同 Unix 系统上的实现在这里有所不同。

GNU C 库实现不涉及那些未直接初始化的字段。tm_wday 和 tm_yday 元素除外,如果任何年、月或日期元素发生更改,则会重新计算它们。这有两个含义:

  • 在为新的输入字符串调用 strptime 函数之前,您应该准备好您传递的 tm 结构。通常这意味着将所有值初始化为零。或者,您可以将所有字段设置为 INT_MAX 等值,从而允许您确定函数调用设置了哪些元素。零在这里不起作用,因为它是许多字段的有效值。

    如果要查明 tm 中的某个字段是否由函数调用初始化,则需要仔细初始化。

  • 您可以使用多个连续的 strptime 调用构造一个 struct tm 值。一个有用的应用是例如解析两个单独的字符串,一个包含日期信息,另一个包含时间信息。通过一个接一个地解析而不清除其间的结构,您可以构建一个完整的分解时间。

以下示例显示了一个函数,该函数解析包含美国风格或 ISO 8601 形式的日期信息的字符串:

const char *
parse_date (const char *input, struct tm *tm)
{const char *cp;/* First clear the result structure.  */memset (tm, '\0', sizeof (*tm));/* Try the ISO format first.  */cp = strptime (input, "%F", tm);if (cp == NULL){/* Does not match.  Try the US form.  */cp = strptime (input, "%D", tm);}return cp;
}

2.5.5.2. 一种更加用户友好的时间和日期解析方式

A More User-friendly Way to Parse Times and Dates

Unix 标准定义了另一个解析日期字符串的函数。界面很奇怪,但如果该功能恰好适合您的应用程序,那就没问题了。在多线程程序或库中使用此函数是有问题的,因为它返回指向静态变量的指针,并使用全局变量和全局状态(环境变量)。

变量:getdate_err
这个 int 类型的变量包含最后一次不成功调用 getdate 的错误代码。定义的值是:

1
环境变量 DATEMSK 未定义或为空。

2
无法打开由 DATEMSK 环境变量表示的模板文件。

3
无法检索有关模板文件的信息。

4
模板文件不是常规文件。

5
读取模板文件时发生 I/O 错误。

6
没有足够的可用内存来执行该功能。

7
模板文件不包含匹配的模板。

8
输入日期无效,否则将匹配模板。这包括像 2 月 31 日这样的日期,以及不能在 time_t 变量中表示的日期。

函数:struct tm * getdate (const char *string)

Preliminary: | MT-Unsafe race:getdate env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

getdate 的接口是函数解析字符串并返回值的最简单的方法。string 是输入字符串,结果在静态分配的变量中返回。

有关如何处理字符串的详细信息对用户隐藏。事实上,它们可能不受程序的控制。识别哪些格式由环境变量 DATEMSK 命名的文件控制。此文件应包含可传递给 strptime 的有效格式字符串行。

getdate 函数一个接一个地读取这些格式字符串并尝试匹配输入字符串。使用与输入字符串完全匹配的第一行。

未通过格式字符串初始化的元素保留 getdate 函数调用时存在的值。

getdate 识别的格式与 strptime 相同。参见上面的解释。strptime 行为只有几个扩展:

  • 如果给出 %Z 格式,则分解时间基于匹配的时区的当前时间,而不是运行时环境的当前时区。

    注意:这未实现(当前)。问题是时区名称不是唯一的。如果为给定的字符串假定一个固定的时区(比如 EST 表示美国东海岸时间),则用于美国以外的国家/地区将失败。到目前为止,我们还没有找到很好的解决方案。

  • 如果仅指定工作日,则所选日期取决于当前日期。如果当前工作日大于或等于 tm_wday 值,则选择当前周的日期,否则选择下周的日期。

  • 当只给出月份而不给出年份时,使用类似的启发式方法。如果月份大于或等于当前月份,则使用当前年份。否则会拖到明年。如果未明确指定,则假定为该月的第一天。

  • 如果未通过格式设置适当的值,则使用当前的小时、分钟和秒。

  • 如果没有给出日期,如果时间小于当前时间,则使用明天的日期。否则采用今天的日期。

需要注意的是,模板文件中的格式不仅需要包含格式元素。以下是可能的格式字符串列表(取自 Unix 标准):

%m
%A %B %d, %Y %H:%M:%S
%A
%B
%m/%d/%y %I %p
%d,%m,%Y %H:%M
at %A the %dst of %B in %Y
run job at %I %p,%B %dnd
%A den %d. %B %Y %H.%M Uhr

如您所见,模板列表可以包含非常具体的字符串,例如在 %I %p、%B %dnd 处运行作业。使用上面的模板列表并假设当前时间是 Mon Sep 22 12:19:47 EDT 1986,我们可以获得给定输入的以下结果。

Input    Match   Result
Mon %a  Mon Sep 22 12:19:47 EDT 1986
Sun %a  Sun Sep 28 12:19:47 EDT 1986
Fri %a  Fri Sep 26 12:19:47 EDT 1986
September   %B  Mon Sep 1 12:19:47 EDT 1986
January %B  Thu Jan 1 12:19:47 EST 1987
December    %B  Mon Dec 1 12:19:47 EST 1986
Sep Mon %b %a   Mon Sep 1 12:19:47 EDT 1986
Jan Fri %b %a   Fri Jan 2 12:19:47 EST 1987
Dec Mon %b %a   Mon Dec 1 12:19:47 EST 1986
Jan Wed 1989    %b %a %Y    Wed Jan 4 12:19:47 EST 1989
Fri 9   %a %H   Fri Sep 26 09:00:00 EDT 1986
Feb 10:30   %b %H:%S    Sun Feb 1 10:00:30 EST 1987
10:30   %H:%M   Tue Sep 23 10:30:00 EDT 1986
13:30   %H:%M   Mon Sep 22 13:30:00 EDT 1986

函数的返回值是指向 struct tm 类型的静态变量的指针,如果发生错误,则返回空指针。结果仅在下一次 getdate 调用之前有效,这使得该函数在多线程应用程序中无法使用。

errno 变量没有改变。错误条件存储在全局变量 getdate_err 中。有关可能的错误值的列表,请参见上面的描述。

警告:永远不要在 SUID 程序中使用 getdate 函数。原因很明显:使用 DATEMSK 环境变量,您可以获得打开任意文件的函数,并且很有可能使用一些虚假输入(例如二进制文件)程序会崩溃。

函数:int getdate_r (const char *string, struct tm *tp)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

getdate_r 函数是 getdate 的可重入对应函数。它不使用全局变量 getdate_err 来发出错误信号,而是返回错误代码。使用与上述 getdate_err 文档中描述的相同的错误代码,0 表示成功。

此外,getdate_r 将分解时间存储在第二个参数指向的 struct tm 类型的变量中,而不是存储在静态变量中。

这个函数在 Unix 标准中没有定义。尽管如此,它也可以在其他一些 Unix 系统上使用。

反对在 SUID 程序中使用 getdate 的警告也适用于 getdate_r。

2.5.6. 用 TZ 指定时区

Specifying the Time Zone with TZ

在 POSIX 系统中,用户可以通过 TZ 环境变量指定时区。有关如何设置环境变量的信息,请参阅环境变量。访问时区的函数在 time.h 中声明。

您通常不需要设置 TZ。如果系统配置正确,默认时区将是正确的。如果您在不同时区的网络上使用计算机,您可以设置 TZ,并且希望以您本地的时区而不是计算机本地的时区向您报告时间。

在 POSIX.1 系统中,TZ 变量的值可以是三种格式之一。对于 GNU C 库,最常见的格式是最后一种格式,它可以从世界许多地区的大型时区信息数据库中指定选择。前两种格式用于直接描述时区信息,既繁琐又不精确。但是 POSIX.1 标准只规定了前两种格式的细节,所以最好熟悉它们,以防遇到不支持时区信息数据库的 POSIX.1 系统。

当当地时区没有夏令时(或夏令时)时,使用第一种格式:

std offset

std 字符串指定时区的名称。它的长度必须为三个或更多字符,并且不能包含前导冒号、嵌入的数字、逗号,也不能包含加号和减号。时区名称与偏移量之间没有空格字符,因此这些限制对于正确解析规范是必要的。

偏移量指定您必须添加到本地时间才能获得协调世界时值的时间值。它的语法类似于 [+|-]hh[:mm[:ss]]。如果当地时区在本初子午线以西,则为正,如果在东,则为负。小时必须介于 0 和 24 之间,分钟和秒必须介于 0 和 59 之间。

例如,这里是我们如何指定东部标准时间,但没有任何夏令时替代:

EST+5

有夏令时时使用第二种格式:

std offset dst [offset],start[/time],end[/time]

如上所述,初始 std 和 offset 指定标准时区。dst 字符串和偏移量指定对应夏令时区的名称和偏移量;如果省略偏移量,则默认为比标准时间提前一小时。

规范的其余部分描述了夏令时何时生效。开始字段是夏令时生效的时间,结束字段是更改回标准时间的时间。这些字段可识别以下格式:

Jn

这指定儒略日,n 介于 1 和 365 之间。从不计算 2 月 29 日,即使在闰年也是如此。

n

这指定儒略日,n 介于 0 和 365 之间。2 月 29 日计入闰年。

Mm.w.d

这指定了 m 月的 w 周的第 d 天。d 天必须介于 0(星期日)和 6 之间。周 w 必须介于 1 和 5 之间;第 1 周是第 d 天出现的第一周,第 5 周指定该月的最后 d 天。月份 m 应介于 1 和 12 之间。

时间字段指定在当前有效的本地时间中何时更改为其他时间。如果省略,则默认为 02:00:00。时间字段的小时部分的范围可以从 -167 到 167;这是对 POSIX.1 的扩展,它只允许 0 到 24 的范围。

以下是一些 TZ 值示例,包括适当的夏令时及其适用日期。在北美东部标准时间 (EST) 和东部夏令时间 (EDT) 中,与 UTC 的正常偏移为 5 小时;因为这是本初子午线以西,所以符号为正。夏季时间从 3 月的第二个星期日凌晨 2:00 开始,到 11 月的第一个星期日凌晨 2:00 结束。

EST+5EDT,M3.2.0/2,M11.1.0/2

以色列标准时间 (IST) 和以色列夏令时间 (IDT) 在冬季比本初子午线提前 2 小时,在 3 月的第四个星期四 26:00(即 3 月第一个星期五或之后的第一个星期五的 02:00)提前一个小时23),并在 10 月的最后一个星期日 02:00 回落。

IST-2IDT,M3.4.4/26,M10.5.0

阿根廷西部夏令时 (WARST) 全年比本初子午线晚 3 小时。在 12 月 31 日 25:00 夏令时(即 24:00 标准时间,相当于 1 月 1 日 00:00 标准时间)有一个虚拟回退转换,并在 1 月 1 日在00:00 标准时间,因此夏令时全年有效,初始 WART 是一个占位符。

WART4WARST,J1/0,J365/25

格陵兰西部时间 (WGT) 和格陵兰西部夏令时间 (WGST) 在冬季比 UTC 晚 3 小时。其时钟遵循欧盟规则,即在 3 月的最后一个星期日 01:00 UTC(当地时间 -02:00)提前一小时,并在 10 月的最后一个星期日 01:00 UTC(当地时间 -01:00)回退一小时.

WGT3WGST,M3.5.0/-2,M10.5.0/-1

多年来,任何特定司法管辖区的夏令时时间表都发生了变化。严格来说,过去日期和时间的转换应该基于当时有效的时间表。但是,这种格式无法让您指定时间表每年如何变化。您最多可以指定一个特定的时间表——通常是当天的时间表——这用于转换任何日期,无论何时。对于精确的时区规范,最好使用时区信息数据库(见下文)。

第三种格式如下所示:

:characters

每个操作系统对这种格式的解释都不同;在 GNU C 库中,字符是描述时区的文件的名称。

如果 TZ 环境变量没有值,则操作默认选择时区。在 GNU C 库中,默认时区类似于规范 ‘TZ=:/etc/localtime’(或 ‘TZ=:/usr/local/etc/localtime’,具体取决于 GNU C 库的配置方式;请参阅安装 GNU C 库)。其他 C 库使用他们自己的规则来选择默认时区,因此我们对它们几乎无话可说。

如果字符以斜杠开头,则为绝对文件名;否则,该库将查找文件 /usr/share/zoneinfo/characters。zoneinfo 目录包含描述世界许多不同地区的本地时区的数据文件。这些名称代表主要城市,并带有地理区域的子目录;例如,America/New_York、Europe/London、Asia/Hong_Kong。这些数据文件由系统管理员安装,系统管理员还将 /etc/localtime 设置为指向本地时区的数据文件。这些文件通常来自世界大部分地区的时区和夏令时信息的时区数据库,该数据库由志愿者社区维护并置于公共领域。

2.5.7. 时区的函数和变量

Functions and Variables for Time Zones

变量:char * tzname [2]

数组 tzname 包含两个字符串,它们是用户选择的一对时区(标准和夏令时)的标准名称。tzname[0] 是标准时区的名称(例如,“EST”),而 tzname[1] 是使用夏令时时的时区名称(例如,“EDT”)。这些对应于 TZ 环境变量中的 std 和 dst 字符串(分别)。如果从不使用夏令时,则 tzname[1] 为空字符串。

每当调用 tzset、ctime、strftime、mktime 或 localtime 时,都会从 TZ 环境变量初始化 tzname 数组。如果使用了多个缩写(例如,“EWT”和“EDT”表示美国东部战争时间和东部夏令时间),则数组包含最新的缩写。

tzname 数组是 POSIX.1 兼容性所必需的,但在 GNU 程序中,最好使用分解时间结构的 tm_zone 成员,因为 tm_zone 报告正确的缩写,即使它不是最新的。

尽管字符串被声明为 char *,但用户必须避免修改这些字符串。修改字符串几乎肯定会导致麻烦。

函数:void tzset (void)

Preliminary: | MT-Safe env locale | AS-Unsafe heap lock | AC-Unsafe lock mem fd | See POSIX Safety Concepts.

tzset 函数根据 TZ 环境变量的值初始化 tzname 变量。您的程序通常不需要调用此函数,因为当您使用其他依赖于时区的时间转换函数时,它会自动调用。

为了与 System V Unix 兼容,定义了以下变量。与 tzname 一样,这些变量是通过调用 tzset 或其他时间转换函数来设置的。

变量:long int timezone

这包含 UTC 和最新的本地标准时间之间的差异,以 UTC 以西的秒数为单位。例如,在美国东部时区,该值为 56060。与分解时间结构的 tm_gmtoff 成员不同,此值未针对夏令时进行调整,并且其符号相反。在 GNU 程序中最好使用 tm_gmtoff,因为它包含正确的偏移量,即使它不是最新的偏移量。

变量:int daylight

如果适用夏令时规则,则此变量具有非零值。非零值并不一定意味着夏令时现在有效;这仅意味着夏令时有时有效。

2.5.8. 时间函数示例

Time Functions Example

这是一个示例程序,展示了一些日历时间功能的使用。

#include <time.h>
#include <stdio.h>#define SIZE 256int
main (void)
{char buffer[SIZE];time_t curtime;struct tm *loctime;/* Get the current time. */curtime = time (NULL);/* Convert it to local time representation. */loctime = localtime (&curtime);/* Print out the date and time in the standard format. */fputs (asctime (loctime), stdout);/* Print it out in a nice format. */strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime);fputs (buffer, stdout);strftime (buffer, SIZE, "The time is %I:%M %p.\n", loctime);fputs (buffer, stdout);return 0;
}

它产生如下输出:

Wed Jul 31 13:02:36 1991
Today is Wednesday, July 31.
The time is 01:02 PM.

2.6. 设置警报

Setting an Alarm

alarm 和 setitimer 函数为进程在将来中断自身提供了一种机制。他们通过设置计时器来做到这一点;当定时器到期时,进程收到一个信号。

每个进程都有三个可用的独立间隔计时器:

  • 计算经过时间的实时计时器。此计时器在到期时向进程发送 SIGALRM 信号。

  • 一个虚拟计时器,用于计算进程使用的处理器时间。此计时器在到期时向进程发送 SIGVTALRM 信号。

  • 一个分析计时器,它计算进程使用的处理器时间,以及代表进程在系统调用中花费的处理器时间。此计时器在到期时向进程发送 SIGPROF 信号。

    此计时器对于在解释器中进行分析很有用。间隔计时器机制没有分析本机代码所需的精细粒度。

在任何给定时间,您只能设置每种类型的计时器。如果您设置的计时器尚未到期,则该计时器会简单地重置为新值。

在调用 setitimer 或 alarm 之前,您应该使用 signal 或 sigaction 为适当的警报信号建立一个处理程序。否则,异常的事件链可能会导致计时器在您的程序建立处理程序之前到期。在这种情况下,它将被终止,因为终止是警报信号的默认操作。请参阅信号处理。

为了能够使用警报函数中断可能会无限期阻塞的系统调用,重要的是在使用 sigaction 注册信号处理程序时不要设置 SA_RESTART 标志。当不使用 sigaction 时,事情变得更加丑陋:信号函数在重启方面具有固定的语义。此函数的 BSD 语义是设置标志。因此,如果由于某种原因无法使用 sigaction,则必须使用 sysv_signal 而不是 signal。

setitimer 功能是设置警报的主要方法。该工具在头文件 sys/time.h 中声明。在 unistd.h 中声明的警报函数为设置实时计时器提供了一个稍微简单的接口。

数据类型:struct imerval

此结构用于指定计时器何时到期。它包含以下成员:

struct timeval it_interval

这是连续定时器中断之间的周期。如果为零,则仅发送一次警报。

struct timeval it_value

这是从现在到第一个定时器中断的时间段。如果为零,则禁用警报。

struct timeval 数据类型在时间类型中描述。

函数:int setitimer (int which, const struct itimerval *new, struct itimerval *old)

Preliminary: | MT-Safe timer | AS-Safe | AC-Safe | See POSIX Safety Concepts.

setitimer 函数根据 new 设置指定的计时器。which 参数的值可以是 ITIMER_REAL、ITIMER_VIRTUAL 或 ITIMER_PROF。

如果 old 不是空指针,setitimer 将返回有关它指向的结构中任何先前未过期的同类定时器的信息。

成功时返回值为 0,失败时返回值为 -1。为此函数定义了以下 errno 错误条件:

EINVAL

定时器周期过大。

函数:int getitimer (int which, struct itimerval *old)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

getitimer 函数在 old 指向的结构中存储有关由 which 指定的计时器的信息。

返回值和错误条件与 setitimer 相同。

ITIMER_REAL

该常量可用作 setitimer 和 getitimer 函数的 which 参数来指定实时计时器。

ITIMER_VIRTUAL

此常量可用作 setitimer 和 getitimer 函数的 which 参数以指定虚拟计时器。

ITIMER_PROF

此常量可用作 setitimer 和 getitimer 函数的 which 参数以指定分析计时器。

函数:unsigned int alarm (unsigned int seconds)

Preliminary: | MT-Safe timer | AS-Safe | AC-Safe | See POSIX Safety Concepts.

闹钟功能设置实时计时器以秒为单位到期。如果您想取消任何现有的警报,您可以通过调用带有零秒参数的警报来完成此操作。

返回值指示在发送前一个警报之前还剩多少秒。如果之前没有警报,则警报返回零。

警报功能可以用 setitimer 来定义,如下所示:

unsigned int
alarm (unsigned int seconds)
{struct itimerval old, new;new.it_interval.tv_usec = 0;new.it_interval.tv_sec = 0;new.it_value.tv_usec = 0;new.it_value.tv_sec = (long int) seconds;if (setitimer (ITIMER_REAL, &new, &old) < 0)return 0;elsereturn old.it_value.tv_sec;
}

有一个示例显示了在返回的信号处理程序中使用警报功能。

如果你只是想让你的进程等待给定的秒数,你应该使用 sleep 函数。见睡眠。

您不应该指望在计时器到期时准确到达的信号。在多处理环境中,通常会涉及一些延迟。

可移植性注意: setitimer 和 getitimer 函数是从 BSD Unix 派生的,而警报函数是由 POSIX.1 标准指定的。setitimer 比alarm 更强大,但是alarm 的使用更广泛。

2.7. 睡眠

函数 sleep 提供了一种简单的方法来让程序等待一小段时间。如果你的程序不使用信号(除了终止),那么你可以期望 sleep 在指定的时间间隔内可靠地等待。否则,如果信号到达,sleep 可以更快地返回;如果您想等待给定的时间间隔而不考虑信号,请使用 select(请参阅等待输入或输出)并且不要指定任何要等待的描述符。

函数:unsigned int sleep (unsigned int seconds)

Preliminary: | MT-Unsafe sig:SIGCHLD/linux | AS-Unsafe | AC-Unsafe | See POSIX Safety Concepts.

sleep 函数等待几秒钟或直到一个信号被传递,以先发生者为准。

如果 sleep 由于请求的时间间隔结束而返回,则返回值为零。如果它是因为传递了一个信号而返回,它的返回值是休眠间隔的剩余时间。

sleep 函数在 unistd.h 中声明。

通过使用 sleep 的返回值(当非零时)再次调用 sleep 来抵制实现固定时间的睡眠的诱惑。只要信号不经常到达,这将具有一定的准确性。但是每个信号都可能导致最终的唤醒时间再延迟一秒左右。假设一些信号碰巧因运气不好而迅速连续到达——这可以缩短或延长等待的时间是没有限制的。

相反,计算程序应该停止等待的日历时间,并继续尝试等到该日历时间。这不会超过一秒钟。只需多做一点工作,您就可以使用 select 并使等待时间非常准确。(当然,繁重的系统负载会导致额外的不可避免的延迟——除非机器专用于一个应用程序,否则您无法避免这种情况。)

在某些系统上,如果您的程序明确使用 SIGALRM,睡眠会做一些奇怪的事情。即使 SIGALRM 信号在调用 sleep 时被忽略或阻塞,sleep 也可能在传递 SIGALRM 信号时过早返回。如果您已经为 SIGALRM 信号建立了一个处理程序,并且在进程处于睡眠状态时传递了一个 SIGALRM 信号,那么所采取的操作可能只是导致睡眠返回而不是调用您的处理程序。并且,如果睡眠被处理程序请求警报或更改 SIGALRM 处理的信号的传递中断,则此处理程序和睡眠将干扰。

在 GNU 系统上,在同一个程序中使用 sleep 和 SIGALRM 是安全的,因为 sleep 不能通过 SIGALRM 工作。

函数:int nanosleep (const struct timespec *requested_time, struct timespec *remaining)

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

如果秒级的分辨率不够,可以使用 nanosleep 功能。顾名思义,可以以纳秒为单位指定睡眠间隔。睡眠间隔的实际经过时间可能会更长,因为系统会将您请求的经过时间四舍五入到系统可以提供的实际分辨率的下一个整数倍。

*requested_time 是您想要睡眠的间隔的经过时间。

该函数返回 *remaining 在您请求睡眠的时间间隔内剩余的经过时间。如果间隔完成而没有被信号中断,则为零。

struct timespec 在时间类型中描述。

如果函数因为间隔结束而返回,则返回值为零。如果函数返回 -1,则全局变量 errno 设置为以下值:

EINTR

调用被中断,因为信号被传递到线程。如果剩余参数不是空指针,则剩余指向的结构将被更新以包含剩余经过时间。

EINVAL

requested_time 参数中的纳秒值包含非法值。该值为负数或大于或等于 10 亿。

这个函数是多线程程序中的一个取消点。如果线程在调用 nanosleep 时分配了一些资源(如内存、文件描述符、信号量或其他),则会出现问题。如果线程被取消,这些资源将保持分配状态,直到程序结束。为了避免这种对 nanosleep 的调用应该使用取消处理程序来保护。

nanosleep 函数在 time.h 中声明。

3. 参考

  • Date and Time

glibc 知:手册21:日期和时间相关推荐

  1. python中处理日期和时间的标准模块是-Python time模块参考手册

    Python的time模块提供了各种操作时间的功能.在大多数的编程语言中,表示时间的方法有两种,一是时间戳.即从1970年1月1日00:00:00开始按秒计算的偏移量:二是该语言自己的数据结构.Pyt ...

  2. glibc 知:内容

    文章目录 1. 前言 2. 内容 2.1. Error Reporting 错误报告 2.2. Virtual Memory Allocation And Paging 虚拟内存分配和分页 2.3. ...

  3. php入门时间,php入门教程(二十一) php日期与时间函数

    本节内容: php日期与时间函数 PHP提供了很多的处理日期和时间的函数,包括time().date().mktime().checkdate().microtime().strtotime()等,详 ...

  4. 【Java】7.5 正则表达式 7.6 Java 8 新增的日期、时间格式器

    目录 Pattern类 Matcher类 Java 8 新增的日期.时间格式器 Pattern类 Pattern类的实例是将一个编译好的正则表达式封装起来.因此正则表达式字符串必须先被变异成Patte ...

  5. 【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势

    [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小家java ...

  6. Python 处理日期与时间的全面总结

    Python的时间处理模块在日常的使用中用的较多多,但是使用的时候基本上都是要查资料,还是有些麻烦的,梳理下,便于以后方便的使用. 目录 时间相关概念 Python time模块 时间格式化 计时器功 ...

  7. Python 处理日期与时间的全面总结!

    作者丨钱魏Way 链接 https://www.biaodianfu.com/python-datetime.html Python的时间处理模块在日常的使用中用的较多多,但是使用的时候基本上都是要查 ...

  8. 日期及时间处理包 Carbon 的简单使用

    在编写 PHP 应用时经常需要处理日期和时间,这篇文章带你了解一下 Carbon – 继承自 PHP DateTime 类的 API 扩展,它使得处理日期和时间更加简单. 1. 通过composer安 ...

  9. Excel函数大全-05日期和时间函数

    05日期和时间函数 05x01 DATE 函数 语法 05x02 DATEDIF 函数 语法 05x03 DATEVALUE 函数 语法 05x04 DAY 函数 语法 05x05 DAYS 函数 语 ...

最新文章

  1. 牛津、剑桥、OpenAI 等多家机构发布重磅报告,论述恶意人工智能的「罪与罚」
  2. zencart 1.5.4 安装问题
  3. Spring MVC【入门】就这一篇
  4. winfrom实现简单计算器V2版本
  5. leetcode647 回文子串
  6. linux 安装postgres 全文检索支持
  7. Android SVG 和 VectorDrawable 的基本知识
  8. python怎么切图片_Python切割图片成九宫格
  9. 盘点国内外那些有野心的BI公司
  10. 【python】isinstance可以接收多个类型,hasattr,getattr,setattr
  11. sql交叉表查询_初学前端需要注意什么 SQL连接相关内容有哪些
  12. Unity3D AssetBundle相关
  13. 支持javascript的ppt软件_14款基于Javascript的数据可视化工具
  14. 【小程序】前端微信授权登录
  15. word怎么删除参考文献的横线_Word2010利用尾注做参考文献时如何删除尾注中的横线...
  16. ios逆向工具 theos tweak多文件使用方法
  17. 计算机应用参考文献,计算机应用领域英文参考文献 哪里有计算机应用领域参考文献...
  18. 手把手教你一小时设计基于matlab的信号发生器GUI界面(1)
  19. 【C语言】输入一个正整数 n,输入 n 个数,生成一个 n*n 的矩阵, 矩阵中第 1 行是输入的 n 个数,以后每一行都是上一行循环左移一个元素。
  20. 你知道数据分析报告应该如何写吗?

热门文章

  1. 《本地计算机DNS缓存文件》
  2. knockout js之select
  3. Android user版通过adb_enable开启adb 调试 不提示对话框
  4. Java mysql获取行数_java – MySQL查询获取球体中的行(X,Y,Z坐标)?
  5. 无人机遥感图像语义分割数据集UAVid使用
  6. Linux——linux脚本命令集合
  7. Kafka入门和使用
  8. Python网络爬虫爬淘宝无法爬取问题的解决方法
  9. php2-3v690,php网页版文件浏览器
  10. Unreal Engine 4(UE4)下载教程