本文用 timezone_provider 1.1.0 在 Flutter 鸿蒙应用中读取当前系统的 IANA
时区标识,并以日历和服务端时间换算场景为例说明刷新、异常和数据存储方式。

三方库仓库: https://atomgit.com/oh-flutter/timezone_provider

本文锁定版本: 9c7a14425b5814c820a12cdfa0999c6fabf7fa69

完整 Demo: timezone_provider/example(受测提交)

一、最终真机效果

在这里插入图片描述

图 1:CHZ-AL00 / HarmonyOS 7.0.0.105 上读取到当前 IANA 时区 Asia/Shanghai

在这里插入图片描述

在这里插入图片描述

真机验证从 Asia/Shanghai 切换到大阪对应的 Asia/Tokyo,再恢复 Asia/Shanghai 和自动时区设置。插件每次刷新都读取系统当前值,没有缓存旧结果,也不会修改系统设置。

验证点实测结果
初始读取Asia/Shanghai
修改系统时区后刷新Asia/Tokyo
恢复系统设置后刷新Asia/Shanghai
权限无需新增权限
自动化与构建7 项 Dart/Widget 测试、静态分析和 HAP 构建通过

二、为什么要保存 IANA 标识

UTC+8 只描述某个时刻的偏移,不能唯一表示地区规则。上海和其他区域可能在当前时刻偏移相同,但历史规则、夏令时和未来政策并不一定一致。日历事件、航班时间和跨地区预约应保存 Asia/Shanghai 这类 IANA ID,并配合可靠的时区数据库换算。

这个库只提供“按请求读取”。它适合应用启动、页面恢复或用户点击刷新时获取当前值;如果业务必须实时收到系统时区变化,应使用 flutter_timezone_observer。不要用定时器高频轮询这个简单读取接口。

三、环境与依赖

组件实测版本
Flutter OH3.41.10-ohos-1.0.1
Dart3.11.5
DevEco Studio26.0.0 Release
HarmonyOS SDKAPI 26,示例兼容 API 18
测试设备CHZ-AL00 / HarmonyOS 7.0.0.105
timezone_provider1.1.0 / 上述受测提交

3.44.9+ohos-0.0.1-canary1 是预览标签,本文没有用它完成同等回归。OHOS 适配尚无稳定 TAG,所以使用完整提交:

dependencies:
  timezone_provider:
    git:
      url: https://atomgit.com/oh-flutter/timezone_provider.git
      ref: 9c7a14425b5814c820a12cdfa0999c6fabf7fa69
flutter pub get

请在 pubspec.lock 核对 resolved-ref,不要只看到 pub get 成功就认为版本已经固定。本库读取公开系统国际化数据,不需要修改 module.json5 权限。

在这里插入图片描述

图 2:AtomGit 适配分支、仓库来源与当前 HEAD。

四、核心 API

公共 API 只有一个,返回非空 String

import 'package:timezone_provider/timezone_provider.dart';

final provider = TimezoneProvider();
final String timezone = await provider.getTimezone();
// 示例:Asia/Shanghai

平台读取失败时会抛出 PlatformException。业务不应把失败静默替换成 UTC,否则日志和预约时间会在表面正常的情况下被错误换算。更稳妥的做法是保留上一次成功值,同时明确标记本次刷新失败,并允许用户重试。

五、带并发保护的页面写法

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:timezone_provider/timezone_provider.dart';

class TimezonePage extends StatefulWidget {
  const TimezonePage({super.key});

  
  State<TimezonePage> createState() => _TimezonePageState();
}

class _TimezonePageState extends State<TimezonePage>
    with WidgetsBindingObserver {
  final _provider = TimezoneProvider();
  String? _timezone;
  String? _error;
  bool _loading = false;
  int _requestId = 0;

  
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _refresh();
  }

  Future<void> _refresh() async {
    final requestId = ++_requestId;
    setState(() {
      _loading = true;
      _error = null;
    });
    try {
      final value = await _provider.getTimezone();
      if (!mounted || requestId != _requestId) return;
      setState(() => _timezone = value);
    } on PlatformException catch (error) {
      if (!mounted || requestId != _requestId) return;
      setState(() => _error = '${error.code}: ${error.message ?? '读取失败'}');
    } finally {
      if (mounted && requestId == _requestId) {
        setState(() => _loading = false);
      }
    }
  }

  
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) _refresh();
  }

  
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('当前时区'),
          actions: [
            IconButton(
              tooltip: '刷新',
              onPressed: _loading ? null : _refresh,
              icon: const Icon(Icons.refresh),
            ),
          ],
        ),
        body: Center(
          child: _loading
              ? const CircularProgressIndicator()
              : Text(_error ?? _timezone ?? '暂无数据'),
        ),
      );
}

页面从系统设置回到前台时会刷新。requestId 防止较早发起、较晚返回的请求覆盖最新结果;mounted 则避免页面销毁后调用 setState

拿到 IANA ID 后,可以把它连同事件的 UTC 时间一起传给服务端。不要只上传本地格式化文本,也不要把面向用户的“上海时间”当作协议字段。

在这里插入图片描述

图 3:getTimezone 经 LocalizationKit 返回系统 IANA ID。

六、测试、构建与真机流程

flutter analyze
flutter test
cd example
flutter test
flutter build hap --debug --no-codesign

在这里插入图片描述

图 4:7 项 Dart/Widget 测试与静态检查通过。

在这里插入图片描述

图 5:HAP 构建结果和真机宿主锁定提交。

在这里插入图片描述

图 6:Asia/Shanghai -> Asia/Tokyo -> Asia/Shanghai 的真实读取和设置恢复记录。

验证时应由用户在系统设置中修改时区,回到应用后主动刷新。城市名称只是设置界面的入口,最终断言应比较插件返回的 IANA ID。本文未把系统设置写入能力算作库功能,因为该库根本不负责修改时区。

七、常见问题

Q1:为什么返回 Asia/Shanghai,不是 GMT+08:00

这是预期结果。IANA ID 能表达地区规则,固定偏移不能完整替代它。

Q2:系统时区变了,页面为什么没有自动更新

本库没有事件流。页面恢复或用户刷新时再次调用 getTimezone();实时监听请使用时区观察库。

Q3:读取失败后能否默认使用 UTC

可以由业务明确选择降级,但必须保留失败状态并提示用户。插件不会把系统异常伪装成真实 UTC 配置。

八、总结

timezone_provider 适合用一个小而明确的 API 读取当前 IANA 时区。本文已验证上海、东京和设置恢复三段流程。项目接入时固定受测 SHA,在页面恢复时刷新,读取失败时不要伪造默认值;需要变化事件时再选用观察型插件。

九、参考链接

欢迎加入CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐