WezTerm Lua 配置中的时间模块:wezterm.time.now()与Time对象完全指南
【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm
wezterm.time是 WezTerm 在 Lua 配置体系中提供的时间处理模块,其中wezterm.time.now()是获取当前时刻快照的入口,它返回一个内部以 UTC 追踪的Time对象,供后续格式化、解析与按时刻动态调整配置使用。本文以wezterm.time.now()为核心,完整覆盖该模块的函数与Time对象的全部方法,并结合仓库源码说明其底层实现,帮助你写出按时间自动变化的配色、定时刷新配置等实战配置。
wezterm.time模块概览
wezterm.time模块自版本20220807-113146-c2fee766起随 WezTerm 一起提供,它在 Lua 侧暴露了一组与时间打交道的能力:获取当前时间、解析时间字符串、格式化时间、以及延时调度回调。模块的完整函数清单见 模块索引,包括:
| 函数 | 作用 |
|---|---|
wezterm.time.now() | 返回一个表示当前调用时刻的Time对象 |
wezterm.time.parse(str, format) | 按给定格式字符串解析时间文本,返回Time对象 |
wezterm.time.parse_rfc3339(str) | 按 RFC 3339 格式解析时间文本,返回Time对象 |
wezterm.time.call_after(interval_seconds, function) | 在指定秒数后调用回调函数 |
这些函数在 Lua 配置文件中通过require 'wezterm'之后即可使用,无需额外引入包。
wezterm.time.now():获取当前时刻
wezterm.time.now()的语义非常简单且直白:返回一个 Time 对象,该对象表示wezterm.time.now()被调用那一刻的时间。它在配置文件中调用一次就固定住"当时"的时间,不会随着后续时间的流逝而变化,因此如果你需要在多个地方使用同一个时间基准(例如同时格式化本地时间与 UTC 时间做对比),应当先把它保存到一个局部变量中。
从源码看,该函数在 lua-api-crates/time-funcs/src/lib.rs 中注册,其实现直接调用了 Rust 侧的时间来源:
time_mod.set( "now", lua.create_function(|_, _: ()| Ok(Time { utc: Utc::now() }))?, )?;可以看到,now()底层就是chronocrate 的Utc::now(),返回的Time结构体内部只保存了一个DateTime<Utc>字段。这意味着无论你本地时区是什么,Time对象内部一律以 UTC 为唯一事实来源,本地时间只是在展示/格式化阶段才进行转换。
Time对象:内部以 UTC 追踪的时刻
所有时间函数最终都会产出Time对象。官方文档对它的描述是:"表示一个内部以 UTC 追踪的日期与时间"。
Time对象的__tostring元方法被实现为输出其内部 UTC 表示,见 time-funcs/src/lib.rs:
methods.add_meta_method(MetaMethod::ToString, |_, this, _: ()| { let utc = this.utc.to_rfc3339(); Ok(format!("Time(utc: {utc})")) });因此,在 Lua 命令行或配置中对Time对象调用tostring(),会得到类似下面的输出(其中时间部分为内部 UTC 时间,与你所在的本地时区可能不同):
Time(utc: 2022-07-17T18:14:15.000+00:00)Time对象提供了三个方法:
- Time:format(format):按格式字符串输出该时刻的本地时间表示;
- Time:format_utc(format):按格式字符串输出该时刻的UTC 时间表示;
- Time:sun_times(lat, lon):根据该时刻的日期与时间分量,计算指定经纬度的日出日落信息。
格式化:Time:format()与Time:format_utc()
format使用时刻的本地时区表示进行格式化,format_utc则固定使用 UTC 表示。二者对格式字符串的支持范围相同(格式占位符体系由底层 chrono crate 的 strftime 风格格式提供,常用的%Y、%m、%d、%H、%M、%S等占位符均可直接使用)。
文档给出的对比示例很直观——同一时刻在 UTC+7 时区下的本地格式化与 UTC 格式化相差 7 小时:
> wezterm.time.now():format("%Y-%m-%d %H:%M:%S") "2022-07-17 11:14:15" > wezterm.time.now():format_utc("%Y-%m-%d %H:%M:%S") "2022-07-17 18:14:15"注意上面两次调用now()产生的是两个几乎相同但不同的时刻对象,实际使用时建议复用同一个Time变量以保证基准一致。从源码看,format的实现先把内部 UTC 时间转换为Local再格式化,而format_utc直接对内部 UTC 值做格式化(见 time-funcs/src/lib.rs):
methods.add_method("format", |_, this, format: String| { let local: DateTime<Local> = this.utc.into(); Ok(local.format(&format).to_string()) }); methods.add_method("format_utc", |_, this, format: String| { Ok(this.utc.format(&format).to_string()) });这解释了为什么两者输出不同:format多了一次 UTC → 本地时区的转换。
日出日落:Time:sun_times(lat, lon)
sun_times(lat, lon)是wezterm.time模块中最有"创意"的能力:针对Time对象中携带的日期与时间,计算给定经纬度的日出(rise)与日落(set)时刻,并判断当前时间是否处于白天。它返回一个 Lua table,包含四个字段:
rise:日出时刻的Time对象(UTC);set:日落时刻的Time对象(UTC);up:布尔值,当前时刻太阳是否在地平线以上;progression:浮点数(0.0 ~ 1.0),当前时刻在白天(up == true时)或夜晚(up == false时)进程中的进度比例。
文档中给出的示例是计算美国凤凰城(北纬 33.44,西经 112)的时刻信息:
> wezterm.time.now():sun_times(33.44, -112) { "progression": 0.41843971631205673, "rise": "Time(utc: 2022-07-17T12:29:42.493449687+00:00)", "set": "Time(utc: 2022-07-18T02:36:40.776247739+00:00)", "up": true, }这个结果表示当时太阳正处于白昼,且已经走过了白天时长的约 41%(progression ≈ 0.418)。如果调用时太阳已落山,则up == false,此时progression表示夜间时长的进度比例。
源码中progression的计算逻辑很清晰(见 time-funcs/src/lib.rs):以rise与set之间为白天时长、其余为夜间时长,把当前时刻在对应区段内的位置按分钟折算成比例。日出前、白天、日落后三种情况分别计算。
还有一个特殊的边界情况:如果经纬度位于两极,可能出现白昼或黑夜连续超过 24 小时。此时rise与set均为nil,progression为0,up直接表示处于极昼(true)还是极夜(false)。这一分支在源码中对应spa::calc_sunrise_and_set返回的PolarDay/PolarNight枚举(见 time-funcs/src/lib.rs)。
官方文档特别点明了该方法的用途:如果你希望根据一天中的时段变化来切换配色方案或其他配置,sun_times提供的信息正是为此设计的——不需要硬编码日落日出时刻,而是让 WezTerm 根据地理坐标自动计算。
与其他时间函数的配合使用
虽然now()是最常用的入口,但wezterm.time模块的价值在于整套函数可以互相配合。理解它们有助于你把now()用得更顺手。
解析时间字符串
wezterm.time.parse(str, format) 按照显式给定的格式字符串解析时间文本。文档示例:
> wezterm.time.parse("1983 Apr 13 12:09:14.274 +0000", "%Y %b %d %H:%M:%S%.3f %z") "Time(utc: 1983-04-13T12:09:14.274+00:00)"这里%b是英文月份缩写,%.3f是毫秒级小数秒,%z是时区偏移。格式字符串支持 chrono crate 的 strftime 风格占位符体系。其源码实现(见 time-funcs/src/lib.rs)先调用DateTime::parse_from_str,成功后再把解析结果统一转换为内部 UTC 存储。
wezterm.time.parse_rfc3339(str) 则直接按 RFC 3339 时间格式解析,例如"2022-07-17T18:14:15+00:00"这类带时区偏移的 ISO 风格字符串。如果输入字符串无法按 RFC 3339 解析,会直接抛出 Lua 错误(源码见 time-funcs/src/lib.rs)。
parse与parse_rfc3339都返回标准的Time对象,因此解析结果同样可以调用format、format_utc、sun_times等方法,实现了"任意来源的时间 → 统一Time对象"的设计。
定时调度:wezterm.time.call_after()
wezterm.time.call_after(interval_seconds, function) 用于在指定秒数之后调用回调函数,常与now()搭配实现"周期性刷新配置"。自版本20230320-124340-559cb7b0起,interval_seconds支持小数秒,可以进行更精确的延时。
官方文档给出的经典示例是根据"当前时刻是小时内的第几分钟"动态生成背景色,并借助call_after每分钟刷新一次配置:
local wezterm = require 'wezterm' -- Reload the configuration every minute wezterm.time.call_after(60, function() wezterm.reload_configuration() end) local amount = math.ceil((tonumber(wezterm.time.now():format '%M') / 60) * 255) return { colors = { background = 'rgb(' .. amount .. ',' .. amount .. ',' .. amount .. ')', }, }这段配置的工作流程是:配置文件加载时调用一次now(),取出当前分钟数%M(0~59),映射到 0~255 得到灰度值,作为背景色写入colors.background;同时用call_after(60, ...)安排一个 60 秒后的回调,回调里调用 wezterm.reload_configuration() 让配置重新加载,从而在下一次加载时得到新的分钟数——如此循环往复,实现背景色每分钟变化一次。
需要特别注意的是,官方文档在该示例后附了一段明确的警告:能力越大责任越大。如果你调度了大量频繁的回调,或者频繁地这样重载配置,会增加系统 CPU 负载,因为这是让计算机做更多的工作。此外,wezterm.reload_configuration() 的文档还强调:如果在配置文件的顶层(文件作用域)直接调用它会造成无限循环,使 WezTerm 失去响应,它应当只在事件或定时器回调中使用。
从源码层面看,call_after的实现要复杂得多(见 time-funcs/src/lib.rs):回调会被包装为事件 ID,与延时一起封装成ScheduledEvent,通过 promise 运行时调度;在配置重载时,WezTerm 会把所有已注册的定时事件用"配置代数(generation)"标记,当定时器到期后,如果当前配置代数与注册时不一致,就跳过执行,从而避免配置重载导致回调按 2 倍、4 倍指数级重复累积(见 time-funcs/src/lib.rs 的注释与实现)。这一机制保证了"定时刷新配置"模式在实际高频重载下是安全且受控的。
实战:按昼夜自动切换配色方案
综合以上 API,一个实用的落地场景是:用sun_times判断当前是否处于白天,再决定采用亮色还是暗色配色,同时用call_after定时重载配置以保证配色随日出日落自动切换。示例框架如下:
local wezterm = require 'wezterm' -- 每 5 分钟检查一次,让昼夜切换及时生效 wezterm.time.call_after(300, function() wezterm.reload_configuration() end) local t = wezterm.time.now() -- 以北京为例:北纬 39.9,东经 116.4 local sun = t:sun_times(39.9, 116.4) local scheme if sun.up then scheme = 'One Light' -- 白天用亮色 else scheme = 'One Dark' -- 夜晚用暗色 end return { color_scheme = scheme, }说明几点:
sun_times的经纬度请按你自己的实际位置填写,数值可参考公开的地理坐标资料;- 定时器间隔请根据你对"切换及时性"与"CPU 开销"的权衡设置,官方建议不要过于频繁;
- 该方案完全由 WezTerm 自身计算日出日落,无需依赖外部服务或硬编码昼夜时刻。
如果你想按分钟粒度(而不是昼夜粒度)做更细的动态调整,now():format '%M'这类分钟提取手法(配合 Time:format())就是官方示例所展示的路径。
小结
wezterm.time.now()看似只是一个取时间的函数,但它是整个wezterm.time模块的起点:它产出的Time对象内部以 UTC 为准,统一支撑本地/UTC 两种格式化输出,也能直接参与日出日落计算;与parse/parse_rfc3339(把外部时间文本纳入同一体系)以及call_after(定时驱动配置重载)组合,就构成了 WezTerm 配置"随时间变化"的完整能力闭环。底层实现集中在 lua-api-crates/time-funcs/src/lib.rs,其"UTC 存储 + 展示时转换"和"配置代数防重复调度"两个设计细节,值得在阅读源码时重点关注。相关函数的完整说明与更多示例可继续查阅 wezterm.time 模块索引。
【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考