date 命令详解与参数实测(Ubuntu 22.04)

date 命令逐参数实测详解:默认输出与格式化(%F %T %A %j %U)、-d 相对时间、-u UTC、epoch 时间戳互转、%N 纳秒、-s 设置时间的 root 权限实测报错,全部回显在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文件管理2026/10/15

date 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 GNU date 的每一个参数——默认输出与常用格式化(%Y-%m-%d、%F %T、%A、%j、%U)、-d 相对时间解析、-u UTC、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 等)
timedatectlsystemd 统一管理时间/时区/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' 这类明确表达。

六、参考链接