import { html, LitElement, PropertyValues, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { formatDate } from "../../../common/datetime/format_date"; import { formatDateTime } from "../../../common/datetime/format_date_time"; import { formatTime } from "../../../common/datetime/format_time"; import { relativeTime } from "../../../common/datetime/relative_time"; import { FrontendLocaleData } from "../../../data/translation"; import { HomeAssistant } from "../../../types"; import { TimestampRenderingFormat } from "./types"; const FORMATS: { [key: string]: (ts: Date, lang: FrontendLocaleData) => string; } = { date: formatDate, datetime: formatDateTime, time: formatTime, }; const INTERVAL_FORMAT = ["relative", "total"]; @customElement("hui-timestamp-display") class HuiTimestampDisplay extends LitElement { @property({ attribute: false }) public hass?: HomeAssistant; @property() public ts?: Date; @property() public format?: TimestampRenderingFormat; @state() private _relative?: string; private _connected?: boolean; private _interval?: number; public connectedCallback(): void { super.connectedCallback(); this._connected = true; this._startInterval(); } public disconnectedCallback(): void { super.disconnectedCallback(); this._connected = false; this._clearInterval(); } protected render(): TemplateResult { if (!this.ts || !this.hass) { return html``; } if (isNaN(this.ts.getTime())) { return html`${this.hass.localize( "ui.panel.lovelace.components.timestamp-display.invalid" )}`; } const format = this._format; if (INTERVAL_FORMAT.includes(format)) { return html` ${this._relative} `; } if (format in FORMATS) { return html` ${FORMATS[format](this.ts, this.hass.locale)} `; } return html`${this.hass.localize( "ui.panel.lovelace.components.timestamp-display.invalid_format" )}`; } protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); if (!changedProperties.has("format") || !this._connected) { return; } if (INTERVAL_FORMAT.includes("relative")) { this._startInterval(); } else { this._clearInterval(); } } private get _format(): string { return this.format || "relative"; } private _startInterval(): void { this._clearInterval(); if (this._connected && INTERVAL_FORMAT.includes(this._format)) { this._updateRelative(); this._interval = window.setInterval(() => this._updateRelative(), 1000); } } private _clearInterval(): void { if (this._interval) { clearInterval(this._interval); this._interval = undefined; } } private _updateRelative(): void { if (this.ts && this.hass!.localize) { this._relative = this._format === "relative" ? relativeTime(this.ts, this.hass!.locale) : (this._relative = relativeTime( new Date(), this.hass!.locale, this.ts, false )); } } } declare global { interface HTMLElementTagNameMap { "hui-timestamp-display": HuiTimestampDisplay; } }