欢迎加入开源鸿蒙PC社区:
atomgit仓库地址: https://atomgit.com/ai_lingshi/time24


一、项目概述
在全球化时代,跨时区协作已成为日常工作的常态。无论是远程办公、跨国会议还是全球化业务运营,了解不同时区的时间都至关重要。本文将详细介绍如何基于 Electron 运行时开发一款全球24时区时间表应用,该应用可以运行在 HarmonyOS 桌面环境中。
1.1 项目背景
随着远程工作和全球化协作的普及,人们需要一款直观、美观的时区查看工具。传统的时区转换工具往往功能单一、界面简陋,难以满足现代办公需求。本项目旨在打造一款功能丰富、视觉精美的24时区时间表应用。
1.2 功能定位
- 实时时间显示:全球24个时区的实时时间展示
- 智能标识:自动识别本地时区并高亮显示
- 时段标记:区分工作时间和午夜时段
- 视觉美观:采用现代UI设计风格
1.3 技术架构
┌─────────────────────────────────────────────────────────────┐
│ 前端应用层 │
│ (HTML5 + CSS3 + JavaScript) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ index.html │ │ style.css │ │ app.js │ │
│ │ (结构层) │ │ (样式层) │ │ (逻辑层) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Electron + Preload 层 │
│ (IPC 通信、API 暴露) │
├─────────────────────────────────────────────────────────────┤
│ HarmonyOS 原生层 │
│ (libadapter.so + ETS Adapters) │
└─────────────────────────────────────────────────────────────┘
二、核心功能实现
2.1 时区数据结构设计
应用的核心是时区数据,我们需要定义包含时区名称、UTC偏移量和代表城市的数据结构:
javascript
const timezones = [
{ name: '国际日期变更线', offset: -12, cities: ['中途岛', '萨摩亚'] },
{ name: '萨摩亚标准时间', offset: -11, cities: ['美属萨摩亚'] },
{ name: '夏威夷-阿留申标准时间', offset: -10, cities: ['檀香山'] },
{ name: '阿拉斯加标准时间', offset: -9, cities: ['安克雷奇'] },
{ name: '太平洋标准时间', offset: -8, cities: ['洛杉矶', '旧金山', '西雅图'] },
{ name: '山地标准时间', offset: -7, cities: ['丹佛', '凤凰城'] },
{ name: '中部标准时间', offset: -6, cities: ['芝加哥', '休斯顿', '达拉斯'] },
{ name: '东部标准时间', offset: -5, cities: ['纽约', '华盛顿', '波士顿'] },
{ name: '大西洋标准时间', offset: -4, cities: ['波多黎各', '百慕大'] },
{ name: '南美洲东部时间', offset: -3, cities: ['圣保罗', '布宜诺斯艾利斯'] },
{ name: '南乔治亚时间', offset: -2, cities: ['南乔治亚岛'] },
{ name: '亚速尔群岛时间', offset: -1, cities: ['亚速尔群岛'] },
{ name: '格林威治标准时间', offset: 0, cities: ['伦敦', '都柏林', '里斯本'] },
{ name: '中欧标准时间', offset: 1, cities: ['柏林', '巴黎', '罗马', '马德里'] },
{ name: '东欧标准时间', offset: 2, cities: ['莫斯科', '开罗', '雅典'] },
{ name: '东非标准时间', offset: 3, cities: ['内罗毕', '巴格达', '利雅得'] },
{ name: '阿拉伯标准时间', offset: 4, cities: ['迪拜', '阿布扎比'] },
{ name: '巴基斯坦标准时间', offset: 5, cities: ['伊斯兰堡', '卡拉奇'] },
{ name: '孟加拉国标准时间', offset: 6, cities: ['达卡'] },
{ name: '印度支那时间', offset: 7, cities: ['曼谷', '河内', '雅加达'] },
{ name: '中国标准时间', offset: 8, cities: ['北京', '上海', '香港', '台北'] },
{ name: '日本标准时间', offset: 9, cities: ['东京', '首尔', '大阪'] },
{ name: '澳大利亚东部标准时间', offset: 10, cities: ['悉尼', '墨尔本', '布里斯班'] },
{ name: '新西兰标准时间', offset: 12, cities: ['奥克兰', '惠灵顿'] }
];
设计要点:
- 覆盖UTC-12到UTC+12的完整时区范围
- 每个时区包含名称、偏移量和代表城市列表
- 数据结构简洁清晰,便于扩展和维护
2.2 时间计算核心函数
2.2.1 UTC时间转换函数
javascript
function getTimezoneDate(offset) {
const now = new Date();
const utc = now.getTime() + now.getTimezoneOffset() * 60000;
return new Date(utc + offset * 3600000);
}
实现原理:
- 获取当前本地时间
- 将本地时间转换为UTC时间(通过
getTimezoneOffset()获取本地时区与UTC的分钟差) - 根据目标时区的偏移量计算目标时区时间
2.2.2 本地时区检测函数
javascript
function isLocalTimezone(offset) {
const localOffset = -new Date().getTimezoneOffset() / 60;
return offset === localOffset;
}
实现原理:
getTimezoneOffset()返回本地时间与UTC的分钟差(东时区为负,西时区为正)- 取负值并除以60得到小时偏移量
- 与目标时区偏移量比较判断是否为本地时区
2.2.3 时段判断函数
javascript
function isWorkingHours(hour) {
return hour >= 9 && hour < 18;
}
function isPastMidnight(hour) {
return hour >= 0 && hour < 6;
}
设计逻辑:
- 工作时间定义为9:00-18:00
- 午夜时段定义为0:00-6:00
- 通过简单的小时判断实现时段分类
2.3 动态卡片生成机制
javascript
function createTimezoneCard(timezone) {
const date = getTimezoneDate(timezone.offset);
const hour = date.getHours();
const isLocal = isLocalTimezone(timezone.offset);
const isWorking = isWorkingHours(hour);
const isNight = isPastMidnight(hour);
let cardClass = 'timezone-card';
if (isLocal) cardClass += ' local';
else if (isNight) cardClass += ' past-midnight';
else if (isWorking) cardClass += ' working-hours';
const timeBlocks = getTimeBlocks(hour);
return `
<div class="${cardClass}">
<div class="timezone-info">
<span class="timezone-name">${timezone.name}</span>
<span class="timezone-offset">${formatOffset(timezone.offset)}</span>
</div>
<div class="time-display">${formatTime(date)}</div>
<div class="date-display">${formatDate(date)}</div>
<div class="location-info">
<i>📍</i>
<span>${timezone.cities.join(', ')}</span>
</div>
<div class="time-indicator">
${timeBlocks.map((active, index) =>
`<div class="time-block${active ? ' active' : ''}" title="${index}:00"></div>`
).join('')}
</div>
</div>
`;
}
核心流程:
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 获取时区时间 | 调用 getTimezoneDate() 计算目标时区当前时间 |
| 2 | 判断时段类型 | 根据小时判断是否为工作时间或午夜时段 |
| 3 | 构建CSS类名 | 根据本地时区、工作时间、午夜时段添加对应类名 |
| 4 | 生成时间块 | 创建24小时指示器 |
| 5 | 返回HTML模板 | 拼接完整的卡片HTML字符串 |
2.4 实时更新机制
javascript
function updateTime() {
const grid = document.getElementById('timezoneGrid');
grid.innerHTML = timezones.map(createTimezoneCard).join('');
const localDate = new Date();
document.getElementById('localDateTime').textContent =
`本地时间: ${formatTime(localDate)} ${formatDate(localDate)}`;
}
updateTime();
setInterval(updateTime, 1000);
实现策略:
- 初始化时立即执行一次
updateTime() - 使用
setInterval()每秒更新一次时间 - 更新时重新生成所有时区卡片,确保时间实时同步
三、视觉设计与样式实现
3.1 整体视觉风格
应用采用深色主题设计,配合现代玻璃态效果:
css
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
min-height: 100vh;
color: #fff;
}
设计特点:
- 深蓝到紫色的渐变背景
- 现代无衬线字体
- 白色文字确保可读性
3.2 卡片布局设计
css
.timezone-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border-radius: 12px;
padding: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.timezone-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 40px rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.3);
}
视觉效果:
- 玻璃态背景(
backdrop-filter: blur()) - 半透明边框
- 悬停时上浮效果
- 紫色光晕阴影
3.3 智能标识样式
css
.timezone-card.local {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.2) 0%, rgba(118, 75, 162, 0.2) 100%);
border-color: rgba(102, 126, 234, 0.5);
}
.timezone-card.past-midnight {
background: rgba(255, 0, 0, 0.08);
}
.timezone-card.working-hours {
background: rgba(0, 255, 136, 0.08);
}
标识规则:
| 状态 | 样式 | 含义 |
|---|---|---|
.local |
紫色渐变背景 | 用户本地时区 |
.past-midnight |
红色背景 | 午夜时段(0:00-6:00) |
.working-hours |
绿色背景 | 工作时间(9:00-18:00) |
3.4 响应式布局
css
.timezone-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
@media (max-width: 768px) {
.header h1 {
font-size: 1.8rem;
}
.time-display {
font-size: 2.2rem;
}
.legend {
flex-wrap: wrap;
}
}
响应式策略:
- 使用 CSS Grid 的
auto-fit实现自适应列数 - 移动端缩小标题和时间显示字体
- 图例区域支持换行
四、核心代码详解
4.1 时间格式化函数
javascript
function formatOffset(offset) {
const sign = offset >= 0 ? '+' : '';
return `UTC${sign}${offset}`;
}
function formatTime(date) {
return date.toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
}
function formatDate(date) {
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
weekday: 'short'
});
}
技术要点:
- 使用
toLocaleTimeString()实现本地化时间格式 - 指定
zh-CN确保中文显示 hour12: false强制使用24小时制
4.2 时间块指示器生成
javascript
function getTimeBlocks(hour) {
const blocks = [];
for (let i = 0; i < 24; i++) {
blocks.push(i === hour);
}
return blocks;
}
实现逻辑:
- 生成24个布尔值的数组
- 当前小时对应的位置为
true,其余为false - 在卡片模板中根据布尔值决定是否添加
.active类
4.3 索引结构优化
javascript
const grid = document.getElementById('timezoneGrid');
grid.innerHTML = timezones.map(createTimezoneCard).join('');
性能优化:
- 使用
map()批量生成卡片HTML - 使用
join('')一次性插入DOM - 避免多次DOM操作提升性能
五、项目结构与组织
5.1 文件组织结构
ohos_hap/web_engine/src/main/resources/resfile/resources/app/
├── main.js # Electron 主进程配置
├── preload.js # 桥接脚本
├── index.html # HTML结构
├── style.css # 样式定义
└── app.js # 应用逻辑
5.2 文件职责划分
| 文件 | 职责 | 内容 |
|---|---|---|
main.js |
Electron主进程 | 窗口创建、菜单配置、IPC通信 |
preload.js |
预加载脚本 | 暴露原生API给渲染进程 |
index.html |
页面结构 | HTML标签、资源引用 |
style.css |
样式定义 | 布局、颜色、动画 |
app.js |
业务逻辑 | 时区计算、DOM更新 |
5.3 代码分离原则
关注点分离(Separation of Concerns):
- HTML:负责页面结构,不包含样式和逻辑
- CSS:负责视觉表现,不包含业务逻辑
- JavaScript:负责交互逻辑,不直接处理样式
六、HarmonyOS原生能力集成
6.1 Electron主进程配置
javascript
const { app, BrowserWindow, Menu } = require('electron');
const path = require('path');
let mainWindow;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
minWidth: 600,
minHeight: 500,
fullscreen: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false
}
});
mainWindow.loadFile(path.join(__dirname, 'index.html'));
}
app.whenReady().then(createWindow);
关键配置:
- 设置窗口初始大小和最小尺寸
- 禁用全屏模式(
fullscreen: false) - 配置预加载脚本路径
6.2 原生API暴露
通过 preload.js 可以向渲染进程暴露原生能力:
javascript
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
showNotification: (title, body) => {
ipcRenderer.send('show-notification', title, body);
},
getSystemInfo: () => {
return ipcRenderer.invoke('get-system-info');
}
});
可用原生能力:
| 功能 | 方法 | 说明 |
|---|---|---|
| 系统信息 | getSystemInfo() |
获取设备和系统信息 |
| 文件对话框 | showOpenDialog() |
打开文件选择对话框 |
| 通知 | showNotification() |
显示系统通知 |
| 窗口控制 | window:minimize/maximize/close |
窗口操作 |
| 剪贴板 | clipboard:read/write |
剪贴板操作 |
七、运行与构建
7.1 开发环境要求
- Node.js 18+
- DevEco Studio 5.0+
- HarmonyOS SDK
7.2 运行项目
在 DevEco Studio 中打开项目后:
- 配置 HarmonyOS SDK 路径
- 选择目标设备或模拟器
- 点击运行按钮启动应用
7.3 构建HAP包
bash
cd ohos_hap
hvigorw assembleHap
构建产物:
entry/build/outputs/hap/debug/entry-debug.hap
八、功能扩展建议
8.1 可能的功能增强
| 功能 | 描述 | 实现难度 |
|---|---|---|
| 时区搜索 | 支持按名称或城市搜索时区 | 低 |
| 时区对比 | 选择多个时区进行对比显示 | 中 |
| 世界时钟 | 添加常用时区到快捷面板 | 中 |
| 日期计算器 | 计算不同时区的日期差异 | 中 |
| 夏令时支持 | 自动识别夏令时调整 | 高 |
| 会议时间建议 | 根据多个时区推荐合适会议时间 | 高 |
8.2 性能优化方向
- 虚拟滚动:当日时区数量增加时,使用虚拟滚动减少DOM节点
- 缓存机制:缓存计算结果避免重复计算
- Web Worker:将时间计算移到Web Worker避免阻塞主线程
8.3 国际化支持
- 支持多语言切换
- 时区名称本地化
- 日期格式本地化
九、常见问题与解决方案
9.1 时间显示不正确
问题描述:某个时区的时间显示与实际不符
排查步骤:
| 步骤 | 检查项 | 说明 |
|---|---|---|
| 1 | 系统时区设置 | 确认系统时区是否正确 |
| 2 | 偏移量计算 | 检查 getTimezoneDate() 函数 |
| 3 | 夏令时影响 | 某些时区存在夏令时调整 |
| 4 | Date对象使用 | 确保使用正确的Date方法 |
解决方案:
javascript
// 确保使用UTC时间计算
function getTimezoneDate(offset) {
const now = new Date();
const utc = now.getTime() + now.getTimezoneOffset() * 60000;
return new Date(utc + offset * 3600000);
}
9.2 构建失败
问题描述 :执行 hvigorw assembleHap 时报错
常见原因:
| 错误类型 | 原因 | 解决方案 |
|---|---|---|
| 签名配置错误 | bundleName不匹配 | 检查 app.json5 和签名配置 |
| 资源缺失 | 字符串资源未定义 | 检查 string.json |
| 依赖问题 | Node.js版本不兼容 | 使用Node.js 18+ |
9.3 窗口显示问题
问题描述:窗口无法正常显示或尺寸异常
检查项:
main.js中窗口配置是否正确- 确保
fullscreen: false - 检查
minWidth和minHeight设置
十、总结
10.1 项目成果
本文详细介绍了基于 Electron 运行时的24时区时间表应用开发过程,涵盖了:
- 核心功能实现:时区数据结构、时间计算、动态卡片生成、实时更新
- 视觉设计:深色主题、玻璃态效果、智能标识、响应式布局
- 架构设计:关注点分离、文件组织、原生能力集成
10.2 技术亮点
- 实时时间同步:每秒更新确保时间准确性
- 智能标识系统:自动识别本地时区和时段类型
- 现代UI设计:玻璃态效果和流畅动画
- 跨平台兼容:基于Electron支持多平台运行
10.3 未来展望
该应用可以进一步扩展功能,如添加时区搜索、会议时间建议、夏令时支持等,使其成为一款功能完善的全球化办公工具。同时,可以通过性能优化提升应用响应速度,通过国际化支持服务全球用户。
项目地址 :https://github.com/example/timezone-app
技术栈:HTML5 + CSS3 + JavaScript + Electron + HarmonyOS
License:MIT