date 命令详解与参数实测(Ubuntu 22.04)
date 命令逐参数实测详解:默认输出与格式化(%F %T %A %j %U)、-d 相对时间、-u UTC、epoch 时间戳互转、%N 纳秒、-s 设置时间的 root 权限实测报错,全部回显在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。
date 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 GNU date 的每一个参数——默认输出与常用格式化(
%Y-%m-%d、%F %T、%A、%j、%U)、-d相对时间解析、-uUTC、epoch 时间戳互转、%N纳秒精度、-s设置时间的权限要求与实测报错,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- date 版本:GNU coreutils 8.32(
date --version实测) - date 属于 coreutils 基础工具集,Ubuntu 22.04 默认预装,无需额外安装
- 系统时区:UTC(由 3.1 默认输出的
UTC字样实测可见) - 实测基准时间:2026-10-15(周四)06:28:30 UTC,
-d相对时间的回显均以该时刻为基准
二、命令概览
2.1 语法与说明
date 有两种语法形态:date [OPTION]... [+FORMAT](按 FORMAT 显示当前时间)和 date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]](以位置参数设置系统时间,更常用的是 -s)。date 不读写文件、不依赖目录数据,因此本篇无需准备演示文件,所有实测围绕时间显示与解析展开。
date 的高频用法集中在两件事上:格式化输出(脚本里生成时间戳、日志前缀、备份文件名)与时间运算(-d 解析「昨天/下周/3 天前」,epoch 秒与可读时间互转)。帮助中的 FORMAT 控制符全表见 2.2。
💡 技术拓展:Linux 里的"时间"分系统时钟与硬件时钟两套,相关命令横向对比——
工具 原理/职责 适用场景 date 读/设内核系统时钟,格式化输出最灵活 脚本取时间戳、日志命名、时间运算 hwclock 读/写硬件(RTC)时钟,可互相同步 校准硬件时钟( --systohc等)timedatectl systemd 统一管理时间/时区/NTP 查看与设置时区、开关 NTP 同步 stat -c %y 取文件的修改时间戳 关心"文件何时变更"而非当前时间 本文主角是 date:操作的是系统时钟,胜在格式化与时间运算能力;系统时钟与硬件时钟/
timedatectl的分工见 3.7 的 💡 提示。
2.2 --help 全量回显
date --help 输出全部参数与格式控制符清单(实测原样保留,可作为速查):
Usage: date [OPTION]... [+FORMAT]
or: date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
Display the current time in the given FORMAT, or set the system date.
Mandatory arguments to long options are mandatory for short options too.
-d, --date=STRING display time described by STRING, not 'now'
--debug annotate the parsed date,
and warn about questionable usage to stderr
-f, --file=DATEFILE like --date; once for each line of DATEFILE
-I[FMT], --iso-8601[=FMT] output date/time in ISO 8601 format.
FMT='date' for date only (the default),
'hours', 'minutes', 'seconds', or 'ns'
for date and time to the indicated precision.
Example: 2006-08-14T02:34:56-06:00
-R, --rfc-email output date and time in RFC 5322 format.
Example: Mon, 14 Aug 2006 02:34:56 -0600
--rfc-3339=FMT output date/time in RFC 3339 format.
FMT='date', 'seconds', or 'ns'
for date and time to the indicated precision.
Example: 2006-08-14 02:34:56-06:00
-r, --reference=FILE display the last modification time of FILE
-s, --set=STRING set time described by STRING
-u, --utc, --universal print or set Coordinated Universal Time (UTC)
--help display this help and exit
--version output version information and exit
FORMAT controls the output. Interpreted sequences are:
%% a literal %
%a locale's abbreviated weekday name (e.g., Sun)
%A locale's full weekday name (e.g., Sunday)
%b locale's abbreviated month name (e.g., Jan)
%B locale's full month name (e.g., January)
%c locale's date and time (e.g., Thu Mar 3 23:05:25 2005)
%C century; like %Y, except omit last two digits (e.g., 20)
%d day of month (e.g., 01)
%D date; same as %m/%d/%y
%e day of month, space padded; same as %_d
%F full date; like %+4Y-%m-%d
%g last two digits of year of ISO week number (see %G)
%G year of ISO week number (see %V); normally useful only with %V
%h same as %b
%H hour (00..23)
%I hour (01..12)
%j day of year (001..366)
%k hour, space padded ( 0..23); same as %_H
%l hour, space padded ( 1..12); same as %_I
%m month (01..12)
%M minute (00..59)
%n a newline
%N nanoseconds (000000000..999999999)
%p locale's equivalent of either AM or PM; blank if not known
%P like %p, but lower case
%q quarter of year (1..4)
%r locale's 12-hour clock time (e.g., 11:11:04 PM)
%R 24-hour hour and minute; same as %H:%M
%s seconds since 1970-01-01 00:00:00 UTC
%S second (00..60)
%t a tab
%T time; same as %H:%M:%S
%u day of week (1..7); 1 is Monday
%U week number of year, with Sunday as first day of week (00..53)
%V ISO week number, with Monday as first day of week (01..53)
%w day of week (0..6); 0 is Sunday
%W week number of year, with Monday as first day of week (00..53)
%x locale's date representation (e.g., 12/31/99)
%X locale's time representation (e.g., 23:13:48)
%y last two digits of year (00..99)
%Y year
%z +hhmm numeric time zone (e.g., -0400)
%:z +hh:mm numeric time zone (e.g., -04:00)
%::z +hh:mm:ss numeric time zone (e.g., -04:00:00)
%:::z numeric time zone with : to necessary precision (e.g., -04, +05:30)
%Z alphabetic time zone abbreviation (e.g., EDT)
By default, date pads numeric fields with zeroes.
The following optional flags may follow '%':
- (hyphen) do not pad the field
_ (underscore) pad with spaces
0 (zero) pad with zeros
+ pad with zeros, and put '+' before future years with >4 digits
^ use upper case if possible
# use opposite case if possible
After any flags comes an optional field width, as a decimal number;
then an optional modifier, which is either
E to use the locale's alternate representations if available, or
O to use the locale's alternate numeric symbols if available.
Examples:
Convert seconds since the epoch (1970-01-01 UTC) to a date
$ date --date='@2147483647'
Show the time on the west coast of the US (use tzselect(1) to find TZ)
$ TZ='America/Los_Angeles' date
Show the local time for 9AM next Friday on the west coast of the US
$ date --date='TZ="America/Los_Angeles" 09:00 next Fri'
GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/date>
or available locally via: info '(coreutils) date invocation'
💡 说明:date 的参数不多但 FORMAT 控制符极多,常用的不过十余个——日期(
%Y/%m/%d/%F)、时间(%H/%M/%S/%T)、星期(%A/%a/%u)、时间戳(%s)、精度(%N)。帮助尾段的 Examples 还演示了时区变量 TZ 的用法(Q2 会用到)。
2.3 版本确认
$ date --version | head -1
date (GNU coreutils) 8.32
三、参数逐项实测
3.1 默认输出
不带任何参数,date 按系统时区的默认格式输出当前时间:
$ date
Thu Oct 15 06:28:30 UTC 2026
格式为「星期 月份 日 时:分:秒 时区 年」。本机时区为 UTC(末尾 UTC 字样),若机器配置为东八区则此处显示 CST 与本地时间。
💡 提示:date 的默认输出可用于日志留痕,但格式含空格,作为文件名或拼接进字符串时务必改用 3.2 的显式 FORMAT。
3.2 常用格式化:+FORMAT
+FORMAT 以 % 控制符定制输出,是 date 使用频率最高的能力:
$ date +%Y-%m-%d
2026-10-15
$ date +%F
2026-10-15
$ date '+%F %T'
2026-10-15 06:28:30
$ date '+%Y-%m-%d %H:%M:%S'
2026-10-15 06:28:30
$ date '+%A %B %d, %Y'
Thursday October 15, 2026
$ date '+%j 第%U周'
288 第41周
%F 等价 %Y-%m-%d,%T 等价 %H:%M:%S(帮助原文),因此第 3、4 条输出完全一致;%A/%B 输出星期与月份全名(受 locale 影响);%j 是年内第几天(288)、%U 是以周日为首的年内周数(41)。含空格的 FORMAT 必须整体加引号,否则 shell 会把空格后的内容拆成独立参数。
💡 提示:FORMAT 中想输出字面
%用%%(帮助原文:a literal %)。生成文件名推荐%F或%Y%m%d,不含空格与冒号,跨平台安全。
3.3 -d:解析相对时间与自然语言日期
-d STRING(--date)不取「现在」,而是解析 STRING 描述的时间。支持 yesterday、tomorrow、next monday、N days ago 等丰富的相对表达:
$ date -d 'yesterday' '+%F %T'
2026-10-14 06:28:30
$ date -d 'next monday' '+%F %A'
2026-10-19 Monday
$ date -d '3 days ago' '+%F %T'
2026-10-12 06:28:30
$ date -d 'tomorrow' '+%F'
2026-10-16
$ date -d '1 hour ago' '+%F %T'
2026-10-15 05:28:30
实测基准时刻是 2026-10-15(周四)06:28:30:yesterday 回到 10-14、3 days ago 回到 10-12、1 hour ago 只回退小时;next monday 算出的是下一个尚未到来的周一 10-19。-d 只负责解析,输出格式仍由 +FORMAT 决定,两者自由组合。
💡 提示:
-d 'next monday'的结果与执行时刻有关(周四执行得到 10-19,周日执行会得到更近的周一),脚本里依赖「下一个周一」做业务判断时要意识到这一点。相对时间语法全集见info date的 Date input formats 章节。
3.4 -u:以 UTC 显示
-u(--utc)按 UTC 而非本地时区显示时间。本机系统时区本就是 UTC,两者输出一致:
$ date
Thu Oct 15 06:28:30 UTC 2026
$ date -u
Thu Oct 15 06:28:30 UTC 2026
$ date '+%F %T %Z'
2026-10-15 06:28:30 UTC
在时区为东八区(CST)的机器上,date 与 date -u 会相差 8 小时;%Z 控制符把时区缩写显式打进输出,跨时区对账时建议始终带上。
💡 提示:服务器日志统一用 UTC(
date -u或TZ=UTC date)可避免夏令时与时区迁移带来的歧义,展示层再转本地时区。
3.5 epoch 时间戳互转
%s 输出自 1970-01-01 00:00:00 UTC 起的秒数(epoch);-d @秒数 把 epoch 反解析为可读时间:
$ date +%s
1792045710
$ date -d @1700000000
Tue Nov 14 22:13:20 UTC 2023
$ date -d @1700000000 '+%F %T %Z'
2023-11-14 22:13:20 UTC
$ date -d '2026-10-15 12:00:00' +%s
1792065600
第一条输出当前 epoch(1792045710);第二、三条把固定时间戳 1700000000 转为可读时间(2023-11-14 22:13:20 UTC);第四条反方向把指定时刻转成 epoch。%s 与 -d @ 一来一回,覆盖了日志时间戳、接口签名过期时间等绝大多数转换场景。
💡 提示:
-d @里的@是「epoch 秒」的标记,丢了会按普通日期串解析而报错。毫秒/微秒时间戳需先缩位成秒(或用 3.6 的%N自行拼装)。
3.6 %N:纳秒精度
%N 输出当前秒内的纳秒部分(9 位数字),可与其他控制符拼接:
$ date '+%F %T.%N'
2026-10-15 06:28:30.259442641
$ date '+%s%N'
1792045710261369174
第一条把时间精度推到纳秒(.259442641 秒);第二条 %s%N 拼出「秒 + 纳秒」的 19 位整数,是 shell 里生成唯一递增序号、测量命令耗时的常用手法(两次取值相减即纳秒级耗时)。
💡 提示:
%N是 GNU date 扩展,BusyBox date 等精简实现会原样输出字面%N(见 Q4);对耗时精度要求不高时%s配合date +%s%N已足够。
3.7 -s:设置系统时间(需 root)
-s STRING(--set)把系统时钟设为 STRING 描述的时刻,需要 root 权限。以普通用户 nobody 实测权限不足的表现:
$ id nobody
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
$ su -s /bin/sh nobody -c "date -s '2026-10-15 12:00:00'"
date: cannot set date: Operation not permitted
Thu Oct 15 12:00:00 UTC 2026
$ date
Thu Oct 15 06:28:30 UTC 2026
非 root 执行时 date 打印两行:第一行 date: cannot set date: Operation not permitted 是设置失败的报错,第二行是它试图设置的目标时间(并非设置后的结果);第三条命令再查当前时间仍是 06:28:30,证明时钟未被改动。只有 root(具备设置时钟权限的账户)执行 date -s 才会真正生效。
💡 提示:date 调整的是系统时钟(内核维护),机器断电不丢的**硬件时钟(RTC/BIOS 时钟)**由
hwclock命令管理,systemd 系统则用timedatectl统一查看与设置(含时区与 NTP 同步开关),三者分工不同,本文不展开。
四、实战示例
4.1 生成备份文件名的时间后缀
脚本里给备份/导出文件打时间戳,用不含空格与冒号的格式:
$ date +%Y-%m-%d
2026-10-15
$ date '+%F %T'
2026-10-15 06:28:30
%F(或 %Y%m%d)适合做文件名后缀;需要精确到秒的记录(如审计日志行)用 %F %T。
4.2 报表时间窗:昨天与前天
定时报表常要「取昨天整天的数据」或「回看 N 天」:
$ date -d 'yesterday' '+%F %T'
2026-10-14 06:28:30
$ date -d '3 days ago' '+%F %T'
2026-10-12 06:28:30
配合 -d 与 +FORMAT 一步得到窗口起止时间,避免手写日期算术。
4.3 epoch 与可读时间互转
排查日志时间戳、核对接口签名有效期:
$ date +%s
1792045710
$ date -d @1700000000 '+%F %T %Z'
2023-11-14 22:13:20 UTC
%s 取当前秒级时间戳;-d @ 把任意时间戳翻译成人话,一条命令搞定两个方向。
4.4 高精度计时
用 %s%N 取纳秒级「秒+纳秒」整数,两次相减即精确耗时:
$ date '+%s%N'
1792045710261369174
Shell 脚本没有内置毫秒计时器时,这是最轻量的方案(起止各取一次 date +%s%N,差值除以 1000000 即毫秒)。
五、注意事项与常见问题
Q1:date -s 报 Operation not permitted?
设置系统时钟需要 root 权限。实测以 nobody 用户执行 date -s '2026-10-15 12:00:00' 报 date: cannot set date: Operation not permitted,且时钟未被改动(见 3.7);用 root 执行同样的命令即可生效。注意报错后 date 仍会打印一行时间,那是它试图设置的目标值,不是设置结果。
Q2:date 显示的时间与本地时间差 8 小时?
时区问题。本机系统时区为 UTC(3.1 实测输出 UTC),与东八区相差 8 小时。临时按其他时区显示可用 TZ 环境变量(帮助原文示例:TZ='America/Los_Angeles' date);永久修改系统时区用 timedatectl set-timezone。
Q3:epoch 时间戳怎么转回可读时间?可读时间怎么转成秒?
正向 date +%s(见 3.5,输出 1792045710);反向 date -d @秒数(见 3.5,1700000000 转出 2023-11-14 22:13:20 UTC);任意可读时刻转秒用 date -d '2026-10-15 12:00:00' +%s(见 3.5,输出 1792065600)。注意 @ 不能省。
Q4:%N 输出一串 0 或字面 %N?
%N 是 GNU date 的纳秒控制符。本机 GNU coreutils 8.32 实测正常(3.6 输出 .259442641);若在 BusyBox 环境(如 Alpine 的精简 shell)里看到全 0 或字面 %N,是实现不支持所致,换用 GNU date 或改用 %s 秒级精度。
Q5:-d 'next monday' 每次执行结果一样吗?
不一样,-d 的相对表达以执行时刻为基准:实测在周四执行得到 2026-10-19(见 3.3),同一条命令在周日执行会得到更近的周一。需要固定窗口(如「上周一」)时用 last monday 或绝对日期 -d '2026-10-12' 这类明确表达。
六、参考链接
- GNU coreutils 官方手册(date 章节):https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html
- Date input formats(-d 语法全集):https://www.gnu.org/software/coreutils/manual/html_node/Date-input-formats.html
- 在线文档:https://www.gnu.org/software/coreutils/date
- 本机帮助:
date --help、info date、man date(Ubuntu 22.04 内置)