# 时钟 `clock/*` 是 TCL 风格的日期和时间集合。跨越命名空间边界的每个值都是数字:epoch 秒是通用货币(`format`、`scan` 和 `add` 都接收或返回它),而 `clock/format` / `clock/scan` 是由同一张 strptime 风格说明符表驱动的严格对偶。`clock/clicks` 是例外——一个单调纳秒计数器,只有作为两次采样之间的差值才有意义。所有函数都注册在每个宿主中,无需导入。 ## 函数 | 函数 | 用途 | |---|---| | `clock/seconds` | 当前墙上时钟时间,以 Unix epoch 以来的整数秒表示 | | `clock/millis` | 当前墙上时钟时间,以 epoch 毫秒表示 | | `clock/micros` | 当前墙上时钟时间,以 epoch 微秒表示 | | `clock/clicks` | 高分辨率单调时间戳,单位为纳秒(不以 epoch 为基准) | | `clock/format time ?format? ?timezone?` | 将 epoch 秒格式化为字符串;spec-map 形式 `%{ :format :timezone :locale }` | | `clock/scan str %{ :format ... }` | 将字符串解析为 epoch 秒;`:format` 必填 | | `clock/add time n :unit ...` | 日历感知的日期运算;spec-map 形式 `%{ :days n :months n :timezone ... }` | 墙上时钟与单调时钟: - `clock/seconds`、`clock/millis` 和 `clock/micros` 读取系统墙上时钟。当时钟被调整时,它们可能向后跳变,因此不适合测量持续时间。 - `clock/clicks` 读取单调计数器。其原点未指定,且可能因运行和进程而异——只有两次读数之间的差值才有意义。用它来测量耗时和性能分析。 格式化与解析: - `clock/format` 默认为 `"%Y-%m-%dT%H:%M:%S%z"`(ISO-8601)和本地时区。时区可以是 `"UTC"`、`"local"`,或带符号的 `+HHMM` / `+HHMMSS` 偏移量。 - 两个函数共用一张说明符表——`%Y %m %d %H %M %S %j %u %A %B %z` 等等,外加复合说明符 `%T %R %D %F %r %+`。 - `clock/scan` 刻意严格:不支持自由格式解析,且 `:format` 是必需的。缺失的时刻字段解析为午夜;缺失的日期字段回退到 `:base`(默认:当前时间);输入中的 `%z` 覆盖 `:timezone` 选项。格式错误的输入返回 `%Err{:message}`。 日历运算: - 单位有 `:second :minute :hour :day :week :month :year`;位置增量从左到右应用。`:second`/`:minute`/`:hour` 将固定时长直接加到 epoch 值上。 - `:day` 和 `:week` 保持墙上时钟:`clock/add` 转换为 `:timezone` 中的分解时间,加上天数,再转换回来。 - `:month` 和 `:year` 是日历运算,将日期钳制到目标月份的最后一天(1 月 31 日 + 1 个月变为 2 月 28/29 日)。 - `clock/add` 在 `:timezone`(默认:`"local"`)中解释日历单位。用 spec-map 形式传入时区,使运算与你用 `clock/scan` 构建时间戳时处于同一时区。 ## 示例 ### 读取墙上时钟
set now [clock/seconds]
echo [clock/format $now]                            # ISO-8601, local tz
echo [clock/format $now "%Y-%m-%d %H:%M:%S" "UTC"]
echo [clock/format 0 "%A, %B %d %Y" "UTC"]          # Thursday, January 01 1970
echo [clock/millis]                                 # epoch milliseconds
### 解析与日历运算
set t [clock/scan "2024-01-31 14:30:00"
       %{ :format "%Y-%m-%d %H:%M:%S" :timezone "UTC" }]

# Month-end clamping, using the same timezone for the arithmetic:
echo [clock/format [clock/add $t %{ :months 1 :timezone "UTC" }] "%F" "UTC"]
# => "2024-02-29"

# Fixed-duration units add to the epoch value directly:
echo [clock/format [clock/add $t 26 :hours] "%F %T" "UTC"]
# => "2024-02-01 16:30:00"
### 用单调时钟测量耗时
set start [clock/clicks]
# ... work ...
set elapsed-ns ([clock/clicks] - $start)
echo "took" ($elapsed-ns / 1000000) "ms"
## 另见 - 并发 — `sleep`、`after` 和定时器调度 - 日志 — 日志记录携带毫秒 epoch 时间戳