☰
Home Assistant 前端时间格式化(含秒)指南:formatTimeWithSeconds 的实现与多语言演示
2026/10/12 5:19:08 网站建设 项目流程
  • 前端
  • 智能家居
  • UI组件

【免费下载链接】frontend

:lollipop: Frontend for Home Assistant

项目地址:https://gitcode.com/gh_mirrors/frontend149/frontend
点击查看免费下载

本篇指南围绕 Home Assistant 前端(frontend)仓库中 Gallery 组件的 time-seconds 演示页面展开,深入剖析formatTimeWithSeconds这一时间格式化函数的定义、底层实现、参数行为与真实应用场景。读者读完本文,将掌握 Home Assistant 前端如何基于Intl.DateTimeFormat实现多语言、12/24 小时制可切换的"时分秒"时间格式化,并能独立在 Lovelace 自定义卡片或前端组件中复用这一能力。

一、Gallery 中的"Time Format (Seconds)"页面是什么

在 frontend 仓库中,Gallery(组件演示平台)位于 gallery 目录,其用途是集中展示前端各类组件与本地化(i18n)效果。gallery/src/pages/date-time/目录下集中了日期时间相关的全部演示页面,包括:

  • time.markdown:不带秒的时间格式演示
  • time-seconds.markdown:带秒的时间格式演示(本文主题)
  • time-weekday.markdown:带星期的演示
  • date.markdown、date-time.markdown 等:日期与日期时间格式演示

关联文档 time-seconds.markdown 的核心内容非常聚焦:

  1. 页面标题为Time Format (Seconds),用于列出所有受支持语言及其可用的(含秒)时间格式;
  2. 该页面演示所使用的格式化函数为:
const formatTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string

也就是说,这是一个"多语言、多格式对照表"性质的演示页:同一时刻,在同一语言下分别以"语言默认格式、12 小时制、24 小时制"三种方式输出时:分:秒,方便开发者直观对比各语言的表现差异。

二、演示组件的实现:三列对比所有语言

与 markdown 文档一一对应的演示组件是 gallery/src/pages/date-time/time-seconds.ts,这是一个基于 LitElement 的自定义元素demo-date-time-time-seconds。其核心逻辑可以拆解为四部分。

2.1 可切换的演示时间

组件顶部使用ha-control-select下拉选择器,选项来自 gallery/src/data/date-options.ts:

export const timeOptions: ControlSelectOption[] = [ { value: "now", label: "Now" }, { value: "00:15:30", label: "12:15:30 AM" }, { value: "06:15:30", label: "06:15:30 AM" }, { value: "12:15:30", label: "12:15:30 PM" }, { value: "18:15:30", label: "06:15:30 PM" }, ];

默认选中"now"(当前时刻);当选择某个固定时刻时,组件将"HH:MM:SS"字符串拆分后写入Date对象的setHours/setMinutes/setSeconds,从而在多个语言列之间使用同一个时间点进行对照,保证结果可比:

if (this.selection !== "now") { const [hours, minutes, seconds] = this.selection.split(":").map(Number); this.date.setHours(hours); this.date.setMinutes(minutes); this.date.setSeconds(seconds); }

2.2 基准 Locale 与三种输出列

组件构造了一个英文基准FrontendLocaleData(结构定义见 src/data/translation.ts),随后遍历translationMetadata.translations中所有受支持语言,为每种语言渲染一行三列:

  • Default (lang):time_format: TimeFormat.language,完全跟随语言的区域习惯;
  • 12 Hours:time_format: TimeFormat.am_pm,强制 12 小时制;
  • 24 Hours:time_format: TimeFormat.twenty_four,强制 24 小时制。

其中translationMetadata来自 src/resources/translations-metadata.ts,该模块读取构建产物build/translations/translationMetadata.json,提供语言代码、原生语言名(nativeName)等元数据,这正是"列出所有受支持语言"的数据来源。

2.3 传入服务器配置

注意演示代码在调用时还传入了第三个参数demoConfig(来自 src/fake_data/demo_config.ts)。这一点与文档中写出的函数签名(只有两个参数)略有差异,说明实际实现中该函数还需要HassConfig来获取服务器时区(详见下文实现分析)。

三、源码实现:formatTimeWithSeconds 的底层原理

核心实现位于 src/common/datetime/format_time.ts:

// 9:15:24 PM || 21:15:24 export const formatTimeWithSeconds = ( dateObj: Date, locale: FrontendLocaleData, config: HassConfig ) => formatTimeWithSecondsMem(locale, config.time_zone).format(dateObj); const formatTimeWithSecondsMem = memoizeOne( (locale: FrontendLocaleData, serverTimeZone: string) => new Intl.DateTimeFormat(locale.language, { hour: useAmPm(locale) ? "numeric" : "2-digit", minute: "2-digit", second: "2-digit", hourCycle: useAmPm(locale) ? "h12" : "h23", timeZone: resolveTimeZone(locale.time_zone, serverTimeZone), }) );

该实现有几个值得注意的技术点。

3.1 基于 Intl.DateTimeFormat

与手写补零的字符串拼接不同,Home Assistant 前端直接使用 ECMAScript 国际化 APIIntl.DateTimeFormat,并把second: "2-digit"作为关键配置项,从而让每种语言都能按自己的区域规则输出秒位(例如数字位数、分隔符、12/24 小时循环等均由 CLDR 区域数据驱动)。这也是"所有受支持语言各有其可用格式"这一能力的根基。

3.2 hourCycle 与 useAmPm 联动

hourCycle由useAmPm(locale)决定。该工具函数位于 src/common/datetime/use_am_pm.ts:

  • 当time_format为TimeFormat.am_pm("12")时,直接返回true,使用h12;
  • 当time_format为TimeFormat.twenty_four("24")时,返回false,使用h23;
  • 当time_format为TimeFormat.language(跟随语言)或TimeFormat.system时,则以一个固定的测试时间new Date("January 1, 2023 22:00:00")调用toLocaleString,通过结果中是否包含"10"来推断该语言默认采用 12 还是 24 小时制——这是一个巧妙且无需额外语言数据的启发式判定。

3.3 时区解析:本地 vs 服务器

timeZone由 src/common/datetime/resolve-time-zone.ts 中的resolveTimeZone决定:

  • 若用户设置time_zone为TimeZone.local且浏览器能解析出合法的 IANA 时区名(如Asia/Shanghai),则使用浏览器本地时区;
  • 否则回退到HassConfig.time_zone(服务器时区);
  • 代码还对 Android 模拟器等返回"+00:00"偏移量而非 IANA 名称的环境做了防御处理,避免把非法时区传给Intl。

3.4 memoizeOne 性能优化

formatTimeWithSecondsMem使用memoizeOne按(locale, serverTimeZone)缓存Intl.DateTimeFormat实例。由于 Gallery 演示会对每一种语言调用一次该函数,缓存机制避免了反复构造格式化器对象,这在多语言对照渲染场景下是明显的性能保障。

四、12 小时制与 24 小时制:TimeFormat 枚举与测试验证

用户可选的time_format取值定义在 src/data/translation.ts:

export enum TimeFormat { language = "language", system = "system", am_pm = "12", twenty_four = "24", }

其中am_pm("12")与twenty_four("24")正是 Gallery 演示页中"12 Hours / 24 Hours"两列所对应的强制模式,而language对应"Default (lang)"列。

仓库的单元测试 test/common/datetime/format_time.test.ts 对formatTimeWithSeconds给出了精确断言,可作为理解其行为的最佳佐证:

const dateObj = new Date(2017, 10, 18, 23, 12, 13, 400); // time_format: am_pm → 期望输出 "11:12:13 PM" // time_format: twenty_four → 期望输出 "23:12:13"

同一时刻23:12:13,在 12 小时制下显示为11:12:13 PM,在 24 小时制下显示为23:12:13,与函数头注释// 9:15:24 PM || 21:15:24完全一致。

五、函数族:一个完整的时间格式化体系

formatTimeWithSeconds并非孤立存在,它与 format_time.ts 中的其他函数共同构成时间格式化体系,可根据精度与语义选择:

函数输出示例说明
formatTime9:15 PM \|\| 21:15精确到分钟
formatTimeWithSeconds9:15:24 PM \|\| 21:15:24精确到秒(本文主题)
formatTimeWithMilliseconds9:15:24.123 PM \|\| 21:15:24,123精确到毫秒,小数分隔符随区域变化(法语为逗号)
formatTimeWeekdaySaturday 11:12 PM分钟精度并附带星期
formatTime24h21:15强制 24 小时制;源码注释特别提到使用en-GB区域以规避 Chrome 中24:59显示为0:59的已知问题

毫秒函数的小数分隔符行为也有测试覆盖:法语区域下23:12:13.400会输出为23:12:13,400(见 format_time.test.ts),印证了"格式完全由区域数据驱动"的设计。

六、真实应用场景:hui-timestamp-display 中的 long 时间格式

formatTimeWithSeconds在前端产品代码中的典型使用位置是 Lovelace 的 hui-timestamp-display.ts。该组件维护了一张格式表:

const FORMATS = { date: { default: formatDate, short: formatDateNumeric }, datetime:{ default: formatDateTime, short: formatDateTimeNumeric }, time: { default: formatTime, long: formatTimeWithSeconds }, };

当配置项format为{ type: "time", style: "long" }时,时间戳将以含秒的格式渲染;同时,无论采用相对时间还是静态格式,当tooltip开启时,悬浮提示统一使用formatDateTimeWithSeconds(日期时间 + 秒)展示完整精确时刻。这说明formatTimeWithSeconds承担着"高精度时间呈现"的角色,适合日志时间戳、事件时刻、设备状态上报等需要秒级分辨率的场景。

七、如何运行与扩展验证

若想在本地复现 Gallery 页面效果,可运行 gallery 的开发脚本:

pnpm run gallery:develop

(具体命令见 gallery/script/develop_gallery。)构建则使用 gallery/script/build_gallery。

在自定义卡片或前端组件中复用该能力的标准调用方式如下:

import { formatTimeWithSeconds } from "../../src/common/datetime/format_time"; const now = new Date(); const locale: FrontendLocaleData = { language: "zh-Hans", number_format: NumberFormat.language, time_format: TimeFormat.language, // 或 "12" / "24" date_format: DateFormat.language, first_weekday: FirstWeekday.language, time_zone: TimeZone.local, }; const text = formatTimeWithSeconds(now, locale, hass.config);

小结

以 time-seconds.markdown 为入口可以看到:Home Assistant 前端把"带秒的时间格式化"做成了一个以Intl.DateTimeFormat为核心、由useAmPm与resolveTimeZone两个工具函数协同决策、以memoizeOne缓存保障性能的完整能力,并通过 Gallery 演示页对全部受支持语言进行 12/24 小时制的对照展示。理解formatTimeWithSeconds,也就理解了这套前端时间本地化体系的基本运作方式,可直接将其移植到自定义卡片与 Lovelace 组件中。

  • 前端
  • 智能家居
  • UI组件

【免费下载链接】frontend

:lollipop: Frontend for Home Assistant

项目地址:https://gitcode.com/gh_mirrors/frontend149/frontend
点击查看免费下载

相关推荐

上一篇:告别复杂JSON处理:GRDB.swift终极Codable与JSON列实战指南
下一篇:Catberry渐进式渲染揭秘:为什么你的应用加载更快

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询