- 前端
- 智能家居
- UI组件
【免费下载链接】frontend
:lollipop: Frontend for Home Assistant
本篇指南围绕 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 的核心内容非常聚焦:
- 页面标题为Time Format (Seconds),用于列出所有受支持语言及其可用的(含秒)时间格式;
- 该页面演示所使用的格式化函数为:
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 中的其他函数共同构成时间格式化体系,可根据精度与语义选择:
| 函数 | 输出示例 | 说明 |
|---|---|---|
formatTime | 9:15 PM \|\| 21:15 | 精确到分钟 |
formatTimeWithSeconds | 9:15:24 PM \|\| 21:15:24 | 精确到秒(本文主题) |
formatTimeWithMilliseconds | 9:15:24.123 PM \|\| 21:15:24,123 | 精确到毫秒,小数分隔符随区域变化(法语为逗号) |
formatTimeWeekday | Saturday 11:12 PM | 分钟精度并附带星期 |
formatTime24h | 21: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
相关推荐
Home Assistant 前端日期时间格式指南:formatDateTime 函数与多语言格式画廊全解析
Home Assistant 前端日期时间格式指南:formatDateTime 函数与多语言格式画廊全解析 本篇技术指南以 Home Assistant(ho
前端智能家居UI组件Home Assistant Frontend 日期时间短格式解析:formatShortDateTime 的多语言格式化实现与 Gallery 实践
Home Assistant Frontend 日期时间短格式解析:formatShortDateTime 的多语言格式化实现与 Gallery 实践 导读 本
前端智能家居UI组件Home Assistant 前端数值日期格式化完整指南:读懂 formatDateNumeric 与多语言日期顺序
Home Assistant 前端数值日期格式化完整指南:读懂 formatDateNumeric 与多语言日期顺序 本指南围绕 Home Assistant
前端智能家居UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考