Flutter 框架跨平台鸿蒙开发 - 时区转换器应用
运行效果图时区转换器是一款专业的时间转换工具,旨在帮助用户轻松应对跨时区的时间计算需求。在全球化时代,跨国商务、国际旅行、远程协作等场景频繁需要处理不同时区的时间转换问题。地球划分为24个时区,每个时区相差1小时。从国际日期变更线开始,向东每跨一个时区增加1小时,向西每跨一个时区减少1小时。本应用支持从UTC-10:00(夏威夷)到UTC+13:00(新西兰)的完整时区范围,覆盖全球主要城市和地区
时区转换器应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图



1.1 应用简介
时区转换器是一款专业的时间转换工具,旨在帮助用户轻松应对跨时区的时间计算需求。在全球化时代,跨国商务、国际旅行、远程协作等场景频繁需要处理不同时区的时间转换问题。本应用整合了全球主要城市的时区数据,支持实时时钟显示、自定义时间转换、收藏常用时区等功能,让时间转换变得简单直观。
地球划分为24个时区,每个时区相差1小时。从国际日期变更线开始,向东每跨一个时区增加1小时,向西每跨一个时区减少1小时。本应用支持从UTC-10:00(夏威夷)到UTC+13:00(新西兰)的完整时区范围,覆盖全球主要城市和地区。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 世界时钟 | 实时显示全球各城市时间 | WorldClock模型 + 实时更新 |
| 时区转换 | 自定义时间跨时区转换 | 时差计算算法 |
| 收藏管理 | 收藏常用时区快速访问 | List集合 + 状态管理 |
| 分类筛选 | 按区域筛选时区 | 枚举分类 + FilterChip |
| 日夜指示 | 显示当前是白天还是夜晚 | 时间判断逻辑 |
| 搜索功能 | 快速搜索城市或时区 | 关键词匹配 |
1.3 时区区域分类
| 区域 | 英文标识 | 图标 | 颜色 | 代表城市 |
|---|---|---|---|---|
| 亚洲 | asia | public | 红色 | 北京、东京、新加坡 |
| 欧洲 | europe | location_city | 蓝色 | 伦敦、巴黎、柏林 |
| 美洲 | america | landscape | 绿色 | 纽约、洛杉矶、多伦多 |
| 非洲 | africa | terrain | 橙色 | 开罗、约翰内斯堡 |
| 大洋洲 | oceania | beach_access | 青色 | 悉尼、墨尔本、奥克兰 |
| 大西洋 | atlantic | water | 靛蓝色 | 大西洋岛屿 |
| 太平洋 | pacific | sailing | 蓝绿色 | 檀香山、斐济 |
| 印度洋 | indian | waves | 紫色 | 毛里求斯 |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | setState | - |
| 目标平台 | 鸿蒙OS | API 21+ |
1.5 项目结构
lib/
└── main_timezone_converter.dart
├── TimeZoneConverterApp # 应用入口
├── TimeZoneRegion # 时区区域枚举
├── TimeZoneInfo # 时区信息模型
├── WorldClock # 世界时钟模型
├── HomePage # 主页面
│ ├── _buildHomePage() # 首页
│ ├── _buildConverterPage() # 转换页
│ ├── _buildWorldClockPage() # 世界时钟页
│ └── _buildFavoritesPage() # 收藏页
└── 辅助方法
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 数据流程图
2.4 时区转换流程
三、核心模块设计
3.1 数据模型设计
3.1.1 时区信息模型 (TimeZoneInfo)
class TimeZoneInfo {
final String id; // 唯一标识
final String name; // 时区名称
final String city; // 城市名称
final String offset; // UTC偏移量字符串
final TimeZoneRegion region; // 所属区域
final String countryCode; // 国家代码
Duration get offsetDuration {
// 解析偏移量字符串为Duration
final parts = offset.split(':');
final hours = int.parse(parts[0]);
final minutes = int.parse(parts[1]);
return Duration(hours: hours, minutes: minutes);
}
String get offsetDisplay {
// 格式化显示: UTC+08:00
final sign = offsetDuration.isNegative ? '-' : '+';
final hours = offsetDuration.inHours.abs().toString().padLeft(2, '0');
final minutes = (offsetDuration.inMinutes.abs() % 60).toString().padLeft(2, '0');
return 'UTC$sign$hours:$minutes';
}
}
3.1.2 世界时钟模型 (WorldClock)
class WorldClock {
final TimeZoneInfo timeZone;
final DateTime dateTime;
factory WorldClock.now(TimeZoneInfo timeZone) {
final now = DateTime.now().toUtc();
final converted = now.add(timeZone.offsetDuration);
return WorldClock(timeZone: timeZone, dateTime: converted);
}
String get timeString {
// 格式: HH:MM:SS
final hour = dateTime.hour.toString().padLeft(2, '0');
final minute = dateTime.minute.toString().padLeft(2, '0');
final second = dateTime.second.toString().padLeft(2, '0');
return '$hour:$minute:$second';
}
bool get isDaytime {
// 判断是否为白天 (6:00 - 18:00)
return dateTime.hour >= 6 && dateTime.hour < 18;
}
}
3.1.3 时区区域枚举 (TimeZoneRegion)
| 区域 | 英文标识 | 图标 | 颜色 | 时区范围 |
|---|---|---|---|---|
| 亚洲 | asia | public | 红色 | UTC+04:00 ~ UTC+09:00 |
| 欧洲 | europe | location_city | 蓝色 | UTC-01:00 ~ UTC+03:00 |
| 美洲 | america | landscape | 绿色 | UTC-08:00 ~ UTC-03:00 |
| 非洲 | africa | terrain | 橙色 | UTC-01:00 ~ UTC+03:00 |
| 大洋洲 | oceania | beach_access | 青色 | UTC+08:00 ~ UTC+13:00 |
3.2 页面结构设计
3.2.1 首页模块
3.2.2 时区转换页面
3.2.3 世界时钟页面
3.3 状态管理
3.3.1 核心状态变量
class _HomePageState extends State<HomePage> {
// 导航状态
int _currentIndex = 0;
// 数据状态
final List<TimeZoneInfo> _allTimeZones = [];
final List<TimeZoneInfo> _favoriteZones = [];
// 转换状态
TimeZoneInfo? _sourceTimeZone;
TimeZoneInfo? _targetTimeZone;
DateTime _selectedDateTime = DateTime.now();
// 筛选状态
TimeZoneRegion? _selectedRegion;
String _searchQuery = '';
}
3.3.2 时间转换逻辑
DateTime _convertTime(DateTime sourceTime, TimeZoneInfo sourceZone, TimeZoneInfo targetZone) {
// 1. 将源时间转换为UTC时间
final utcTime = sourceTime.subtract(sourceZone.offsetDuration);
// 2. 将UTC时间转换为目标时区时间
return utcTime.add(targetZone.offsetDuration);
}
String _formatTimeDifference(TimeZoneInfo source, TimeZoneInfo target) {
// 计算时差(分钟)
final diff = target.offsetDuration.inMinutes - source.offsetDuration.inMinutes;
if (diff == 0) return '相同时间';
final hours = diff.abs() ~/ 60;
final minutes = diff.abs() % 60;
String result = diff > 0 ? '快 ' : '慢 ';
if (hours > 0) result += '$hours 小时';
if (minutes > 0) {
if (hours > 0) result += ' ';
result += '$minutes 分钟';
}
return result;
}
四、UI设计规范
4.1 配色方案
应用采用深色主题设计,营造专业沉稳的氛围:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #00897B (Teal) | AppBar、按钮、强调元素 |
| 背景色 | #0F1419 | 页面背景 |
| 卡片背景 | #1C2833 | 卡片、弹窗 |
| 输入框背景 | #2C3E50 | 输入框、选择器 |
| 文字主色 | #FFFFFF | 主要文字 |
| 文字次色 | #B0BEC5 | 次要文字 |
区域专属颜色:
// 亚洲 - 红色
Colors.red
// 欧洲 - 蓝色
Colors.blue
// 美洲 - 绿色
Colors.green
// 非洲 - 橙色
Colors.orange
// 大洋洲 - 青色
Colors.cyan
// 大西洋 - 靛蓝色
Colors.indigo
// 太平洋 - 蓝绿色
Colors.teal
// 印度洋 - 紫色
Colors.purple
4.2 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 当前时间 | 36px | Bold | #FFFFFF |
| 转换结果 | 48px | Bold | #FFFFFF |
| 城市名称 | 15px | Medium | #FFFFFF |
| 时区偏移 | 12px | Regular | #B0BEC5 |
| 时间显示 | 18px | Bold | #FFFFFF |
4.3 组件规范
4.3.1 时区卡片
┌─────────────────────────────────────────────────┐
│ ┌────┐ 北京 [☆] │
│ │ 🌏 │ UTC+08:00 │
│ └────┘ 14:30 ☀️ │
└─────────────────────────────────────────────────┘
4.3.2 转换结果卡片
┌─────────────────────────────────────────────────┐
│ 转换结果 │
│ │
│ 09:30 │
│ │
│ 2024-01-25 │
│ │
│ ┌─────────────────────────────┐ │
│ │ 目标时区比源时区 快 5 小时 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────────────────┘
4.3.3 日夜图标
白天 (06:00 - 18:00): ☀️ 橙色
夜晚 (18:00 - 06:00): 🌙 靛蓝色
五、核心功能实现
5.1 时区数据加载
void _loadTimeZones() {
_allTimeZones.addAll([
// 亚洲
const TimeZoneInfo(
id: 'asia_shanghai',
name: '中国标准时间',
city: '北京/上海',
offset: '+08:00',
region: TimeZoneRegion.asia,
countryCode: 'CN',
),
const TimeZoneInfo(
id: 'asia_tokyo',
name: '日本标准时间',
city: '东京',
offset: '+09:00',
region: TimeZoneRegion.asia,
countryCode: 'JP',
),
// ... 更多时区
]);
}
5.2 时间转换
DateTime _convertTime(
DateTime sourceTime,
TimeZoneInfo sourceZone,
TimeZoneInfo targetZone
) {
// 转换为UTC时间
final utcTime = sourceTime.subtract(sourceZone.offsetDuration);
// 转换为目标时区
return utcTime.add(targetZone.offsetDuration);
}
5.3 时差计算
String _formatTimeDifference(TimeZoneInfo source, TimeZoneInfo target) {
final diff = target.offsetDuration.inMinutes - source.offsetDuration.inMinutes;
if (diff == 0) return '相同时间';
final hours = diff.abs() ~/ 60;
final minutes = diff.abs() % 60;
String result = diff > 0 ? '快 ' : '慢 ';
if (hours > 0) result += '$hours 小时';
if (minutes > 0) {
if (hours > 0) result += ' ';
result += '$minutes 分钟';
}
return result;
}
5.4 收藏功能
void _toggleFavorite(TimeZoneInfo timeZone) {
setState(() {
if (_favoriteZones.any((z) => z.id == timeZone.id)) {
_favoriteZones.removeWhere((z) => z.id == timeZone.id);
} else {
_favoriteZones.add(timeZone);
}
});
}
bool _isFavorite(TimeZoneInfo timeZone) {
return _favoriteZones.any((z) => z.id == timeZone.id);
}
5.5 日夜判断
bool get isDaytime {
// 06:00 - 18:00 为白天
return dateTime.hour >= 6 && dateTime.hour < 18;
}
六、预置时区数据
6.1 亚洲时区
| 城市 | 时区名称 | UTC偏移 | 国家 |
|---|---|---|---|
| 北京/上海 | 中国标准时间 | +08:00 | 中国 |
| 香港 | 香港时间 | +08:00 | 中国香港 |
| 台北 | 台北时间 | +08:00 | 中国台湾 |
| 东京 | 日本标准时间 | +09:00 | 日本 |
| 首尔 | 韩国标准时间 | +09:00 | 韩国 |
| 新加坡 | 新加坡时间 | +08:00 | 新加坡 |
| 曼谷 | 印度支那时间 | +07:00 | 泰国 |
| 迪拜 | 海湾标准时间 | +04:00 | 阿联酋 |
| 新德里 | 印度标准时间 | +05:30 | 印度 |
6.2 欧洲时区
| 城市 | 时区名称 | UTC偏移 | 国家 |
|---|---|---|---|
| 伦敦 | 格林威治时间 | +00:00 | 英国 |
| 巴黎 | 中欧时间 | +01:00 | 法国 |
| 柏林 | 中欧时间 | +01:00 | 德国 |
| 莫斯科 | 莫斯科时间 | +03:00 | 俄罗斯 |
| 罗马 | 中欧时间 | +01:00 | 意大利 |
| 马德里 | 中欧时间 | +01:00 | 西班牙 |
6.3 美洲时区
| 城市 | 时区名称 | UTC偏移 | 国家 |
|---|---|---|---|
| 纽约 | 东部时间 | -05:00 | 美国 |
| 洛杉矶 | 太平洋时间 | -08:00 | 美国 |
| 芝加哥 | 中部时间 | -06:00 | 美国 |
| 多伦多 | 东部时间 | -05:00 | 加拿大 |
| 温哥华 | 太平洋时间 | -08:00 | 加拿大 |
| 圣保罗 | 巴西利亚时间 | -03:00 | 巴西 |
6.4 大洋洲时区
| 城市 | 时区名称 | UTC偏移 | 国家 |
|---|---|---|---|
| 悉尼 | 澳大利亚东部时间 | +11:00 | 澳大利亚 |
| 墨尔本 | 澳大利亚东部时间 | +11:00 | 澳大利亚 |
| 珀斯 | 澳大利亚西部时间 | +08:00 | 澳大利亚 |
| 奥克兰 | 新西兰时间 | +13:00 | 新西兰 |
七、时区知识
7.1 时区原理
7.2 特殊时区
| 时区 | 偏移 | 说明 |
|---|---|---|
| UTC+00:00 | 格林威治标准时间 | 本初子午线经过 |
| UTC+05:30 | 印度标准时间 | 偏移30分钟 |
| UTC+05:45 | 尼泊尔时间 | 偏移45分钟 |
| UTC+13:00 | 新西兰夏令时 | 夏令时调整 |
| UTC+14:00 | 莱恩群岛 | 最早进入新的一天 |
7.3 夏令时说明
八、扩展功能规划
8.1 后续版本规划
8.2 功能扩展建议
8.2.1 会议时间规划
帮助跨时区团队安排会议:
- 显示所有参与者本地时间
- 自动推荐最佳会议时间
- 生成时区对比链接
8.2.2 倒计时功能
支持跨时区倒计时:
- 重要事件倒计时
- 多时区同步显示
- 提醒通知
8.2.3 时区地图
可视化时区分布:
- 世界地图展示
- 点击选择时区
- 时区边界显示
九、注意事项
9.1 开发注意事项
-
时区偏移解析:正确处理正负偏移
-
日夜判断:使用本地时间判断
-
时间格式化:统一使用24小时制
-
夏令时:当前版本未实现夏令时自动调整
9.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 时差计算错误 | 偏移量解析问题 | 检查offset字符串格式 |
| 日夜状态不对 | 时区未转换 | 使用转换后的时间判断 |
| 时间显示异常 | 时区数据缺失 | 检查时区数据完整性 |
9.3 时区提示
⚠️ 重要提示 ⚠️
本应用使用静态时区偏移量,未考虑夏令时调整。
实际使用时,部分国家/地区会根据季节调整时间。
建议结合实际需求确认具体时区规则。
十、运行说明
10.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
10.2 运行命令
# 查看可用设备
flutter devices
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_timezone_converter.dart
# 运行到Windows
flutter run -d windows -t lib/main_timezone_converter.dart
# 代码分析
flutter analyze lib/main_timezone_converter.dart
十一、总结
时区转换器通过直观的界面设计和精准的时间计算,为用户提供了一个便捷的跨时区时间管理工具。应用采用深色主题设计,符合专业工具的定位;代码结构清晰,遵循Flutter最佳实践;数据模型设计合理,便于后续扩展夏令时支持等功能。
核心功能涵盖全球主要城市的时区数据,从亚洲到美洲,从欧洲到大洋洲,帮助用户轻松应对跨国时间计算需求。世界时钟实时显示功能让用户一目了然地了解全球各地时间,时区转换功能支持自定义时间输入,满足各种场景需求。
通过本应用,希望能够帮助用户更好地管理跨时区的时间安排,提升国际协作效率,让时间不再是距离的障碍。
跨越时区,连接世界
更多推荐


所有评论(0)