不动系统时钟,让 Windows 应用在任意日期运行
把某个应用的时钟调到明年、让它停住,或者加速运转,让 30 天的试用期在你泡咖啡的工夫里到期。机器上的其他部分仍然使用真实时间——域登录、证书和其他所有程序都照常工作。
然后它会告诉你,这次替换是否真的生效了。
免费开源,GPL-3.0 便携版或安装版 运行无需管理员权限 从不连接互联网
一次会话的样子
23:59:50
18:12:33
为什么需要它
测试任何与日期相关的功能,都得拨动时间。常见的两种做法都不好。
许可证到期、试用期、订阅续费、证书有效期、令牌寿命、月末与年末报表、利息计提、提醒。
做法一:修改系统时钟
它会破坏域登录和 Kerberos,让 TLS 证书失效、浏览器无法使用,扰乱 Windows 更新,还会让这台机器上其他所有应用写出错误的时间戳。在加入域的机器上,组策略通常会直接禁止修改,或者几分钟后又把时间改回去,于是测试连重复执行都做不到。
做法二:等
也就是说:不测。与日期相关的用例就这样被跳过,“许可证永不过期”的版本也就这样交到了客户手里。
它能做什么
只有一个进程穿越时间,机器上的其他一切都不受影响。
任意时刻
一个具体的日期和时间,或者一个相对的时间——+30 days、-1 year。
流动、冻结或加速
正常速度、停住的时钟,或者一个整数倍率。x1440 让一天只需一分钟。
独立的时区
只对该进程生效的固定偏移量,系统时区则原封不动。
子进程一并跟随
安装程序和启动器都会派生子进程。没有这一点,测试只覆盖了实际运行内容的一半。
会话中途跳转
向前或向后都可以——包括笔记本与时间服务器重新同步后发生的那种向后跳变。
同样支持 Electron 和 Chromium
通过另一种机制实现,因为它们的时钟位于沙盒渲染进程中,注入够不到那里。
别人都没做的部分
你怎么知道它生效了?
用其他任何工具,你都无从知道。应用启动了,显示出某个日期,而你只能假定一切正常。可它也许是通过工具从未拦截的通道读取时钟的——来自服务器、来自数据库、来自某个运行时层——到那时,“测试通过”就毫无意义。
- →在真正的测试开始之前就给出判定:生效 / 部分生效 / 未生效
- →在 44 个时间通道中,哪些已被覆盖,应用对每个通道各查询了多少次
- →哪些通道没有被覆盖——如实写明,绝不省略
- →附带后果说明的警告:“该应用会从网络读取时间——仅做本地替换可能不够”
两分钟上手
用窗口来探索,用命令行跑 CI。两者背后是同一个引擎。
# 让应用以 2027 年的最后一秒来运行 chrono run "C:\apps\test.exe" --at 2027-12-31T23:59:59 # 在你泡咖啡时看着 30 天试用期到期:x1440 就是一分钟一天 chrono run "C:\apps\test.exe" --mode x1440 # 用命名场景代替日期,并把证据写入文件 chrono run "C:\apps\test.exe" --preset year-rollover --report session.txt
计算器回答日期测试的另一半——该用哪个日期:
$ chrono calc --preset year-2038 --zone +00:00 Chrono Mock - date calculator preset: year-2038 - 2038 boundary explains: Does the app survive the 32-bit Unix time boundary (2038-01-19T03:14:07Z)? base: 2038-01-19T03:14:07 result: 2038-01-19T03:14:07 formats: ISO date 2038-01-19 ISO datetime 2038-01-19T03:14:07+00:00 US 01/19/2038 PL 19.01.2038 epoch (s) 2147483647 epoch (ms) 2147483647000 FILETIME 137919572470000000 RFC 1123 Tue, 19 Jan 2038 03:14:07 GMT ... what this date lands on: at or past the 2038-01-19T03:14:07Z 32-bit time_t limit (Y2038)
与你可能正在用的工具对比
像 RunAsDate,但补上了缺失的部分
RunAsDate 拦截五个挂钟时间函数,并且做得很好。下面是两者的差异——完整页面还会说明 RunAsDate 在哪些情况下仍是更好的选择。
| RunAsDate | Chrono Mock | |
|---|---|---|
| 让一个应用以虚拟日期运行 | 是 | 是 |
| 被拦截的时间通道 | 5 | 44(30 个被偏移,14 个仅计数) |
| 加快时钟 | 否 | 是 |
| 独立的时区 | 文档中未提及 | 是 |
| 跟随子进程 | 文档中未提及 | 是 |
| 告诉你是否生效 | 否 | 是,逐个通道 |
| 可获取源代码 | 免费软件,闭源 | GPL-3.0 |
获取
解压到任意位置即可运行,也可以安装已签名的 .msi,供这台计算机上的每个账户使用。运行不需要管理员权限,zip 包也不会向注册表写入任何内容。