Remove Intl polyfill on connection and consistently resolve time zone (#19326)
This commit is contained in:
parent
96a41704ea
commit
88abeada44
|
@ -1,7 +1,8 @@
|
|||
import { HassConfig } from "home-assistant-js-websocket";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { FrontendLocaleData, DateFormat } from "../../data/translation";
|
||||
import { DateFormat, FrontendLocaleData } from "../../data/translation";
|
||||
import "../../resources/intl-polyfill";
|
||||
import { resolveTimeZone } from "./resolve-time-zone";
|
||||
|
||||
// Tuesday, August 10
|
||||
export const formatDateWeekdayDay = (
|
||||
|
@ -16,7 +17,7 @@ const formatDateWeekdayDayMem = memoizeOne(
|
|||
weekday: "long",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -33,7 +34,7 @@ const formatDateMem = memoizeOne(
|
|||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -50,7 +51,7 @@ const formatDateShortMem = memoizeOne(
|
|||
year: "numeric",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -105,7 +106,7 @@ const formatDateNumericMem = memoizeOne(
|
|||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -113,7 +114,7 @@ const formatDateNumericMem = memoizeOne(
|
|||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -130,7 +131,7 @@ const formatDateVeryShortMem = memoizeOne(
|
|||
new Intl.DateTimeFormat(locale.language, {
|
||||
day: "numeric",
|
||||
month: "short",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -146,7 +147,7 @@ const formatDateMonthYearMem = memoizeOne(
|
|||
new Intl.DateTimeFormat(locale.language, {
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -161,7 +162,7 @@ const formatDateMonthMem = memoizeOne(
|
|||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
month: "long",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -176,7 +177,7 @@ const formatDateYearMem = memoizeOne(
|
|||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
year: "numeric",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -191,7 +192,7 @@ const formatDateWeekdayMem = memoizeOne(
|
|||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
weekday: "long",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -206,6 +207,6 @@ const formatDateWeekdayShortMem = memoizeOne(
|
|||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||
new Intl.DateTimeFormat(locale.language, {
|
||||
weekday: "short",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
|
|
@ -4,6 +4,7 @@ import { FrontendLocaleData } from "../../data/translation";
|
|||
import "../../resources/intl-polyfill";
|
||||
import { formatDateNumeric } from "./format_date";
|
||||
import { formatTime } from "./format_time";
|
||||
import { resolveTimeZone } from "./resolve-time-zone";
|
||||
import { useAmPm } from "./use_am_pm";
|
||||
|
||||
// August 9, 2021, 8:23 AM
|
||||
|
@ -22,7 +23,7 @@ const formatDateTimeMem = memoizeOne(
|
|||
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||
minute: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -42,7 +43,7 @@ const formatShortDateTimeWithYearMem = memoizeOne(
|
|||
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||
minute: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -61,7 +62,7 @@ const formatShortDateTimeMem = memoizeOne(
|
|||
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||
minute: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -82,7 +83,7 @@ const formatDateTimeWithSecondsMem = memoizeOne(
|
|||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import { HassConfig } from "home-assistant-js-websocket";
|
|||
import memoizeOne from "memoize-one";
|
||||
import { FrontendLocaleData } from "../../data/translation";
|
||||
import "../../resources/intl-polyfill";
|
||||
import { resolveTimeZone } from "./resolve-time-zone";
|
||||
import { useAmPm } from "./use_am_pm";
|
||||
|
||||
// 9:15 PM || 21:15
|
||||
|
@ -17,7 +18,7 @@ const formatTimeMem = memoizeOne(
|
|||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -35,7 +36,7 @@ const formatTimeWithSecondsMem = memoizeOne(
|
|||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -53,7 +54,7 @@ const formatTimeWeekdayMem = memoizeOne(
|
|||
hour: useAmPm(locale) ? "numeric" : "2-digit",
|
||||
minute: "2-digit",
|
||||
hourCycle: useAmPm(locale) ? "h12" : "h23",
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -71,6 +72,6 @@ const formatTime24hMem = memoizeOne(
|
|||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
|
||||
})
|
||||
);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import memoizeOne from "memoize-one";
|
||||
import "../../resources/intl-polyfill";
|
||||
|
||||
export const localizeWeekdays = memoizeOne(
|
||||
(language: string, short: boolean): string[] => {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { TimeZone } from "../../data/translation";
|
||||
|
||||
// Browser time zone can be determined from Intl, with fallback to UTC for polyfill or no support.
|
||||
// Alternatively, we could fallback to a fixed offset IANA zone (e.g. "Etc/GMT+5") using
|
||||
// Date.prototype.getTimeOffset(), but IANA only has whole hour Etc zones, and problems
|
||||
// might occur with relative time due to DST.
|
||||
// Use optional chain instead of polyfill import since polyfill will always return UTC
|
||||
export const LOCAL_TIME_ZONE =
|
||||
Intl.DateTimeFormat?.().resolvedOptions?.().timeZone ?? "UTC";
|
||||
|
||||
// Pick time zone based on user profile option. Core zone is used when local cannot be determined.
|
||||
export const resolveTimeZone = (option: TimeZone, serverTimeZone: string) =>
|
||||
option === TimeZone.local && LOCAL_TIME_ZONE !== "UTC"
|
||||
? LOCAL_TIME_ZONE
|
||||
: serverTimeZone;
|
|
@ -9,6 +9,7 @@ import {
|
|||
TemplateResult,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { LOCAL_TIME_ZONE } from "../common/datetime/resolve-time-zone";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import "../components/ha-alert";
|
||||
|
@ -33,8 +34,7 @@ class OnboardingCoreConfig extends LitElement {
|
|||
|
||||
private _elevation = "0";
|
||||
|
||||
private _timeZone: ConfigUpdateValues["time_zone"] =
|
||||
Intl.DateTimeFormat?.().resolvedOptions?.().timeZone;
|
||||
private _timeZone: ConfigUpdateValues["time_zone"] = LOCAL_TIME_ZONE;
|
||||
|
||||
private _language: ConfigUpdateValues["language"] = getLocalLanguage();
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import { renderRRuleAsText } from "./recurrence";
|
|||
import { showConfirmEventDialog } from "./show-confirm-event-dialog-box";
|
||||
import { CalendarEventDetailDialogParams } from "./show-dialog-calendar-event-detail";
|
||||
import { showCalendarEventEditDialog } from "./show-dialog-calendar-event-editor";
|
||||
import { resolveTimeZone } from "../../common/datetime/resolve-time-zone";
|
||||
|
||||
class DialogCalendarEventDetail extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
@ -138,8 +139,10 @@ class DialogCalendarEventDetail extends LitElement {
|
|||
}
|
||||
|
||||
private _formatDateRange() {
|
||||
// Parse a dates in the browser timezone
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const timeZone = resolveTimeZone(
|
||||
this.hass.locale.time_zone,
|
||||
this.hass.config.time_zone
|
||||
);
|
||||
const start = toDate(this._data!.dtstart, { timeZone: timeZone });
|
||||
const endValue = toDate(this._data!.dtend, { timeZone: timeZone });
|
||||
// All day events should be displayed as a day earlier
|
||||
|
|
|
@ -11,6 +11,7 @@ import { HassEntity } from "home-assistant-js-websocket";
|
|||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { resolveTimeZone } from "../../common/datetime/resolve-time-zone";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||
|
@ -32,7 +33,6 @@ import {
|
|||
deleteCalendarEvent,
|
||||
updateCalendarEvent,
|
||||
} from "../../data/calendar";
|
||||
import { TimeZone } from "../../data/translation";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import "../lovelace/components/hui-generic-entity-row";
|
||||
|
@ -68,7 +68,7 @@ class DialogCalendarEventEditor extends LitElement {
|
|||
|
||||
@state() private _submitting = false;
|
||||
|
||||
// Dates are manipulated and displayed in the browser timezone
|
||||
// Dates are displayed in the timezone according to the user's profile
|
||||
// which may be different from the Home Assistant timezone. When
|
||||
// events are persisted, they are relative to the Home Assistant
|
||||
// timezone, but floating without a timezone.
|
||||
|
@ -85,10 +85,10 @@ class DialogCalendarEventEditor extends LitElement {
|
|||
computeStateDomain(stateObj) === "calendar" &&
|
||||
supportsFeature(stateObj, CalendarEntityFeature.CREATE_EVENT)
|
||||
)?.entity_id;
|
||||
this._timeZone =
|
||||
this.hass.locale.time_zone === TimeZone.local
|
||||
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
: this.hass.config.time_zone;
|
||||
this._timeZone = resolveTimeZone(
|
||||
this.hass.locale.time_zone,
|
||||
this.hass.config.time_zone
|
||||
);
|
||||
if (params.entry) {
|
||||
const entry = params.entry!;
|
||||
this._allDay = isDate(entry.dtstart);
|
||||
|
|
|
@ -294,10 +294,7 @@ class HaConfigSectionGeneral extends LitElement {
|
|||
this._country = this.hass.config.country;
|
||||
this._language = this.hass.config.language;
|
||||
this._elevation = this.hass.config.elevation;
|
||||
this._timeZone =
|
||||
this.hass.config.time_zone ||
|
||||
Intl.DateTimeFormat?.().resolvedOptions?.().timeZone ||
|
||||
"Etc/GMT";
|
||||
this._timeZone = this.hass.config.time_zone || "Etc/GMT";
|
||||
this._name = this.hass.config.location_name;
|
||||
this._updateUnits = true;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import "@material/mwc-list/mwc-list-item";
|
|||
import { html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { formatDateTimeNumeric } from "../../common/datetime/format_date_time";
|
||||
import { resolveTimeZone } from "../../common/datetime/resolve-time-zone";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../../components/ha-card";
|
||||
import "../../components/ha-select";
|
||||
|
@ -48,10 +49,9 @@ class TimeZoneRow extends LitElement {
|
|||
>${this.hass.localize(
|
||||
`ui.panel.profile.time_zone.options.${format}`,
|
||||
{
|
||||
timezone: (format === "server"
|
||||
? this.hass.config.time_zone
|
||||
: Intl.DateTimeFormat?.().resolvedOptions?.().timeZone ||
|
||||
""
|
||||
timezone: resolveTimeZone(
|
||||
format,
|
||||
this.hass.config.time_zone
|
||||
).replace("_", " "),
|
||||
}
|
||||
)}</span
|
||||
|
|
|
@ -3,6 +3,7 @@ import { formatInTimeZone, toDate } from "date-fns-tz";
|
|||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { resolveTimeZone } from "../../common/datetime/resolve-time-zone";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||
import "../../components/ha-alert";
|
||||
|
@ -19,7 +20,6 @@ import {
|
|||
deleteItems,
|
||||
updateItem,
|
||||
} from "../../data/todo";
|
||||
import { TimeZone } from "../../data/translation";
|
||||
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
|
||||
import { haStyleDialog } from "../../resources/styles";
|
||||
import { HomeAssistant } from "../../types";
|
||||
|
@ -54,10 +54,10 @@ class DialogTodoItemEditor extends LitElement {
|
|||
public showDialog(params: TodoItemEditDialogParams): void {
|
||||
this._error = undefined;
|
||||
this._params = params;
|
||||
this._timeZone =
|
||||
this.hass.locale.time_zone === TimeZone.local
|
||||
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
: this.hass.config.time_zone;
|
||||
this._timeZone = resolveTimeZone(
|
||||
this.hass.locale.time_zone,
|
||||
this.hass.config.time_zone
|
||||
);
|
||||
if (params.item) {
|
||||
const entry = params.item;
|
||||
this._checked = entry.status === TodoItemStatus.Completed;
|
||||
|
|
|
@ -259,17 +259,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
|||
}
|
||||
this._updateHass({ areas });
|
||||
});
|
||||
subscribeConfig(conn, (config) => {
|
||||
if (this.hass?.config?.time_zone !== config.time_zone) {
|
||||
import("../resources/intl-polyfill").then(() => {
|
||||
if ("__setDefaultTimeZone" in Intl.DateTimeFormat) {
|
||||
// @ts-ignore
|
||||
Intl.DateTimeFormat.__setDefaultTimeZone(config.time_zone);
|
||||
}
|
||||
});
|
||||
}
|
||||
this._updateHass({ config });
|
||||
});
|
||||
subscribeConfig(conn, (config) => this._updateHass({ config }));
|
||||
subscribeServices(conn, (services) => this._updateHass({ services }));
|
||||
subscribePanels(conn, (panels) => this._updateHass({ panels }));
|
||||
subscribeFrontendUserData(conn, "core", (userData) =>
|
||||
|
|
Loading…
Reference in New Issue