# DualClock **Repository Path**: au2/dual-clock ## Basic Information - **Project Name**: DualClock - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-20 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # DualClock 使用与打包文档 一个运行在 Windows 桌面的无边框多时区时钟:同时显示多个时区的时间、公历日期、星期和**农历**,支持为不同时区分别设置闹钟,并可按时区设置**整点/半点语音报时**,可最小化到系统托盘、开机自启。 - 源码:`DualClock.py` - 打包产物:`dist\DualClock.exe`(单文件,约 22 MB,免安装 Python 即可运行) - 配置文件:`clock_config.json`(运行后自动生成在程序/exe 同目录) - 位置文件:`clock_pos.ini`(自动记忆窗口位置) --- ## 一、功能说明 ### 1. 多时区时钟 - 默认显示本机系统时区 + 一个对照时区(本机在中国大陆时默认对照纽约)。 - 每个时区一张卡片,包含: - 自定义显示名(如"北京/上海""洛杉矶") - IANA 时区名和系统时区缩写(如 CST、EDT) - 当地时间(时:分:秒,每秒刷新) - 公历日期 + 星期 - **农历**:干支年 + 生肖 + 农历月日(含闰月标记),如 `农历 丙午马年 八月初十` - 窗口尺寸随时区卡片数量自动调整,每行最多 4 个,自动换行。 - 农历按每张卡片所在时区的**当地日期**换算(跨日边界时不同卡片可能显示不同农历日期)。 ### 2. 闹钟(支持不同时区) - 可为任意时区设置闹钟,按该时区的**当地时间**触发。 - 触发时:置顶弹窗 + 蜂鸣提示音(约 2 秒),同一闹钟每天只响一次,每天自动重复。 - 闹钟可设置备注,可单独启用/停用、删除。 ### 3. 整点/半点语音报时(支持不同时区) - 可为指定时区开启报时,按该时区的**当地时间**触发,窗口隐藏时也会播报。 - **整点报时**:每小时 00 分,语音朗读"现在时间,X点整"。 - **半点报时**:每小时 30 分,语音朗读"现在时间,X点半"。 - 语音使用 Windows 自带的 **SAPI 中文女声(Microsoft Huihui)**,无需联网;可同时勾选蜂鸣提示。 - 每个时区可配置一条,支持单独启用/停用、修改、删除;设置窗口提供"试听语音"按钮。 - 同一时刻只播报一次(不会因刷新而重复朗读),每天自动循环。 ### 4. 操作方式 | 操作 | 效果 | | --- | --- | | 左键拖动窗口 | 移动位置,松手后自动保存 | | 右键 / 双击窗口 | 打开"设置"窗口 | | 托盘菜单"设置..." | 打开"设置"窗口 | | 托盘菜单"显示/隐藏窗口" | 显示或隐藏桌面时钟 | | 托盘菜单"开启/关闭开机自启" | 写入/删除注册表自启项 | | 托盘菜单"退出程序" | 完全退出 | ### 5. 设置窗口 设置窗口分为三列: - **显示时区**:从 28 个常用城市预设中添加;也可输入自定义 IANA 时区名(如 `Europe/London`);支持修改显示名、上移/下移排序、删除(至少保留一个)。 - **闹钟管理**:选择时区、设置时分、填写备注、勾选启用;可添加、启用/停用、删除。 - **整点/半点报时**:选择时区,勾选整点/半点、语音/蜂鸣、启用;可添加、修改、删除,并可"试听语音"。 - 修改后点击"保存并应用"立即生效;点"取消"放弃修改。 ### 6. 其他特性 - 单实例互斥:重复启动会提示"已经在运行中"。 - 深色主题、无边框置顶风格。 - 开机自启通过注册表 `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` 实现,注册的是当前 exe/脚本的真实路径。 --- ## 二、配置文件 clock_config.json 运行程序后自动在同目录生成,可手工编辑(修改后重新打开设置或重启程序生效)。格式: ```json { "timezones": [ { "name": "America/Los_Angeles", "label": "洛杉矶" }, { "name": "America/New_York", "label": "纽约" } ], "alarms": [ { "tz": "Asia/Shanghai", "time": "08:30", "label": "晨会", "enabled": true } ], "chimes": [ { "tz": "Asia/Shanghai", "hourly": true, "half": true, "voice": true, "beep": false, "enabled": true } ] } ``` 字段说明: | 字段 | 含义 | | --- | --- | | `timezones[].name` | IANA 时区名,如 `Asia/Shanghai`、`Europe/London`、`America/New_York` | | `timezones[].label` | 卡片上显示的名称 | | `alarms[].tz` | 闹钟所属时区(IANA 名) | | `alarms[].time` | 触发时间,24 小时制 `HH:MM`,按所选时区的当地时间 | | `alarms[].label` | 闹钟备注,可为空 | | `alarms[].enabled` | 是否启用 | | `chimes[].tz` | 报时所属时区(IANA 名),每个时区一条 | | `chimes[].hourly` | 是否整点报时(每小时 00 分) | | `chimes[].half` | 是否半点报时(每小时 30 分) | | `chimes[].voice` | 是否语音播报(SAPI 中文女声) | | `chimes[].beep` | 是否同时蜂鸣提示 | | `chimes[].enabled` | 是否启用 | > 配置文件损坏时程序会自动将其备份为 `clock_config.json.bad` 并重建默认配置。 --- ## 三、直接运行源码 ### 环境要求 - Windows 10/11,64 位 - Python 3.10 及以上(打包使用的是 Python 3.14.6) ### 安装依赖 ```powershell python -m pip install tzdata lunardate pystray pillow pywin32 ``` | 依赖 | 用途 | | --- | --- | | `tzdata` | Windows 上 `zoneinfo` 所需的 IANA 时区数据(含夏令时规则) | | `lunardate` | 农历换算(内置 1900–2100 真实历法数据) | | `pystray` | 系统托盘图标与菜单 | | `pillow` | 托盘图标绘制 | | `pywin32` | 调用 Windows SAPI 语音(整点/半点语音报时) | | `tkinter` | GUI(Windows 官方 Python 安装包自带,无需单独安装) | ### 运行 ```powershell python DualClock.py ``` --- ## 四、打包为 exe(PyInstaller) ### 1. 固定解释器并安装打包工具 务必使用**同一个 Python 解释器**完成"装依赖 → 打包",避免多 Python 环境串用: ```powershell # 确认解释器路径(示例输出 C:\Python314\python.exe) python -c "import sys; print(sys.executable)" python -m pip install pyinstaller python -m pip install tzdata lunardate pystray pillow pywin32 ``` ### 2.(可选)生成应用图标 项目当前的 `clock.ico` 可用下面的脚本重新生成,保存为 `_make_icon.py` 后执行: ```python # -*- coding: utf-8 -*- from PIL import Image, ImageDraw import math S = 256 img = Image.new("RGBA", (S, S), (18, 18, 20, 255)) d = ImageDraw.Draw(img) m = 26 d.ellipse([m, m, S - m, S - m], outline=(247, 248, 250, 255), width=12) cx = cy = S // 2 d.line([cx, m + 14, cx, m + 38], fill=(247, 248, 250, 255), width=8) a = math.radians(-120) d.line([cx, cy, cx + int(56 * math.cos(a)), cy + int(56 * math.sin(a))], fill=(247, 248, 250, 255), width=14) a = math.radians(-30) d.line([cx, cy, cx + int(82 * math.cos(a)), cy + int(82 * math.sin(a))], fill=(122, 162, 255, 255), width=10) d.ellipse([cx - 12, cy - 12, cx + 12, cy + 12], fill=(247, 248, 250, 255)) sizes = [16, 24, 32, 48, 64, 128, 256] icons = [img.resize((s, s), Image.LANCZOS) for s in sizes] icons[0].save("clock.ico", sizes=[(s, s) for s in sizes], append_images=icons[1:]) print("clock.ico 已生成") ``` ```powershell python _make_icon.py ``` ### 3. 执行打包(单文件 onefile) 在 `DualClock.py` 所在目录(`D:\Users\SafeFolder\dual-clock`)打开 PowerShell: ```powershell python -m PyInstaller ` --noconfirm --onefile --windowed ` --name DualClock ` --icon clock.ico ` --collect-all tzdata ` --collect-all pystray ` --collect-all pywin32 ` --collect-submodules lunardate ` DualClock.py ``` 写成单行: ```powershell python -m PyInstaller --noconfirm --onefile --windowed --name DualClock --icon clock.ico --collect-all tzdata --collect-all pystray --collect-all pywin32 --collect-submodules lunardate DualClock.py ``` 参数说明: | 参数 | 作用 | | --- | --- | | `--onefile` | 打包成单个 exe(首次启动会解压到临时目录,稍慢 1~2 秒) | | `--windowed` | GUI 程序,不弹黑色控制台窗口 | | `--name DualClock` | 输出文件名 `DualClock.exe` | | `--icon clock.ico` | 嵌入应用图标 | | `--collect-all tzdata` | **关键**:把 tzdata 的全部时区数据文件打入 exe | | `--collect-all pystray` | 收集 pystray 各平台后端,避免托盘动态导入失败 | | `--collect-all pywin32` | **关键**:收集 pywin32 的 DLL 和 COM 组件,保证打包后语音可用 | | `--collect-submodules lunardate` | 确保农历库子模块齐全 | | `--noconfirm` | 覆盖旧产物时不询问 | ### 4. 产物与验证 ``` D:\Users\SafeFolder\dual-clock\ ├─ dist\ │ ├─ DualClock.exe ← 最终可执行文件(约 22 MB) │ ├─ clock_config.json ← 首次运行后自动生成 │ └─ clock_pos.ini ← 窗口位置(运行拖动后生成) ├─ build\ ← 中间文件,可删 └─ DualClock.spec ← 打包配置,可删(保留便于下次复用) ``` 验证 exe 是否正常(运行 7 秒后结束): ```powershell $p = Start-Process ".\dist\DualClock.exe" -PassThru Start-Sleep -Seconds 7 if ($p.HasExited) { "异常退出,ExitCode=$($p.ExitCode)" } else { "运行正常 PID=$($p.Id)"; Stop-Process -Id $p.Id -Force } ``` ### 5. 清理中间文件 ```powershell Remove-Item -Recurse -Force .\build, .\DualClock.spec ``` ### 6. 分发 - 只拷贝 `dist\DualClock.exe` 即可,目标机器无需安装 Python;首次运行自动生成配置。 - 如需带上已配置好的时区/闹钟/报时,把 `clock_config.json` 与 exe 放在**同一目录**一起拷贝。 - 语音报时依赖 Windows 自带 SAPI(Win10/11 中文系统默认含 Huihui 语音),无需额外安装。 - 若移动了 exe 位置,在托盘菜单重新点一次"开启开机自启"以更新注册路径。 --- ## 五、常见问题 **Q:双击 exe 后时间/时区正常,但显示"未安装农历库"?** 说明 `lunardate` 没被正确收集,按上面的命令加 `--collect-submodules lunardate` 重新打包。 **Q:卡片显示"⚠ 无效时区"?** `clock_config.json` 中的时区名写错或不在 tzdata 中。改成有效的 IANA 名称(参考 [https://www.iana.org/time-zones](https://www.iana.org/time-zones))后重启程序。 **Q:打包后的 exe 到别的电脑上启动报错或时间不对?** 确认打包时带了 `--collect-all tzdata`;时间以目标机系统时钟为准,确保目标机时间和时区设置正确。 **Q:闹钟没响?** 检查:① 闹钟是否勾选启用;② 设置的是该时区的当地时间;③ 程序是否仍在运行(查看托盘区是否有图标)。 **Q:到了整点/半点没有语音报时?** 检查:① 报时条目是否勾选"启用";② 是否勾选了整点/半点和"语音播报";③ 系统音量是否开启。可在设置窗口点"试听语音"快速验证。 **Q:点"试听语音"没声音,或打包后的 exe 无法语音报时?** 源码运行时确认已安装 pywin32(`pip install pywin32`);打包时确认带了 `--collect-all pywin32`。可用 `python -c "import win32com.client"` 验证环境。目标电脑缺少中文语音时会静默跳过,可在"设置 → 时间和语言 → 语音"中添加中文语音包。 **Q:如何查看开机自启是否设置成功?** 打开"注册表编辑器",查看 `HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run` 下是否有 `DualClockDesktopClock` 项。 **Q:单文件 exe 启动慢?** 正常现象,onefile 模式需先解压到 `%TEMP%` 目录。若追求秒开,可把 `--onefile` 改为 `--onedir`(分发时拷贝整个文件夹)。 --- ## 六、版本与打包记录 | 项目 | 内容 | | --- | --- | | 开发/打包系统 | Windows(64 位) | | Python | 3.14.6(C:\Python314) | | PyInstaller | 6.22.2 | | tzdata | 2026.4 | | lunardate | 0.3.0 | | pystray | 0.19.5 | | pillow | 12.3.0 | | pywin32 | 312(Windows SAPI 语音报时) | | 打包产物 | dist\DualClock.exe,约 22.3 MB | | 文档更新日期 | 2026-09-19 |