1 第8.4节:时间函数
awk
程序通常用于处理包含时间戳信息的日志文件,这些时间戳表明特定日志记录的写入时间。许多程序以时间记录系统调用返回的形式记录其时间戳,即自特定纪元以来的秒数。在符合 POSIX 标准的系统上,它是自 1970 年 1 月 1 日 00:00:00 UTC 起的秒数,不计算闰秒。所有已知的符合 POSIX 标准的系统都支持从 0 到 2³¹ - 1 的范围,该范围足以表示到 2038 年 1 月 19 日 03:14:07 UTC 的时间。许多系统支持更广泛的时间戳范围,包括表示纪元之前时间的负时间戳。
为了更轻松地处理此类日志文件并生成有用的报告,gawk
提供了以下用于处理时间戳的函数。它们是 gawk
的扩展;它们未在 POSIX 标准中指定。可选参数用方括号([]
)括起来:
1.1 mktime(datespec [, utc-flag ])
将日期时间字符串转换为与 systime()
返回形式相同的时间戳。它与 ISO C 中同名函数的功能类似。参数 datespec
是格式为 "YYYY MM DD HH MM SS [DST]"
的字符串。该字符串由六个或七个数字组成,分别表示当前年份、从 1 到 12 的月份、从 1 到 31 的一个月中的某天、从 0 到 23 的一天中的小时、从 0 到 59 的分钟、从 0 到 60 的秒,以及一个可选的夏令时标志。
这些数字的值不必在指定的范围内;例如,小时为 -1 表示午夜前 1 小时。假定使用起始于零的公历,年份为 0 表示公元前 1 年,年份 -1 表示公元前 2 年。如果存在 utc-flag
且其为非零值或非空值,则假定时间位于 UTC 时区;否则,假定时间位于本地时区。如果 DST
夏令时标志为正,则假定时间为夏令时;如果为零,则假定时间为标准时间;如果为负(默认值),mktime()
会尝试确定指定时间是否实行夏令时。
如果 datespec
包含的元素不足,或者生成的时间超出范围,mktime()
将返回 -1。
1.2 strftime(format [, timestamp [, utc-flag ] ] )
根据 format
字符串的内容格式化 timestamp
指定的时间,并返回结果。它与 ISO C 中同名函数的功能类似。如果存在 utc-flag
且其为非零值或非空值,则值会格式化为 UTC(协调世界时,以前称为 GMT 或格林威治标准时间)。否则,该值会格式化为本地时区。时间戳与 systime()
函数返回的值格式相同,或者是当前时间。如果没有提供 timestamp
参数,gawk
会使用当前日期和时间作为时间戳。如果没有 format
参数,strftime()
会使用 PROCINFO["strftime"]
的值。默认字符串值为 "%a %b %e %H:%M:%S %Z %Y"
。此格式字符串生成的输出与 date
工具的输出等效。您可以为 PROCINFO["strftime"]
分配一个新值来更改默认格式;有关各种格式指令,请参见下面的列表。
1.3 systime()
返回自纪元以来的当前时间(以秒为单位)。在 POSIX 系统上,它是自 1970 年 1 月 1 日 00:00:00 UTC 起的秒数,不计算闰秒。在其他系统上可能有所不同。
systime()
函数允许您将日志文件中的时间戳与当前日期和时间进行比较。特别是,可以轻松确定特定记录的记录时间距今有多久。它还允许您使用“自纪元以来的秒数”格式生成日志记录。
mktime()
函数允许您将日期和时间的文本表示转换为时间戳。这使得在处理来自外部源(如日志文件)的日期和时间数据时,很容易进行日期和时间的前后比较。
strftime()
函数允许您轻松将时间戳转换为人类可读的信息。它在本质上与 sprintf()
函数类似,因为它会按原样复制非格式说明符字符到返回的字符串中,同时用日期和时间值替换格式说明符在格式字符串中的位置。
根据 1999 年 ISO C 标准,strftime()
保证支持以下日期格式说明符:
%a
:区域设置的缩写星期几名称。%A
:区域设置的完整星期几名称。%b
:区域设置的缩写月份名称。%B
:区域设置的完整月份名称。%c
:区域设置的“适当”日期和时间表示。(在“C”区域设置中,这是"%A %B %d %T %Y"
。)%C
:当前年份的世纪部分。即年份除以 100 并截断为下一个较小的整数。%d
:一个月中的某天,作为十进制数(01 - 31)。%D
:等效于指定"%m/%d/%y"
。%e
:一个月中的某天,如果只有一位数字,则用空格填充。%F
:等效于指定"%Y-%m-%d"
。这是 ISO 8601 日期格式。%g
:ISO 8601 周数的年份模 100,作为十进制数(00 - 99)。例如,2012 年 1 月 1 日属于 2011 年的第 53 周。因此,其 ISO 周数的年份是 2011,即使其年份是 2012。同样,2012 年 12 月 31 日属于 2013 年的第 1 周。因此,其 ISO 周数的年份是 2013,即使其年份是 2012。%G
:ISO 周数的完整年份,作为十进制数。%h
:等效于"%b"
。%H
:小时(24 小时制),作为十进制数(00 - 23)。%I
:小时(12 小时制),作为十进制数(01 - 12)。%j
:一年中的某天,作为十进制数(001 - 366)。%m
:月份,作为十进制数(01 - 12)。%M
:分钟,作为十进制数(00 - 59)。%n
:换行符(ASCII LF)。%p
:与 12 小时制相关的区域设置等效的 AM/PM 标识。%r
:区域设置的 12 小时制时间。(在“C”区域设置中,这是"%I:%M:%S %p"
。)%R
:等效于指定"%H:%M"
。%S
:秒,作为十进制数(00 - 60)。%t
:制表符。%T
:等效于指定"%H:%M:%S"
。%u
:星期几,作为十进制数(1 - 7)。星期一是第一天。%U
:一年中的周数(将第一个星期日作为第一周的第一天),作为十进制数(00 - 53)。%V
:一年中的周数(将第一个星期一作为第一周的第一天),作为十进制数(01 - 53)。确定周数的方法如 ISO 8601 所指定。也就是说,包含 1 月 1 日的那一周有四天或更多天,则为第一周;否则,是上一年的最后一周(52 或 53 周),下一周为第一周。%w
:星期几,作为十进制数(0 - 6)。星期日是第一天。%W
:一年中的周数(将第一个星期一作为第一周的第一天),作为十进制数(00 - 53)。%x
:区域设置的“适当”日期表示。(在“C”区域设置中,这是"%A %B %d %Y"
。)%X
:区域设置的“适当”时间表示。(在“C”区域设置中,这是"%T"
。)%y
:年份模 100,作为十进制数(00 - 99)。%Y
:完整年份,作为十进制数(例如,2015)。%z
:时区偏移量,采用+HHMM
格式(例如,生成 RFC 822 / RFC 1036 日期头所需的格式)。%Z
:时区名称或缩写;如果无法确定时区,则无字符。%%
:文字'%'
。
还提供了仅使用说明符第二个字母的替代表示形式(例如,%Ec
、%EC
、%Ex
、%EX
、%Ey
、%EY
、%Od
、%Oe
、%OH
、%OI
、%Om
、%OM
、%OS
、%Ou
、%OU
、%OV
、%Ow
、%OW
、%Oy
)。这些便于与仅使用 "%c"
、"%C"
等的规范兼容。
gawk
提供了一份来自 GNU C 库的 strftime()
副本。如果使用该版本来编译 gawk
,则还可以使用以下附加格式说明符:
%k
:小时(24 小时制),作为十进制数(0 - 23)。一位数用空格填充。%l
:小时(12 小时制),作为十进制数(1 - 12)。一位数用空格填充。%s
:自纪元以来的时间戳,以秒为单位的十进制数。
附加表示形式会被识别,但它们的正常表示形式通常会被使用。
注意:与 printf()
类似,strftime()
的某些版本支持在 %
和格式说明符字母之间使用标志。请查阅您的 strftime
本地手册页,了解是否使用了任何此类标志,以及它们的含义。但是,请注意,使用任何此类标志可能会使您的脚本在其他系统上的可移植性降低。
以下示例是 awk
对 POSIX date
工具的实现。通常,date
工具以众所周知的格式打印当天的当前日期和时间。但是,如果您提供一个以 +
开头的参数,它会将格式说明符字符打印到标准输出,并根据字符串中的格式说明符解释当前时间。例如:
$ date +"Today is %A, %B %d, %Y"
Today is Monday, September 21, 2014.
以下是 gawk
版本的 date
工具。它有一个 shell“包装器”来处理 -u
选项,该选项要求 date
运行时仿佛时区设置为 UTC:
#!/bin/sh
# date --- approximate the POSIX 'date' command
case $1 in
-u) TZ=UTC0 # use UTC
export TZ
shift ;;
esac
gawk 'BEGIN {
format = PROCINFO["strftime"]
exitval = 0
if (ARGC > 2)
exit(ARGC != 2)
else if (ARGC == 2) {
format = ARGV[1]
if (format ~ /^\+/)
format = substr(format, 2) # remove leading +
}
print strftime(format)
exit exitval
}' "[email protected]"
这个脚本是在 strftime()
函数获得其第三个参数 utc-flag
选项之前编写的。考虑一下您如何修改该程序以完全在 awk
中工作,并处理 -u
选项以打印 UTC 时间。
作者声明:本文用于记录和分享作者的学习心得,可能有部分文字或示例来自AI平台,如:豆包、DeepSeek(硅基流动)(注册链接)等,由于本人水平有限,难免存在表达错误,欢迎留言交流和指教!
Copyright © 2022~2025 All rights reserved.