diff --git a/gallery/src/pages/date-time/date.ts b/gallery/src/pages/date-time/date.ts
index c344f6f7cc..90776e89b1 100644
--- a/gallery/src/pages/date-time/date.ts
+++ b/gallery/src/pages/date-time/date.ts
@@ -10,7 +10,9 @@ import {
TimeFormat,
DateFormat,
FirstWeekday,
+ TimeZone,
} from "../../../../src/data/translation";
+import "@material/mwc-list/mwc-list";
@customElement("demo-date-time-date")
export class DemoDateTimeDate extends LitElement {
@@ -22,6 +24,7 @@ export class DemoDateTimeDate extends LitElement {
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
};
const date = new Date();
@@ -41,32 +44,48 @@ export class DemoDateTimeDate extends LitElement {
${value.nativeName}
- ${formatDateNumeric(date, {
- ...defaultLocale,
- language: key,
- date_format: DateFormat.language,
- })}
+ ${formatDateNumeric(
+ date,
+ {
+ ...defaultLocale,
+ language: key,
+ date_format: DateFormat.language,
+ },
+ this.hass.config
+ )}
- ${formatDateNumeric(date, {
- ...defaultLocale,
- language: key,
- date_format: DateFormat.DMY,
- })}
+ ${formatDateNumeric(
+ date,
+ {
+ ...defaultLocale,
+ language: key,
+ date_format: DateFormat.DMY,
+ },
+ this.hass.config
+ )}
- ${formatDateNumeric(date, {
- ...defaultLocale,
- language: key,
- date_format: DateFormat.MDY,
- })}
+ ${formatDateNumeric(
+ date,
+ {
+ ...defaultLocale,
+ language: key,
+ date_format: DateFormat.MDY,
+ },
+ this.hass.config
+ )}
- ${formatDateNumeric(date, {
- ...defaultLocale,
- language: key,
- date_format: DateFormat.YMD,
- })}
+ ${formatDateNumeric(
+ date,
+ {
+ ...defaultLocale,
+ language: key,
+ date_format: DateFormat.YMD,
+ },
+ this.hass.config
+ )}
`
diff --git a/gallery/src/pages/misc/entity-state.ts b/gallery/src/pages/misc/entity-state.ts
index 01beaa0507..aa0905d9b2 100644
--- a/gallery/src/pages/misc/entity-state.ts
+++ b/gallery/src/pages/misc/entity-state.ts
@@ -354,6 +354,7 @@ export class DemoEntityState extends LitElement {
hass.localize,
entry.stateObj,
hass.locale,
+ hass.config,
hass.entities
)}`,
},
diff --git a/hassio/src/components/supervisor-backup-content.ts b/hassio/src/components/supervisor-backup-content.ts
index 3480cf9aba..ded21bf63a 100644
--- a/hassio/src/components/supervisor-backup-content.ts
+++ b/hassio/src/components/supervisor-backup-content.ts
@@ -143,7 +143,11 @@ export class SupervisorBackupContent extends LitElement {
: this._localize("partial_backup")}
(${Math.ceil(this.backup.size * 10) / 10 + " MB"}) {
const _to = to ?? new Date();
if (isSameDay(from, _to)) {
- return formatTime(from, locale);
+ return formatTime(from, locale, config);
}
if (isSameYear(from, _to)) {
- return formatShortDateTime(from, locale);
+ return formatShortDateTime(from, locale, config);
}
- return formatShortDateTimeWithYear(from, locale);
+ return formatShortDateTimeWithYear(from, locale, config);
};
diff --git a/src/common/datetime/calc_date.ts b/src/common/datetime/calc_date.ts
new file mode 100644
index 0000000000..5a4da09a29
--- /dev/null
+++ b/src/common/datetime/calc_date.ts
@@ -0,0 +1,25 @@
+import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz";
+import { HassConfig } from "home-assistant-js-websocket";
+import { FrontendLocaleData, TimeZone } from "../../data/translation";
+
+const calcZonedDate = (
+ date: Date,
+ tz: string,
+ fn: (date: Date, options?: any) => Date,
+ options?
+) => {
+ const inputZoned = utcToZonedTime(date, tz);
+ const fnZoned = fn(inputZoned, options);
+ return zonedTimeToUtc(fnZoned, tz);
+};
+
+export const calcDate = (
+ date: Date,
+ fn: (date: Date, options?: any) => Date,
+ locale: FrontendLocaleData,
+ config: HassConfig,
+ options?
+) =>
+ locale.time_zone === TimeZone.server
+ ? calcZonedDate(date, config.time_zone, fn, options)
+ : fn(date, options);
diff --git a/src/common/datetime/format_date.ts b/src/common/datetime/format_date.ts
index cb6893a625..ffb48bc64e 100644
--- a/src/common/datetime/format_date.ts
+++ b/src/common/datetime/format_date.ts
@@ -1,3 +1,4 @@
+import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData, DateFormat } from "../../data/translation";
import "../../resources/intl-polyfill";
@@ -5,37 +6,44 @@ import "../../resources/intl-polyfill";
// Tuesday, August 10
export const formatDateWeekdayDay = (
dateObj: Date,
- locale: FrontendLocaleData
-) => formatDateWeekdayDayMem(locale).format(dateObj);
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateWeekdayDayMem(locale, config.time_zone).format(dateObj);
const formatDateWeekdayDayMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "long",
month: "long",
day: "numeric",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August 10, 2021
-export const formatDate = (dateObj: Date, locale: FrontendLocaleData) =>
- formatDateMem(locale).format(dateObj);
+export const formatDate = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateMem(locale, config.time_zone).format(dateObj);
const formatDateMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
month: "long",
day: "numeric",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 10/08/2021
export const formatDateNumeric = (
dateObj: Date,
- locale: FrontendLocaleData
+ locale: FrontendLocaleData,
+ config: HassConfig
) => {
- const formatter = formatDateNumericMem(locale);
+ const formatter = formatDateNumericMem(locale, config.time_zone);
if (
locale.date_format === DateFormat.language ||
@@ -67,83 +75,120 @@ export const formatDateNumeric = (
return formats[locale.date_format];
};
-const formatDateNumericMem = memoizeOne((locale: FrontendLocaleData) => {
- const localeString =
- locale.date_format === DateFormat.system ? undefined : locale.language;
+const formatDateNumericMem = memoizeOne(
+ (locale: FrontendLocaleData, serverTimeZone: string) => {
+ const localeString =
+ locale.date_format === DateFormat.system ? undefined : locale.language;
+
+ if (
+ locale.date_format === DateFormat.language ||
+ locale.date_format === DateFormat.system
+ ) {
+ return new Intl.DateTimeFormat(localeString, {
+ year: "numeric",
+ month: "numeric",
+ day: "numeric",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
+ });
+ }
- if (
- locale.date_format === DateFormat.language ||
- locale.date_format === DateFormat.system
- ) {
return new Intl.DateTimeFormat(localeString, {
year: "numeric",
month: "numeric",
day: "numeric",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
});
}
-
- return new Intl.DateTimeFormat(localeString, {
- year: "numeric",
- month: "numeric",
- day: "numeric",
- });
-});
+);
// Aug 10
-export const formatDateShort = (dateObj: Date, locale: FrontendLocaleData) =>
- formatDateShortMem(locale).format(dateObj);
+export const formatDateShort = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateShortMem(locale, config.time_zone).format(dateObj);
const formatDateShortMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
day: "numeric",
month: "short",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August 2021
export const formatDateMonthYear = (
dateObj: Date,
- locale: FrontendLocaleData
-) => formatDateMonthYearMem(locale).format(dateObj);
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateMonthYearMem(locale, config.time_zone).format(dateObj);
const formatDateMonthYearMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
month: "long",
year: "numeric",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August
-export const formatDateMonth = (dateObj: Date, locale: FrontendLocaleData) =>
- formatDateMonthMem(locale).format(dateObj);
+export const formatDateMonth = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateMonthMem(locale, config.time_zone).format(dateObj);
const formatDateMonthMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
month: "long",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 2021
-export const formatDateYear = (dateObj: Date, locale: FrontendLocaleData) =>
- formatDateYearMem(locale).format(dateObj);
+export const formatDateYear = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateYearMem(locale, config.time_zone).format(dateObj);
const formatDateYearMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// Monday
-export const formatDateWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
- formatDateWeekdayMem(locale).format(dateObj);
+export const formatDateWeekday = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateWeekdayMem(locale, config.time_zone).format(dateObj);
const formatDateWeekdayMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "long",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
+ })
+);
+
+// Mon
+export const formatDateWeekdayShort = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateWeekdayShortMem(locale, config.time_zone).format(dateObj);
+
+const formatDateWeekdayShortMem = memoizeOne(
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
+ new Intl.DateTimeFormat(locale.language, {
+ weekday: "short",
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
diff --git a/src/common/datetime/format_date_time.ts b/src/common/datetime/format_date_time.ts
index 7c38d1fd18..d9b7a3a862 100644
--- a/src/common/datetime/format_date_time.ts
+++ b/src/common/datetime/format_date_time.ts
@@ -1,16 +1,20 @@
+import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
-import { useAmPm } from "./use_am_pm";
import { formatDateNumeric } from "./format_date";
import { formatTime } from "./format_time";
+import { useAmPm } from "./use_am_pm";
// August 9, 2021, 8:23 AM
-export const formatDateTime = (dateObj: Date, locale: FrontendLocaleData) =>
- formatDateTimeMem(locale).format(dateObj);
+export const formatDateTime = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateTimeMem(locale, config.time_zone).format(dateObj);
const formatDateTimeMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -22,6 +26,7 @@ const formatDateTimeMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
@@ -29,11 +34,12 @@ const formatDateTimeMem = memoizeOne(
// Aug 9, 2021, 8:23 AM
export const formatShortDateTimeWithYear = (
dateObj: Date,
- locale: FrontendLocaleData
-) => formatShortDateTimeWithYearMem(locale).format(dateObj);
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatShortDateTimeWithYearMem(locale, config.time_zone).format(dateObj);
const formatShortDateTimeWithYearMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -45,6 +51,7 @@ const formatShortDateTimeWithYearMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
@@ -52,11 +59,12 @@ const formatShortDateTimeWithYearMem = memoizeOne(
// Aug 9, 8:23 AM
export const formatShortDateTime = (
dateObj: Date,
- locale: FrontendLocaleData
-) => formatShortDateTimeMem(locale).format(dateObj);
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatShortDateTimeMem(locale, config.time_zone).format(dateObj);
const formatShortDateTimeMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -67,6 +75,7 @@ const formatShortDateTimeMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
@@ -74,11 +83,12 @@ const formatShortDateTimeMem = memoizeOne(
// August 9, 2021, 8:23:15 AM
export const formatDateTimeWithSeconds = (
dateObj: Date,
- locale: FrontendLocaleData
-) => formatDateTimeWithSecondsMem(locale).format(dateObj);
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatDateTimeWithSecondsMem(locale, config.time_zone).format(dateObj);
const formatDateTimeWithSecondsMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -91,6 +101,7 @@ const formatDateTimeWithSecondsMem = memoizeOne(
minute: "2-digit",
second: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
@@ -98,5 +109,11 @@ const formatDateTimeWithSecondsMem = memoizeOne(
// 9/8/2021, 8:23 AM
export const formatDateTimeNumeric = (
dateObj: Date,
- locale: FrontendLocaleData
-) => `${formatDateNumeric(dateObj, locale)}, ${formatTime(dateObj, locale)}`;
+ locale: FrontendLocaleData,
+ config: HassConfig
+) =>
+ `${formatDateNumeric(dateObj, locale, config)}, ${formatTime(
+ dateObj,
+ locale,
+ config
+ )}`;
diff --git a/src/common/datetime/format_time.ts b/src/common/datetime/format_time.ts
index ec4459fe2c..41827b4f8d 100644
--- a/src/common/datetime/format_time.ts
+++ b/src/common/datetime/format_time.ts
@@ -1,14 +1,18 @@
+import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
import { useAmPm } from "./use_am_pm";
// 9:15 PM || 21:15
-export const formatTime = (dateObj: Date, locale: FrontendLocaleData) =>
- formatTimeMem(locale).format(dateObj);
+export const formatTime = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatTimeMem(locale, config.time_zone).format(dateObj);
const formatTimeMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -17,6 +21,7 @@ const formatTimeMem = memoizeOne(
hour: "numeric",
minute: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
@@ -24,11 +29,12 @@ const formatTimeMem = memoizeOne(
// 9:15:24 PM || 21:15:24
export const formatTimeWithSeconds = (
dateObj: Date,
- locale: FrontendLocaleData
-) => formatTimeWithSecondsMem(locale).format(dateObj);
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatTimeWithSecondsMem(locale, config.time_zone).format(dateObj);
const formatTimeWithSecondsMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -38,16 +44,20 @@ const formatTimeWithSecondsMem = memoizeOne(
minute: "2-digit",
second: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
// Tuesday 7:00 PM || Tuesday 19:00
-export const formatTimeWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
- formatTimeWeekdayMem(locale).format(dateObj);
+export const formatTimeWeekday = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatTimeWeekdayMem(locale, config.time_zone).format(dateObj);
const formatTimeWeekdayMem = memoizeOne(
- (locale: FrontendLocaleData) =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
@@ -57,20 +67,25 @@ const formatTimeWeekdayMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
}
)
);
// 21:15
-export const formatTime24h = (dateObj: Date) =>
- formatTime24hMem().format(dateObj);
+export const formatTime24h = (
+ dateObj: Date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => formatTime24hMem(locale, config.time_zone).format(dateObj);
const formatTime24hMem = memoizeOne(
- () =>
+ (locale: FrontendLocaleData, serverTimeZone: string) =>
// en-GB to fix Chrome 24:59 to 0:59 https://stackoverflow.com/a/60898146
new Intl.DateTimeFormat("en-GB", {
hour: "numeric",
minute: "2-digit",
hour12: false,
+ timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
diff --git a/src/common/entity/compute_attribute_display.ts b/src/common/entity/compute_attribute_display.ts
index 5fdfabe7a8..1d5d8af8a4 100644
--- a/src/common/entity/compute_attribute_display.ts
+++ b/src/common/entity/compute_attribute_display.ts
@@ -1,4 +1,4 @@
-import { HassEntity } from "home-assistant-js-websocket";
+import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import { html, TemplateResult } from "lit";
import { until } from "lit/directives/until";
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
@@ -20,6 +20,7 @@ export const computeAttributeValueDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
+ config: HassConfig,
entities: HomeAssistant["entities"],
attribute: string,
value?: any
@@ -59,14 +60,14 @@ export const computeAttributeValueDisplay = (
if (isTimestamp(attributeValue)) {
const date = new Date(attributeValue);
if (checkValidDate(date)) {
- return formatDateTimeWithSeconds(date, locale);
+ return formatDateTimeWithSeconds(date, locale, config);
}
}
// Value was not a timestamp, so only do date formatting
const date = new Date(attributeValue);
if (checkValidDate(date)) {
- return formatDate(date, locale);
+ return formatDate(date, locale, config);
}
}
}
@@ -92,6 +93,7 @@ export const computeAttributeValueDisplay = (
localize,
stateObj,
locale,
+ config,
entities,
attribute,
item
diff --git a/src/common/entity/compute_state_display.ts b/src/common/entity/compute_state_display.ts
index a35b8cf780..34db8700d1 100644
--- a/src/common/entity/compute_state_display.ts
+++ b/src/common/entity/compute_state_display.ts
@@ -1,7 +1,7 @@
-import { HassEntity } from "home-assistant-js-websocket";
+import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
-import { FrontendLocaleData } from "../../data/translation";
+import { FrontendLocaleData, TimeZone } from "../../data/translation";
import {
updateIsInstallingFromAttributes,
UPDATE_SUPPORT_PROGRESS,
@@ -28,12 +28,14 @@ export const computeStateDisplaySingleEntity = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
+ config: HassConfig,
entity: EntityRegistryDisplayEntry | undefined,
state?: string
): string =>
computeStateDisplayFromEntityAttributes(
localize,
locale,
+ config,
entity,
stateObj.entity_id,
stateObj.attributes,
@@ -44,6 +46,7 @@ export const computeStateDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
+ config: HassConfig,
entities: HomeAssistant["entities"],
state?: string
): string => {
@@ -54,6 +57,7 @@ export const computeStateDisplay = (
return computeStateDisplayFromEntityAttributes(
localize,
locale,
+ config,
entity,
stateObj.entity_id,
stateObj.attributes,
@@ -64,6 +68,7 @@ export const computeStateDisplay = (
export const computeStateDisplayFromEntityAttributes = (
localize: LocalizeFunc,
locale: FrontendLocaleData,
+ config: HassConfig,
entity: EntityRegistryDisplayEntry | undefined,
entityId: string,
attributes: any,
@@ -119,29 +124,40 @@ export const computeStateDisplayFromEntityAttributes = (
if (domain === "datetime") {
const time = new Date(state);
- return formatDateTime(time, locale);
+ return formatDateTime(time, locale, config);
}
if (["date", "input_datetime", "time"].includes(domain)) {
// If trying to display an explicit state, need to parse the explicit state to `Date` then format.
// Attributes aren't available, we have to use `state`.
+
+ // These are timezone agnostic, so we should NOT use the system timezone here.
try {
const components = state.split(" ");
if (components.length === 2) {
// Date and time.
- return formatDateTime(new Date(components.join("T")), locale);
+ return formatDateTime(
+ new Date(components.join("T")),
+ { ...locale, time_zone: TimeZone.local },
+ config
+ );
}
if (components.length === 1) {
if (state.includes("-")) {
// Date only.
- return formatDate(new Date(`${state}T00:00`), locale);
+ return formatDate(
+ new Date(`${state}T00:00`),
+ { ...locale, time_zone: TimeZone.local },
+ config
+ );
}
if (state.includes(":")) {
// Time only.
const now = new Date();
return formatTime(
new Date(`${now.toISOString().split("T")[0]}T${state}`),
- locale
+ { ...locale, time_zone: TimeZone.local },
+ config
);
}
}
@@ -179,7 +195,7 @@ export const computeStateDisplayFromEntityAttributes = (
(domain === "sensor" && attributes.device_class === "timestamp")
) {
try {
- return formatDateTime(new Date(state), locale);
+ return formatDateTime(new Date(state), locale, config);
} catch (_err) {
return state;
}
diff --git a/src/common/translations/day_names.ts b/src/common/translations/day_names.ts
index 34b18fdb4a..885cd84029 100644
--- a/src/common/translations/day_names.ts
+++ b/src/common/translations/day_names.ts
@@ -1,10 +1,12 @@
import { addDays, startOfWeek } from "date-fns";
+import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import { formatDateWeekday } from "../datetime/format_date";
-export const dayNames = memoizeOne((locale: FrontendLocaleData): string[] =>
- Array.from({ length: 7 }, (_, d) =>
- formatDateWeekday(addDays(startOfWeek(new Date()), d), locale)
- )
+export const dayNames = memoizeOne(
+ (locale: FrontendLocaleData, config: HassConfig): string[] =>
+ Array.from({ length: 7 }, (_, d) =>
+ formatDateWeekday(addDays(startOfWeek(new Date()), d), locale, config)
+ )
);
diff --git a/src/common/translations/month_names.ts b/src/common/translations/month_names.ts
index 2e456b1855..4df4236d28 100644
--- a/src/common/translations/month_names.ts
+++ b/src/common/translations/month_names.ts
@@ -1,10 +1,12 @@
import { addMonths, startOfYear } from "date-fns";
+import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import { formatDateMonth } from "../datetime/format_date";
-export const monthNames = memoizeOne((locale: FrontendLocaleData): string[] =>
- Array.from({ length: 12 }, (_, m) =>
- formatDateMonth(addMonths(startOfYear(new Date()), m), locale)
- )
+export const monthNames = memoizeOne(
+ (locale: FrontendLocaleData, config: HassConfig): string[] =>
+ Array.from({ length: 12 }, (_, m) =>
+ formatDateMonth(addMonths(startOfYear(new Date()), m), locale, config)
+ )
);
diff --git a/src/components/chart/chart-date-adapter.ts b/src/components/chart/chart-date-adapter.ts
index 462ee52dc1..f348823a29 100644
--- a/src/components/chart/chart-date-adapter.ts
+++ b/src/components/chart/chart-date-adapter.ts
@@ -80,33 +80,89 @@ _adapters._date.override({
format: function (time, fmt: keyof typeof FORMATS) {
switch (fmt) {
case "datetime":
- return formatDateTime(new Date(time), this.options.locale);
+ return formatDateTime(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "datetimeseconds":
- return formatDateTimeWithSeconds(new Date(time), this.options.locale);
+ return formatDateTimeWithSeconds(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "millisecond":
- return formatTimeWithSeconds(new Date(time), this.options.locale);
+ return formatTimeWithSeconds(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "second":
- return formatTimeWithSeconds(new Date(time), this.options.locale);
+ return formatTimeWithSeconds(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "minute":
- return formatTime(new Date(time), this.options.locale);
+ return formatTime(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "hour":
- return formatTime(new Date(time), this.options.locale);
+ return formatTime(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "weekday":
- return formatDateWeekdayDay(new Date(time), this.options.locale);
+ return formatDateWeekdayDay(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "date":
- return formatDate(new Date(time), this.options.locale);
+ return formatDate(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "day":
- return formatDateShort(new Date(time), this.options.locale);
+ return formatDateShort(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "week":
- return formatDate(new Date(time), this.options.locale);
+ return formatDate(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "month":
- return formatDateMonth(new Date(time), this.options.locale);
+ return formatDateMonth(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "monthyear":
- return formatDateMonthYear(new Date(time), this.options.locale);
+ return formatDateMonthYear(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "quarter":
- return formatDate(new Date(time), this.options.locale);
+ return formatDate(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
case "year":
- return formatDateYear(new Date(time), this.options.locale);
+ return formatDateYear(
+ new Date(time),
+ this.options.locale,
+ this.options.config
+ );
default:
return "";
}
diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts
index 3ce2235320..50f164c094 100644
--- a/src/components/chart/state-history-chart-line.ts
+++ b/src/components/chart/state-history-chart-line.ts
@@ -71,6 +71,7 @@ class StateHistoryChartLine extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
+ config: this.hass.config,
},
},
suggestedMax: this.endTime,
diff --git a/src/components/chart/state-history-chart-timeline.ts b/src/components/chart/state-history-chart-timeline.ts
index 2d9b93b413..b1686aa2ab 100644
--- a/src/components/chart/state-history-chart-timeline.ts
+++ b/src/components/chart/state-history-chart-timeline.ts
@@ -98,6 +98,7 @@ export class StateHistoryChartTimeline extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
+ config: this.hass.config,
},
},
suggestedMin: this.startTime,
@@ -181,8 +182,16 @@ export class StateHistoryChartTimeline extends LitElement {
return [
d.label || "",
- formatDateTimeWithSeconds(d.start, this.hass.locale),
- formatDateTimeWithSeconds(d.end, this.hass.locale),
+ formatDateTimeWithSeconds(
+ d.start,
+ this.hass.locale,
+ this.hass.config
+ ),
+ formatDateTimeWithSeconds(
+ d.end,
+ this.hass.locale,
+ this.hass.config
+ ),
formattedDuration,
];
},
diff --git a/src/components/chart/statistics-chart.ts b/src/components/chart/statistics-chart.ts
index 014e658417..d9f30d9d67 100644
--- a/src/components/chart/statistics-chart.ts
+++ b/src/components/chart/statistics-chart.ts
@@ -146,6 +146,7 @@ class StatisticsChart extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
+ config: this.hass.config,
},
},
ticks: {
diff --git a/src/components/entity/ha-entity-state-picker.ts b/src/components/entity/ha-entity-state-picker.ts
index 7b92f63aa2..688b38e6db 100644
--- a/src/components/entity/ha-entity-state-picker.ts
+++ b/src/components/entity/ha-entity-state-picker.ts
@@ -62,6 +62,7 @@ class HaEntityStatePicker extends LitElement {
this.hass.localize,
state,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
key
)
@@ -69,6 +70,7 @@ class HaEntityStatePicker extends LitElement {
this.hass.localize,
state,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
this.attribute,
key
diff --git a/src/components/entity/ha-state-label-badge.ts b/src/components/entity/ha-state-label-badge.ts
index b5d60d9bb1..519dbfc107 100644
--- a/src/components/entity/ha-state-label-badge.ts
+++ b/src/components/entity/ha-state-label-badge.ts
@@ -192,6 +192,7 @@ export class HaStateLabelBadge extends LitElement {
this.hass!.localize,
entityState,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities
);
}
diff --git a/src/components/ha-absolute-time.ts b/src/components/ha-absolute-time.ts
index f782b32317..528c658514 100644
--- a/src/components/ha-absolute-time.ts
+++ b/src/components/ha-absolute-time.ts
@@ -64,7 +64,11 @@ class HaAbsoluteTime extends ReactiveElement {
if (!this.datetime) {
this.innerHTML = this.hass.localize("ui.components.absolute_time.never");
} else {
- this.innerHTML = absoluteTime(new Date(this.datetime), this.hass.locale);
+ this.innerHTML = absoluteTime(
+ new Date(this.datetime),
+ this.hass.locale,
+ this.hass.config
+ );
}
}
}
diff --git a/src/components/ha-attributes.ts b/src/components/ha-attributes.ts
index c1092cb96f..dce1fd4c07 100644
--- a/src/components/ha-attributes.ts
+++ b/src/components/ha-attributes.ts
@@ -62,6 +62,7 @@ class HaAttributes extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
attribute
)}
diff --git a/src/components/ha-climate-state.ts b/src/components/ha-climate-state.ts
index 7c8be97a6e..7a1617e4ee 100644
--- a/src/components/ha-climate-state.ts
+++ b/src/components/ha-climate-state.ts
@@ -28,6 +28,7 @@ class HaClimateState extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"preset_mode"
)}`
@@ -136,6 +137,7 @@ class HaClimateState extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
);
@@ -144,6 +146,7 @@ class HaClimateState extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"hvac_action"
)} (${stateString})`
diff --git a/src/components/ha-date-input.ts b/src/components/ha-date-input.ts
index 2b1cc6fe22..d3b5a0607e 100644
--- a/src/components/ha-date-input.ts
+++ b/src/components/ha-date-input.ts
@@ -1,9 +1,11 @@
import { mdiCalendar } from "@mdi/js";
+import { HassConfig } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
-import { formatDateNumeric } from "../common/datetime/format_date";
import { firstWeekdayIndex } from "../common/datetime/first_weekday";
+import { formatDateNumeric } from "../common/datetime/format_date";
import { fireEvent } from "../common/dom/fire_event";
+import { TimeZone } from "../data/translation";
import { HomeAssistant } from "../types";
import "./ha-svg-icon";
import "./ha-textfield";
@@ -59,7 +61,11 @@ export class HaDateInput extends LitElement {
.value=${this.value
? formatDateNumeric(
new Date(`${this.value.split("T")[0]}T00:00:00`),
- this.locale
+ {
+ ...this.locale,
+ time_zone: TimeZone.local,
+ },
+ {} as HassConfig
)
: ""}
.required=${this.required}
diff --git a/src/components/ha-date-range-picker.ts b/src/components/ha-date-range-picker.ts
index 5c870215a7..557d139ae3 100644
--- a/src/components/ha-date-range-picker.ts
+++ b/src/components/ha-date-range-picker.ts
@@ -3,6 +3,13 @@ import "@material/mwc-list/mwc-list";
import { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import "@material/mwc-list/mwc-list-item";
import { mdiCalendar } from "@mdi/js";
+import {
+ addDays,
+ endOfDay,
+ endOfWeek,
+ startOfDay,
+ startOfWeek,
+} from "date-fns";
import {
css,
CSSResultGroup,
@@ -12,10 +19,11 @@ import {
TemplateResult,
} from "lit";
import { customElement, property } from "lit/decorators";
-import { formatDateTime } from "../common/datetime/format_date_time";
-import { formatDate } from "../common/datetime/format_date";
-import { useAmPm } from "../common/datetime/use_am_pm";
+import { calcDate } from "../common/datetime/calc_date";
import { firstWeekdayIndex } from "../common/datetime/first_weekday";
+import { formatDate } from "../common/datetime/format_date";
+import { formatDateTime } from "../common/datetime/format_date_time";
+import { useAmPm } from "../common/datetime/use_am_pm";
import { computeRTLDirection } from "../common/util/compute_rtl";
import { HomeAssistant } from "../types";
import "./date-range-picker";
@@ -34,7 +42,7 @@ export class HaDateRangePicker extends LitElement {
@property() public endDate!: Date;
- @property() public ranges?: DateRangePickerRanges;
+ @property() public ranges?: DateRangePickerRanges | false;
@property() public autoApply = false;
@@ -46,6 +54,70 @@ export class HaDateRangePicker extends LitElement {
@property({ type: String }) private _rtlDirection = "ltr";
+ protected willUpdate() {
+ if (!this.hasUpdated && this.ranges === undefined) {
+ const today = new Date();
+ const weekStartsOn = firstWeekdayIndex(this.hass.locale);
+ const weekStart = calcDate(
+ today,
+ startOfWeek,
+ this.hass.locale,
+ this.hass.config,
+ {
+ weekStartsOn,
+ }
+ );
+ const weekEnd = calcDate(
+ today,
+ endOfWeek,
+ this.hass.locale,
+ this.hass.config,
+ {
+ weekStartsOn,
+ }
+ );
+
+ this.ranges = {
+ [this.hass.localize("ui.components.date-range-picker.ranges.today")]: [
+ calcDate(today, startOfDay, this.hass.locale, this.hass.config, {
+ weekStartsOn,
+ }),
+ calcDate(today, endOfDay, this.hass.locale, this.hass.config, {
+ weekStartsOn,
+ }),
+ ],
+ [this.hass.localize(
+ "ui.components.date-range-picker.ranges.yesterday"
+ )]: [
+ calcDate(
+ addDays(today, -1),
+ startOfDay,
+ this.hass.locale,
+ this.hass.config,
+ {
+ weekStartsOn,
+ }
+ ),
+ calcDate(
+ addDays(today, -1),
+ endOfDay,
+ this.hass.locale,
+ this.hass.config,
+ {
+ weekStartsOn,
+ }
+ ),
+ ],
+ [this.hass.localize(
+ "ui.components.date-range-picker.ranges.this_week"
+ )]: [weekStart, weekEnd],
+ [this.hass.localize(
+ "ui.components.date-range-picker.ranges.last_week"
+ )]: [addDays(weekStart, -7), addDays(weekEnd, -7)],
+ };
+ }
+ }
+
protected updated(changedProps: PropertyValues) {
if (changedProps.has("hass")) {
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
@@ -65,15 +137,19 @@ export class HaDateRangePicker extends LitElement {
twentyfour-hours=${this._hour24format}
start-date=${this.startDate}
end-date=${this.endDate}
- ?ranges=${this.ranges !== undefined}
+ ?ranges=${this.ranges !== false}
first-day=${firstWeekdayIndex(this.hass.locale)}
>
${result
? html`Result:
diff --git a/src/components/trace/hat-trace-timeline.ts b/src/components/trace/hat-trace-timeline.ts
index 7bd01cd431..2396c65879 100644
--- a/src/components/trace/hat-trace-timeline.ts
+++ b/src/components/trace/hat-trace-timeline.ts
@@ -335,7 +335,8 @@ class ActionRenderer {
} at
${formatDateTimeWithSeconds(
new Date(triggerStep.timestamp),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}`,
mdiCircle
);
@@ -632,7 +633,8 @@ export class HaAutomationTracer extends LitElement {
const renderFinishedAt = () =>
formatDateTimeWithSeconds(
new Date(this.trace!.timestamp.finish!),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
);
const renderRuntime = () => `(runtime:
${(
diff --git a/src/data/automation_i18n.ts b/src/data/automation_i18n.ts
index d989b8617f..ab4c0056ea 100644
--- a/src/data/automation_i18n.ts
+++ b/src/data/automation_i18n.ts
@@ -1,26 +1,27 @@
+import { HassConfig } from "home-assistant-js-websocket";
+import { ensureArray } from "../common/array/ensure-array";
import { formatDuration } from "../common/datetime/format_duration";
import {
formatTime,
formatTimeWithSeconds,
} from "../common/datetime/format_time";
-import { FrontendLocaleData } from "./translation";
import secondsToDuration from "../common/datetime/seconds_to_duration";
-import { ensureArray } from "../common/array/ensure-array";
+import {
+ computeAttributeNameDisplay,
+ computeAttributeValueDisplay,
+} from "../common/entity/compute_attribute_display";
+import { computeStateDisplay } from "../common/entity/compute_state_display";
import { computeStateName } from "../common/entity/compute_state_name";
import type { HomeAssistant } from "../types";
-import { Condition, Trigger, ForDict } from "./automation";
+import { Condition, ForDict, Trigger } from "./automation";
import {
DeviceCondition,
DeviceTrigger,
localizeDeviceAutomationCondition,
localizeDeviceAutomationTrigger,
} from "./device_automation";
-import {
- computeAttributeNameDisplay,
- computeAttributeValueDisplay,
-} from "../common/entity/compute_attribute_display";
-import { computeStateDisplay } from "../common/entity/compute_state_display";
import { EntityRegistryEntry } from "./entity_registry";
+import { FrontendLocaleData } from "./translation";
const describeDuration = (forTime: number | string | ForDict) => {
let duration: string | null;
@@ -34,7 +35,11 @@ const describeDuration = (forTime: number | string | ForDict) => {
return duration;
};
-const localizeTimeString = (time: string, locale: FrontendLocaleData) => {
+const localizeTimeString = (
+ time: string,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => {
const chunks = time.split(":");
if (chunks.length < 2 || chunks.length > 3) {
return time;
@@ -42,9 +47,9 @@ const localizeTimeString = (time: string, locale: FrontendLocaleData) => {
try {
const dt = new Date("1970-01-01T" + time);
if (chunks.length === 2 || Number(chunks[2]) === 0) {
- return formatTime(dt, locale);
+ return formatTime(dt, locale, config);
}
- return formatTimeWithSeconds(dt, locale);
+ return formatTimeWithSeconds(dt, locale, config);
} catch {
return time;
}
@@ -209,6 +214,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
trigger.attribute,
state
@@ -217,6 +223,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
state
)
@@ -232,6 +239,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
trigger.attribute,
trigger.from
@@ -240,6 +248,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
trigger.from.toString()
).toString()
@@ -263,6 +272,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
trigger.attribute,
state
@@ -271,6 +281,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
state
).toString()
@@ -286,6 +297,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
trigger.attribute,
trigger.to
@@ -294,6 +306,7 @@ export const describeTrigger = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
trigger.to.toString()
).toString()
@@ -353,7 +366,7 @@ export const describeTrigger = (
? at
: at.includes(".")
? `entity ${hass.states[at] ? computeStateName(hass.states[at]) : at}`
- : localizeTimeString(at, hass.locale)
+ : localizeTimeString(at, hass.locale, hass.config)
);
const last = result.splice(-1, 1)[0];
@@ -738,6 +751,7 @@ export const describeCondition = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
condition.attribute,
state
@@ -746,6 +760,7 @@ export const describeCondition = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
state
)
@@ -758,6 +773,7 @@ export const describeCondition = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
condition.attribute,
condition.state
@@ -766,6 +782,7 @@ export const describeCondition = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
condition.state.toString()
).toString()
@@ -830,7 +847,7 @@ export const describeCondition = (
? computeStateName(hass.states[condition.before])
: condition.before
}`
- : localizeTimeString(condition.before, hass.locale);
+ : localizeTimeString(condition.before, hass.locale, hass.config);
const after =
typeof condition.after !== "string"
@@ -841,7 +858,7 @@ export const describeCondition = (
? computeStateName(hass.states[condition.after])
: condition.after
}`
- : localizeTimeString(condition.after, hass.locale);
+ : localizeTimeString(condition.after, hass.locale, hass.config);
let result = "Confirm the ";
if (after || before) {
diff --git a/src/data/context.ts b/src/data/context.ts
index f62e666ebe..7fbff9fd06 100644
--- a/src/data/context.ts
+++ b/src/data/context.ts
@@ -1,4 +1,5 @@
import { createContext } from "@lit-labs/context";
+import { HassConfig } from "home-assistant-js-websocket";
import { HomeAssistant } from "../types";
import { EntityRegistryEntry } from "./entity_registry";
@@ -11,7 +12,7 @@ export const areasContext = createContext
("areas");
export const localizeContext =
createContext("localize");
export const localeContext = createContext("locale");
-export const configContext = createContext("config");
+export const configContext = createContext("config");
export const themesContext = createContext("themes");
export const selectedThemeContext =
createContext("selectedTheme");
diff --git a/src/data/energy.ts b/src/data/energy.ts
index 151089d929..1e1fbd3c5e 100644
--- a/src/data/energy.ts
+++ b/src/data/energy.ts
@@ -4,12 +4,12 @@ import {
addMilliseconds,
addMonths,
differenceInDays,
- endOfToday,
- endOfYesterday,
- startOfToday,
- startOfYesterday,
+ endOfDay,
+ startOfDay,
} from "date-fns/esm";
import { Collection, getCollection } from "home-assistant-js-websocket";
+import { calcDate } from "../common/datetime/calc_date";
+import { formatTime24h } from "../common/datetime/format_time";
import { groupBy } from "../common/util/group-by";
import { HomeAssistant } from "../types";
import { ConfigEntry, getConfigEntries } from "./config_entries";
@@ -626,18 +626,40 @@ export const getEnergyDataCollection = (
collection._active = 0;
collection.prefs = options.prefs;
const now = new Date();
+ const hour = formatTime24h(now, hass.locale, hass.config).split(":")[0];
// Set start to start of today if we have data for today, otherwise yesterday
- collection.start = now.getHours() > 0 ? startOfToday() : startOfYesterday();
- collection.end = now.getHours() > 0 ? endOfToday() : endOfYesterday();
+ collection.start = calcDate(
+ hour === "0" ? addDays(now, -1) : now,
+ startOfDay,
+ hass.locale,
+ hass.config
+ );
+ collection.end = calcDate(
+ hour === "0" ? addDays(now, -1) : now,
+ endOfDay,
+ hass.locale,
+ hass.config
+ );
const scheduleUpdatePeriod = () => {
collection._updatePeriodTimeout = window.setTimeout(
() => {
- collection.start = startOfToday();
- collection.end = endOfToday();
+ collection.start = calcDate(
+ new Date(),
+ startOfDay,
+ hass.locale,
+ hass.config
+ );
+ collection.end = calcDate(
+ new Date(),
+ endOfDay,
+ hass.locale,
+ hass.config
+ );
scheduleUpdatePeriod();
},
- addHours(endOfToday(), 1).getTime() - Date.now() // Switch to next day an hour after the day changed
+ addHours(calcDate(now, endOfDay, hass.locale, hass.config), 1).getTime() -
+ Date.now() // Switch to next day an hour after the day changed
);
};
scheduleUpdatePeriod();
@@ -649,8 +671,10 @@ export const getEnergyDataCollection = (
collection.start = newStart;
collection.end = newEnd;
if (
- collection.start.getTime() === startOfToday().getTime() &&
- collection.end?.getTime() === endOfToday().getTime() &&
+ collection.start.getTime() ===
+ calcDate(new Date(), startOfDay, hass.locale, hass.config).getTime() &&
+ collection.end?.getTime() ===
+ calcDate(new Date(), endOfDay, hass.locale, hass.config).getTime() &&
!collection._updatePeriodTimeout
) {
scheduleUpdatePeriod();
diff --git a/src/data/history.ts b/src/data/history.ts
index dcc37a45a3..8202f44167 100644
--- a/src/data/history.ts
+++ b/src/data/history.ts
@@ -1,4 +1,5 @@
import {
+ HassConfig,
HassEntities,
HassEntity,
HassEntityAttributeBase,
@@ -269,7 +270,8 @@ const equalState = (obj1: LineChartState, obj2: LineChartState) =>
const processTimelineEntity = (
localize: LocalizeFunc,
- language: FrontendLocaleData,
+ locale: FrontendLocaleData,
+ config: HassConfig,
entities: HomeAssistant["entities"],
entityId: string,
states: EntityHistoryState[],
@@ -290,7 +292,8 @@ const processTimelineEntity = (
data.push({
state_localize: computeStateDisplayFromEntityAttributes(
localize,
- language,
+ locale,
+ config,
entities[entityId],
entityId,
{
@@ -441,6 +444,7 @@ export const computeHistory = (
processTimelineEntity(
localize,
hass.locale,
+ hass.config,
hass.entities,
entityId,
stateInfo,
diff --git a/src/data/logbook.ts b/src/data/logbook.ts
index c191ed8535..a30b9cde02 100644
--- a/src/data/logbook.ts
+++ b/src/data/logbook.ts
@@ -439,6 +439,7 @@ export const localizeStateMessage = (
localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
state
)
diff --git a/src/data/timer.ts b/src/data/timer.ts
index a06a865bf3..5401175d41 100644
--- a/src/data/timer.ts
+++ b/src/data/timer.ts
@@ -94,6 +94,7 @@ export const computeDisplayTimer = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities
);
}
@@ -105,6 +106,7 @@ export const computeDisplayTimer = (
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities
)})`;
}
diff --git a/src/data/translation.ts b/src/data/translation.ts
index fb6fdaeeb9..b64e557b6b 100644
--- a/src/data/translation.ts
+++ b/src/data/translation.ts
@@ -17,6 +17,11 @@ export enum TimeFormat {
twenty_four = "24",
}
+export enum TimeZone {
+ local = "local",
+ server = "server",
+}
+
export enum DateFormat {
language = "language",
system = "system",
@@ -42,6 +47,7 @@ export interface FrontendLocaleData {
time_format: TimeFormat;
date_format: DateFormat;
first_weekday: FirstWeekday;
+ time_zone: TimeZone;
}
declare global {
diff --git a/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts b/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts
index d40e88816e..72333bd2a2 100644
--- a/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts
+++ b/src/dialogs/more-info/components/fan/ha-more-info-fan-speed.ts
@@ -72,6 +72,7 @@ export class HaMoreInfoFanSpeed extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
speed
);
diff --git a/src/dialogs/more-info/components/ha-more-info-state-header.ts b/src/dialogs/more-info/components/ha-more-info-state-header.ts
index 1e7430cb23..150058e89b 100644
--- a/src/dialogs/more-info/components/ha-more-info-state-header.ts
+++ b/src/dialogs/more-info/components/ha-more-info-state-header.ts
@@ -39,6 +39,7 @@ export class HaMoreInfoStateHeader extends LitElement {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities
);
diff --git a/src/dialogs/more-info/controls/more-info-climate.ts b/src/dialogs/more-info/controls/more-info-climate.ts
index 52a4b0aa14..9294e06855 100644
--- a/src/dialogs/more-info/controls/more-info-climate.ts
+++ b/src/dialogs/more-info/controls/more-info-climate.ts
@@ -203,6 +203,7 @@ class MoreInfoClimate extends LitElement {
hass.localize,
stateObj,
hass.locale,
+ this.hass.config,
hass.entities,
mode
)}
@@ -236,6 +237,7 @@ class MoreInfoClimate extends LitElement {
hass.localize,
stateObj,
hass.locale,
+ hass.config,
hass.entities,
"preset_mode",
mode
@@ -270,6 +272,7 @@ class MoreInfoClimate extends LitElement {
hass.localize,
stateObj,
hass.locale,
+ this.hass.config,
hass.entities,
"fan_mode",
mode
@@ -304,6 +307,7 @@ class MoreInfoClimate extends LitElement {
hass.localize,
stateObj,
hass.locale,
+ this.hass.config,
hass.entities,
"swing_mode",
mode
diff --git a/src/dialogs/more-info/controls/more-info-cover.ts b/src/dialogs/more-info/controls/more-info-cover.ts
index b4fe8114ba..7fd9d9a8ac 100644
--- a/src/dialogs/more-info/controls/more-info-cover.ts
+++ b/src/dialogs/more-info/controls/more-info-cover.ts
@@ -83,6 +83,7 @@ class MoreInfoCover extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
forcedState
);
diff --git a/src/dialogs/more-info/controls/more-info-fan.ts b/src/dialogs/more-info/controls/more-info-fan.ts
index af32733d77..588397c5ce 100644
--- a/src/dialogs/more-info/controls/more-info-fan.ts
+++ b/src/dialogs/more-info/controls/more-info-fan.ts
@@ -119,6 +119,7 @@ class MoreInfoFan extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
forcedState
);
@@ -281,6 +282,7 @@ class MoreInfoFan extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"preset_mode",
this._presetMode
@@ -307,6 +309,7 @@ class MoreInfoFan extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"preset_mode",
mode
diff --git a/src/dialogs/more-info/controls/more-info-humidifier.ts b/src/dialogs/more-info/controls/more-info-humidifier.ts
index 1e6d270d9d..527c82461f 100644
--- a/src/dialogs/more-info/controls/more-info-humidifier.ts
+++ b/src/dialogs/more-info/controls/more-info-humidifier.ts
@@ -83,6 +83,7 @@ class MoreInfoHumidifier extends LitElement {
hass.localize,
stateObj,
hass.locale,
+ this.hass.config,
hass.entities,
"mode",
mode
diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts
index f40b41977b..45597b228d 100644
--- a/src/dialogs/more-info/controls/more-info-light.ts
+++ b/src/dialogs/more-info/controls/more-info-light.ts
@@ -240,6 +240,7 @@ class MoreInfoLight extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"effect",
this._effect
@@ -261,6 +262,7 @@ class MoreInfoLight extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"effect",
effect
diff --git a/src/dialogs/more-info/controls/more-info-media_player.ts b/src/dialogs/more-info/controls/more-info-media_player.ts
index c6b4d34840..b02fc75e9d 100644
--- a/src/dialogs/more-info/controls/more-info-media_player.ts
+++ b/src/dialogs/more-info/controls/more-info-media_player.ts
@@ -163,6 +163,7 @@ class MoreInfoMediaPlayer extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"source",
source
@@ -196,6 +197,7 @@ class MoreInfoMediaPlayer extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"sound_mode",
mode
diff --git a/src/dialogs/more-info/controls/more-info-remote.ts b/src/dialogs/more-info/controls/more-info-remote.ts
index 4d486fb5d4..9080897c13 100644
--- a/src/dialogs/more-info/controls/more-info-remote.ts
+++ b/src/dialogs/more-info/controls/more-info-remote.ts
@@ -44,6 +44,7 @@ class MoreInfoRemote extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"activity",
activity
diff --git a/src/dialogs/more-info/controls/more-info-sun.ts b/src/dialogs/more-info/controls/more-info-sun.ts
index 537fb95f78..28f5727e43 100644
--- a/src/dialogs/more-info/controls/more-info-sun.ts
+++ b/src/dialogs/more-info/controls/more-info-sun.ts
@@ -44,7 +44,8 @@ class MoreInfoSun extends LitElement {
${formatTime(
item === "ris" ? risingDate : settingDate,
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
diff --git a/src/dialogs/more-info/controls/more-info-vacuum.ts b/src/dialogs/more-info/controls/more-info-vacuum.ts
index 652a3eb785..dfa940e31f 100644
--- a/src/dialogs/more-info/controls/more-info-vacuum.ts
+++ b/src/dialogs/more-info/controls/more-info-vacuum.ts
@@ -119,6 +119,7 @@ class MoreInfoVacuum extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"status"
) ||
@@ -126,6 +127,7 @@ class MoreInfoVacuum extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
@@ -201,6 +203,7 @@ class MoreInfoVacuum extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"fan_speed",
mode
@@ -218,6 +221,7 @@ class MoreInfoVacuum extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"fan_speed"
)}
diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts
index 0b4a80ad93..628886339d 100644
--- a/src/dialogs/more-info/controls/more-info-weather.ts
+++ b/src/dialogs/more-info/controls/more-info-weather.ts
@@ -164,7 +164,8 @@ class MoreInfoWeather extends LitElement {
${formatTimeWeekday(
new Date(item.datetime),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
`
@@ -172,7 +173,8 @@ class MoreInfoWeather extends LitElement {
${formatDateWeekdayDay(
new Date(item.datetime),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
`}
diff --git a/src/dialogs/notifications/configurator-notification-item.ts b/src/dialogs/notifications/configurator-notification-item.ts
index 47c7be0750..96174e02a1 100644
--- a/src/dialogs/notifications/configurator-notification-item.ts
+++ b/src/dialogs/notifications/configurator-notification-item.ts
@@ -38,6 +38,7 @@ export class HuiConfiguratorNotificationItem extends LitElement {
this.hass.localize,
this.notification,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
diff --git a/src/dialogs/notifications/persistent-notification-item.ts b/src/dialogs/notifications/persistent-notification-item.ts
index 310a6b93b9..40ce7e6b2f 100644
--- a/src/dialogs/notifications/persistent-notification-item.ts
+++ b/src/dialogs/notifications/persistent-notification-item.ts
@@ -82,7 +82,7 @@ export class HuiPersistentNotificationItem extends LitElement {
}
const d = new Date(notification.created_at!);
- return formatDateTime(d, hass.locale);
+ return formatDateTime(d, hass.locale, hass.config);
}
}
diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts
index 6116fbc015..3da61ed4fe 100644
--- a/src/fake_data/provide_hass.ts
+++ b/src/fake_data/provide_hass.ts
@@ -11,6 +11,7 @@ import {
NumberFormat,
DateFormat,
TimeFormat,
+ TimeZone,
} from "../data/translation";
import { translationMetadata } from "../resources/translations-metadata";
import { HomeAssistant } from "../types";
@@ -230,6 +231,7 @@ export const provideHass = (
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
},
resources: null as any,
diff --git a/src/panels/calendar/dialog-calendar-event-detail.ts b/src/panels/calendar/dialog-calendar-event-detail.ts
index aba011143a..6172e79b4c 100644
--- a/src/panels/calendar/dialog-calendar-event-detail.ts
+++ b/src/panels/calendar/dialog-calendar-event-detail.ts
@@ -154,23 +154,28 @@ class DialogCalendarEventDetail extends LitElement {
if (isSameDay(start, end)) {
if (isDate(this._data.dtstart)) {
// Single date string only
- return formatDate(start, this.hass.locale);
+ return formatDate(start, this.hass.locale, this.hass.config);
}
// Single day with a start/end time range
- return `${formatDate(start, this.hass.locale)} ${formatTime(
+ return `${formatDate(
start,
- this.hass.locale
- )} - ${formatTime(end, this.hass.locale)}`;
+ this.hass.locale,
+ this.hass.config
+ )} ${formatTime(
+ start,
+ this.hass.locale,
+ this.hass.config
+ )} - ${formatTime(end, this.hass.locale, this.hass.config)}`;
}
// An event across multiple dates, optionally with a time range
return `${
isDate(this._data.dtstart)
- ? formatDate(start, this.hass.locale)
- : formatDateTime(start, this.hass.locale)
+ ? formatDate(start, this.hass.locale, this.hass.config)
+ : formatDateTime(start, this.hass.locale, this.hass.config)
} - ${
isDate(this._data.dtend)
- ? formatDate(end, this.hass.locale)
- : formatDateTime(end, this.hass.locale)
+ ? formatDate(end, this.hass.locale, this.hass.config)
+ : formatDateTime(end, this.hass.locale, this.hass.config)
}`;
}
diff --git a/src/panels/calendar/recurrence.ts b/src/panels/calendar/recurrence.ts
index ddc1d45729..1a502c9678 100644
--- a/src/panels/calendar/recurrence.ts
+++ b/src/panels/calendar/recurrence.ts
@@ -247,8 +247,8 @@ export function renderRRuleAsText(hass: HomeAssistant, value: string) {
return "";
},
{
- dayNames: dayNames(hass.locale),
- monthNames: monthNames(hass.locale),
+ dayNames: dayNames(hass.locale, hass.config),
+ monthNames: monthNames(hass.locale, hass.config),
tokens: {},
},
// Format the date
@@ -263,9 +263,9 @@ export function renderRRuleAsText(hass: HomeAssistant, value: string) {
// need to convert it back to something Date can work with. The already localized
// months names are a must in the RRule.Language structure (an empty string[] would
// mean we get undefined months input in this method here).
- date.setMonth(monthNames(hass.locale).indexOf(month));
+ date.setMonth(monthNames(hass.locale, hass.config).indexOf(month));
date.setDate(day);
- return formatDate(date, hass.locale);
+ return formatDate(date, hass.locale, hass.config);
}
)
);
diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts
index cb89fd8af5..cdf33e2b50 100644
--- a/src/panels/config/automation/ha-automation-picker.ts
+++ b/src/panels/config/automation/ha-automation-picker.ts
@@ -128,7 +128,11 @@ class HaAutomationPicker extends LitElement {
${this.hass.localize("ui.card.automation.last_triggered")}:
${automation.attributes.last_triggered
? dayDifference > 3
- ? formatShortDateTime(date, this.hass.locale)
+ ? formatShortDateTime(
+ date,
+ this.hass.locale,
+ this.hass.config
+ )
: relativeTime(date, this.hass.locale)
: this.hass.localize("ui.components.relative_time.never")}
@@ -149,7 +153,11 @@ class HaAutomationPicker extends LitElement {
return html`
${last_triggered
? dayDifference > 3
- ? formatShortDateTime(date, this.hass.locale)
+ ? formatShortDateTime(
+ date,
+ this.hass.locale,
+ this.hass.config
+ )
: relativeTime(date, this.hass.locale)
: this.hass.localize("ui.components.relative_time.never")}
`;
diff --git a/src/panels/config/automation/ha-automation-trace.ts b/src/panels/config/automation/ha-automation-trace.ts
index bfebbadb0b..fbf52c6974 100644
--- a/src/panels/config/automation/ha-automation-trace.ts
+++ b/src/panels/config/automation/ha-automation-trace.ts
@@ -192,7 +192,8 @@ export class HaAutomationTrace extends LitElement {
html``
)}
diff --git a/src/panels/config/cloud/account/cloud-account.ts b/src/panels/config/cloud/account/cloud-account.ts
index 2be0ccffbd..2f0f3e791d 100644
--- a/src/panels/config/cloud/account/cloud-account.ts
+++ b/src/panels/config/cloud/account/cloud-account.ts
@@ -79,7 +79,8 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
new Date(
this._subscription.plan_renewal_date * 1000
),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)
: ""
)
diff --git a/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts b/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts
index d999a162af..0e170e539b 100644
--- a/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts
+++ b/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts
@@ -49,7 +49,8 @@ class DialogCloudCertificate extends LitElement {
)}
${formatDateTime(
new Date(certificateInfo.expire_date),
- this.hass!.locale
+ this.hass!.locale,
+ this.hass!.config
)}
(${this.hass!.localize(
"ui.panel.config.cloud.dialog_certificate.will_be_auto_renewed"
diff --git a/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts b/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts
index 90bfb086c0..2d3b5acd1f 100644
--- a/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts
+++ b/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts
@@ -55,7 +55,8 @@ class MQTTMessages extends LitElement {
${this.direction}
${formatTimeWithSeconds(
new Date(message.time),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
${this._renderSingleMessage(message)}
diff --git a/src/panels/config/hardware/ha-config-hardware.ts b/src/panels/config/hardware/ha-config-hardware.ts
index ee910d622e..a6498ab9bb 100644
--- a/src/panels/config/hardware/ha-config-hardware.ts
+++ b/src/panels/config/hardware/ha-config-hardware.ts
@@ -170,6 +170,7 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
adapters: {
date: {
locale: this.hass.locale,
+ config: this.hass.config,
},
},
gridLines: {
diff --git a/src/panels/config/helpers/forms/ha-schedule-form.ts b/src/panels/config/helpers/forms/ha-schedule-form.ts
index 1568452504..e3116d5b21 100644
--- a/src/panels/config/helpers/forms/ha-schedule-form.ts
+++ b/src/panels/config/helpers/forms/ha-schedule-form.ts
@@ -286,9 +286,9 @@ class HaScheduleForm extends LitElement {
const value = [...this[`_${day}`]];
const newValue = { ...this._item };
- const endFormatted = formatTime24h(end);
+ const endFormatted = formatTime24h(end, this.hass.locale, this.hass.config);
value.push({
- from: formatTime24h(start),
+ from: formatTime24h(start, this.hass.locale, this.hass.config),
to:
!isSameDay(start, end) || endFormatted === "0:00"
? "24:00"
@@ -313,7 +313,7 @@ class HaScheduleForm extends LitElement {
const value = this[`_${day}`][parseInt(index)];
const newValue = { ...this._item };
- const endFormatted = formatTime24h(end);
+ const endFormatted = formatTime24h(end, this.hass.locale, this.hass.config);
newValue[day][index] = {
from: value.from,
to:
@@ -338,9 +338,9 @@ class HaScheduleForm extends LitElement {
const newDay = weekdays[start.getDay()];
const newValue = { ...this._item };
- const endFormatted = formatTime24h(end);
+ const endFormatted = formatTime24h(end, this.hass.locale, this.hass.config);
const event = {
- from: formatTime24h(start),
+ from: formatTime24h(start, this.hass.locale, this.hass.config),
to:
!isSameDay(start, end) || endFormatted === "0:00"
? "24:00"
diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts
index 1798614a68..02935336c0 100644
--- a/src/panels/config/integrations/dialog-add-integration.ts
+++ b/src/panels/config/integrations/dialog-add-integration.ts
@@ -1,6 +1,7 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list";
import Fuse from "fuse.js";
+import { HassConfig } from "home-assistant-js-websocket";
import {
css,
html,
@@ -158,7 +159,7 @@ class AddIntegrationDialog extends LitElement {
(
i: Brands,
h: Integrations,
- components: HomeAssistant["config"]["components"],
+ components: HassConfig["components"],
localize: LocalizeFunc,
filter?: string
): IntegrationListItem[] => {
diff --git a/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts b/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts
index ebc0e1a123..bb04eb4f78 100644
--- a/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts
+++ b/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts
@@ -105,7 +105,7 @@ class MqttSubscribeCard extends LitElement {
"topic",
msg.message.topic,
"time",
- formatTime(msg.time, this.hass!.locale)
+ formatTime(msg.time, this.hass!.locale, this.hass!.config)
)}
${msg.payload}
diff --git a/src/panels/config/logs/dialog-system-log-detail.ts b/src/panels/config/logs/dialog-system-log-detail.ts
index 49891035ef..4856efdb98 100644
--- a/src/panels/config/logs/dialog-system-log-detail.ts
+++ b/src/panels/config/logs/dialog-system-log-detail.ts
@@ -145,12 +145,20 @@ class DialogSystemLogDetail extends LitElement {
${item.count > 0
? html`
First occurred:
- ${formatSystemLogTime(item.first_occurred, this.hass!.locale)}
+ ${formatSystemLogTime(
+ item.first_occurred,
+ this.hass!.locale,
+ this.hass!.config
+ )}
(${item.count} occurrences)
`
: ""}
Last logged:
- ${formatSystemLogTime(item.timestamp, this.hass!.locale)}
+ ${formatSystemLogTime(
+ item.timestamp,
+ this.hass!.locale,
+ this.hass!.config
+ )}
${item.message.length > 1
? html`
diff --git a/src/panels/config/logs/system-log-card.ts b/src/panels/config/logs/system-log-card.ts
index beec07abaf..e05da8a75d 100644
--- a/src/panels/config/logs/system-log-card.ts
+++ b/src/panels/config/logs/system-log-card.ts
@@ -38,14 +38,22 @@ export class SystemLogCard extends LitElement {
}
private _timestamp(item: LoggedError): string {
- return formatSystemLogTime(item.timestamp, this.hass!.locale);
+ return formatSystemLogTime(
+ item.timestamp,
+ this.hass.locale,
+ this.hass.config
+ );
}
private _multipleMessages(item: LoggedError): string {
return this.hass.localize(
"ui.panel.config.logs.multiple_messages",
"time",
- formatSystemLogTime(item.first_occurred, this.hass!.locale),
+ formatSystemLogTime(
+ item.first_occurred,
+ this.hass.locale,
+ this.hass.config
+ ),
"counter",
item.count
);
diff --git a/src/panels/config/logs/util.ts b/src/panels/config/logs/util.ts
index 3eb92fcd96..4cf0d7f704 100644
--- a/src/panels/config/logs/util.ts
+++ b/src/panels/config/logs/util.ts
@@ -1,13 +1,18 @@
+import { HassConfig } from "home-assistant-js-websocket";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import { formatTimeWithSeconds } from "../../../common/datetime/format_time";
import { FrontendLocaleData } from "../../../data/translation";
-export const formatSystemLogTime = (date, locale: FrontendLocaleData) => {
+export const formatSystemLogTime = (
+ date,
+ locale: FrontendLocaleData,
+ config: HassConfig
+) => {
const today = new Date().setHours(0, 0, 0, 0);
const dateTime = new Date(date * 1000);
const dateTimeDay = new Date(date * 1000).setHours(0, 0, 0, 0);
return dateTimeDay < today
- ? formatDateTimeWithSeconds(dateTime, locale)
- : formatTimeWithSeconds(dateTime, locale);
+ ? formatDateTimeWithSeconds(dateTime, locale, config)
+ : formatTimeWithSeconds(dateTime, locale, config);
};
diff --git a/src/panels/config/repairs/dialog-repairs-issue.ts b/src/panels/config/repairs/dialog-repairs-issue.ts
index 3aae980d29..4e628ccbd0 100644
--- a/src/panels/config/repairs/dialog-repairs-issue.ts
+++ b/src/panels/config/repairs/dialog-repairs-issue.ts
@@ -100,7 +100,8 @@ class DialogRepairsIssue extends LitElement {
${this._issue.created
? formatDateNumeric(
new Date(this._issue.created),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)
: ""}
diff --git a/src/panels/config/repairs/dialog-system-information.ts b/src/panels/config/repairs/dialog-system-information.ts
index ce2bfefd5a..bc3b1e0181 100644
--- a/src/panels/config/repairs/dialog-system-information.ts
+++ b/src/panels/config/repairs/dialog-system-information.ts
@@ -349,7 +349,11 @@ class DialogSystemInformation extends LitElement {
`}
`;
} else if (info.type === "date") {
- value = formatDateTime(new Date(info.value), this.hass.locale);
+ value = formatDateTime(
+ new Date(info.value),
+ this.hass.locale,
+ this.hass.config
+ );
}
} else {
value = domainInfo.info[key];
@@ -425,7 +429,11 @@ class DialogSystemInformation extends LitElement {
} else if (info.type === "failed") {
value = `failed to load: ${info.error}`;
} else if (info.type === "date") {
- value = formatDateTime(new Date(info.value), this.hass.locale);
+ value = formatDateTime(
+ new Date(info.value),
+ this.hass.locale,
+ this.hass.config
+ );
}
} else {
value = domainInfo.info[key];
diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts
index 11762b419b..df9f6be040 100644
--- a/src/panels/config/scene/ha-scene-dashboard.ts
+++ b/src/panels/config/scene/ha-scene-dashboard.ts
@@ -118,7 +118,11 @@ class HaSceneDashboard extends LitElement {
return html`
${last_activated && !isUnavailableState(last_activated)
? dayDifference > 3
- ? formatShortDateTime(date, this.hass.locale)
+ ? formatShortDateTime(
+ date,
+ this.hass.locale,
+ this.hass.config
+ )
: relativeTime(date, this.hass.locale)
: this.hass.localize("ui.components.relative_time.never")}
`;
diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts
index f5d80a60be..61ac52dc3f 100644
--- a/src/panels/config/script/ha-script-picker.ts
+++ b/src/panels/config/script/ha-script-picker.ts
@@ -118,7 +118,11 @@ class HaScriptPicker extends LitElement {
${this.hass.localize("ui.card.automation.last_triggered")}:
${script.attributes.last_triggered
? dayDifference > 3
- ? formatShortDateTime(date, this.hass.locale)
+ ? formatShortDateTime(
+ date,
+ this.hass.locale,
+ this.hass.config
+ )
: relativeTime(date, this.hass.locale)
: this.hass.localize("ui.components.relative_time.never")}
@@ -139,7 +143,7 @@ class HaScriptPicker extends LitElement {
return html`
${last_triggered
? dayDifference > 3
- ? formatShortDateTime(date, this.hass.locale)
+ ? formatShortDateTime(date, this.hass.locale, this.hass.config)
: relativeTime(date, this.hass.locale)
: this.hass.localize("ui.components.relative_time.never")}
`;
diff --git a/src/panels/config/script/ha-script-trace.ts b/src/panels/config/script/ha-script-trace.ts
index 54bb1542d2..dd410b745a 100644
--- a/src/panels/config/script/ha-script-trace.ts
+++ b/src/panels/config/script/ha-script-trace.ts
@@ -191,7 +191,8 @@ export class HaScriptTrace extends LitElement {
html``
)}
diff --git a/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts b/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts
index 638fad5c3c..e75f3a230f 100644
--- a/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts
+++ b/src/panels/config/voice-assistants/debug/assist-pipeline-debug.ts
@@ -64,7 +64,8 @@ export class AssistPipelineDebug extends LitElement {
html``
)}
diff --git a/src/panels/developer-tools/event/event-subscribe-card.ts b/src/panels/developer-tools/event/event-subscribe-card.ts
index 0b0ce881b6..d1d7afc0aa 100644
--- a/src/panels/developer-tools/event/event-subscribe-card.ts
+++ b/src/panels/developer-tools/event/event-subscribe-card.ts
@@ -80,7 +80,8 @@ class EventSubscribeCard extends LitElement {
)}
${formatTime(
new Date(event.event.time_fired),
- this.hass!.locale
+ this.hass!.locale,
+ this.hass!.config
)}:
${growth} ${unit}
- ${formatDateTime(new Date(stat.start), this.hass.locale)}
+ ${formatDateTime(
+ new Date(stat.start),
+ this.hass.locale,
+ this.hass.config
+ )}
@@ -213,7 +217,8 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
${formatDateTime(
new Date(this._chosenStat!.start),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
@@ -223,7 +228,8 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
${formatDateTime(
new Date(this._chosenStat!.end),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts
index 08b8f0d90c..b88861d44c 100644
--- a/src/panels/history/ha-panel-history.ts
+++ b/src/panels/history/ha-panel-history.ts
@@ -1,14 +1,5 @@
import { mdiFilterRemove, mdiRefresh } from "@mdi/js";
-import {
- addDays,
- differenceInHours,
- endOfToday,
- endOfWeek,
- endOfYesterday,
- startOfToday,
- startOfWeek,
- startOfYesterday,
-} from "date-fns/esm";
+import { differenceInHours } from "date-fns/esm";
import {
HassServiceTarget,
UnsubscribeFunc,
@@ -16,7 +7,6 @@ import {
import { css, html, LitElement, PropertyValues } from "lit";
import { property, query, state } from "lit/decorators";
import { ensureArray } from "../../common/array/ensure-array";
-import { firstWeekdayIndex } from "../../common/datetime/first_weekday";
import { LocalStorage } from "../../common/decorators/local-storage";
import { navigate } from "../../common/navigate";
import { constructUrlCurrentPath } from "../../common/url/construct-url";
@@ -31,10 +21,11 @@ import "../../components/chart/state-history-charts";
import type { StateHistoryCharts } from "../../components/chart/state-history-charts";
import "../../components/ha-circular-progress";
import "../../components/ha-date-range-picker";
-import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
import "../../components/ha-icon-button";
+import "../../components/ha-icon-button-arrow-prev";
import "../../components/ha-menu-button";
import "../../components/ha-target-picker";
+import "../../components/ha-top-app-bar-fixed";
import {
AreaDeviceLookup,
AreaEntityLookup,
@@ -55,8 +46,6 @@ import {
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types";
-import "../../components/ha-top-app-bar-fixed";
-import "../../components/ha-icon-button-arrow-prev";
class HaPanelHistory extends SubscribeMixin(LitElement) {
@property({ attribute: false }) hass!: HomeAssistant;
@@ -76,8 +65,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
@state() private _stateHistory?: HistoryResult;
- @state() private _ranges?: DateRangePickerRanges;
-
@state() private _deviceEntityLookup?: DeviceEntityLookup;
@state() private _areaEntityLookup?: AreaEntityLookup;
@@ -178,7 +165,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
?disabled=${this._isLoading}
.startDate=${this._startDate}
.endDate=${this._endDate}
- .ranges=${this._ranges}
@change=${this._dateRangeChanged}
>
- ${formatDate(new Date(item.when * 1000), this.hass.locale)}
+ ${formatDate(
+ new Date(item.when * 1000),
+ this.hass.locale,
+ this.hass.config
+ )}
`
: nothing}
@@ -229,7 +233,8 @@ class HaLogbookRenderer extends LitElement {
${formatTimeWithSeconds(
new Date(item.when * 1000),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}
-
diff --git a/src/panels/logbook/ha-panel-logbook.ts b/src/panels/logbook/ha-panel-logbook.ts
index aba47b77d4..9a93813793 100644
--- a/src/panels/logbook/ha-panel-logbook.ts
+++ b/src/panels/logbook/ha-panel-logbook.ts
@@ -1,16 +1,6 @@
import { mdiRefresh } from "@mdi/js";
-import {
- addDays,
- endOfToday,
- endOfWeek,
- endOfYesterday,
- startOfToday,
- startOfWeek,
- startOfYesterday,
-} from "date-fns/esm";
import { css, html, LitElement, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
-import { firstWeekdayIndex } from "../../common/datetime/first_weekday";
import { navigate } from "../../common/navigate";
import { constructUrlCurrentPath } from "../../common/url/construct-url";
import {
@@ -20,7 +10,6 @@ import {
} from "../../common/url/search-params";
import "../../components/entity/ha-entity-picker";
import "../../components/ha-date-range-picker";
-import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
import "../../components/ha-icon-button";
import "../../components/ha-icon-button-arrow-prev";
import "../../components/ha-menu-button";
@@ -40,8 +29,6 @@ export class HaPanelLogbook extends LitElement {
@state() _entityIds?: string[];
- @state() private _ranges?: DateRangePickerRanges;
-
@state()
private _showBack?: boolean;
@@ -91,7 +78,6 @@ export class HaPanelLogbook extends LitElement {
.hass=${this.hass}
.startDate=${this._time.range[0]}
.endDate=${this._time.range[1]}
- .ranges=${this._ranges}
@change=${this._dateRangeChanged}
>
@@ -123,24 +109,6 @@ export class HaPanelLogbook extends LitElement {
return;
}
- const today = new Date();
- const weekStartsOn = firstWeekdayIndex(this.hass.locale);
- const weekStart = startOfWeek(today, { weekStartsOn });
- const weekEnd = endOfWeek(today, { weekStartsOn });
-
- this._ranges = {
- [this.hass.localize("ui.components.date-range-picker.ranges.today")]: [
- startOfToday(),
- endOfToday(),
- ],
- [this.hass.localize("ui.components.date-range-picker.ranges.yesterday")]:
- [startOfYesterday(), endOfYesterday()],
- [this.hass.localize("ui.components.date-range-picker.ranges.this_week")]:
- [weekStart, weekEnd],
- [this.hass.localize("ui.components.date-range-picker.ranges.last_week")]:
- [addDays(weekStart, -7), addDays(weekEnd, -7)],
- };
-
this._applyURLParams();
}
diff --git a/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts b/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts
index 552680e2e9..4c545668fe 100644
--- a/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts
+++ b/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts
@@ -60,18 +60,27 @@ export class HuiEnergyCompareCard
${this.hass.localize("ui.panel.energy.compare.info", {
start: html`${formatDate(this._start!, this.hass.locale)}${dayDifference > 0
+ >${formatDate(
+ this._start!,
+ this.hass.locale,
+ this.hass.config
+ )}${dayDifference > 0
? ` -
- ${formatDate(this._end || endOfDay(new Date()), this.hass.locale)}`
+ ${formatDate(
+ this._end || endOfDay(new Date()),
+ this.hass.locale,
+ this.hass.config
+ )}`
: ""}`,
end: html`${formatDate(
this._startCompare,
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}${dayDifference > 0
? ` -
- ${formatDate(this._endCompare, this.hass.locale)}`
+ ${formatDate(this._endCompare, this.hass.locale, this.hass.config)}`
: ""}`,
})}
diff --git a/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts
index 8fa32d49b1..432dada500 100644
--- a/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts
+++ b/src/panels/lovelace/cards/energy/hui-energy-gas-graph-card.ts
@@ -12,7 +12,7 @@ import {
isToday,
startOfToday,
} from "date-fns";
-import { UnsubscribeFunc } from "home-assistant-js-websocket";
+import { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -112,6 +112,7 @@ export class HuiEnergyGasGraphCard
this._start,
this._end,
this.hass.locale,
+ this.hass.config,
this._unit,
this._compareStart,
this._compareEnd
@@ -137,6 +138,7 @@ export class HuiEnergyGasGraphCard
start: Date,
end: Date,
locale: FrontendLocaleData,
+ config: HassConfig,
unit?: string,
compareStart?: Date,
compareEnd?: Date
@@ -167,7 +169,8 @@ export class HuiEnergyGasGraphCard
suggestedMax: end.getTime(),
adapters: {
date: {
- locale: locale,
+ locale,
+ config,
},
},
ticks: {
@@ -221,10 +224,11 @@ export class HuiEnergyGasGraphCard
}
const date = new Date(datasets[0].parsed.x);
return `${
- compare ? `${formatDateShort(date, locale)}: ` : ""
- }${formatTime(date, locale)} – ${formatTime(
+ compare ? `${formatDateShort(date, locale, config)}: ` : ""
+ }${formatTime(date, locale, config)} – ${formatTime(
addHours(date, 1),
- locale
+ locale,
+ config
)}`;
},
label: (context) =>
diff --git a/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts
index 6c693b4b46..49290b5647 100644
--- a/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts
+++ b/src/panels/lovelace/cards/energy/hui-energy-solar-graph-card.ts
@@ -12,7 +12,7 @@ import {
isToday,
startOfToday,
} from "date-fns/esm";
-import { UnsubscribeFunc } from "home-assistant-js-websocket";
+import { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -111,6 +111,7 @@ export class HuiEnergySolarGraphCard
this._start,
this._end,
this.hass.locale,
+ this.hass.config,
this._compareStart,
this._compareEnd
)}
@@ -135,6 +136,7 @@ export class HuiEnergySolarGraphCard
start: Date,
end: Date,
locale: FrontendLocaleData,
+ config: HassConfig,
compareStart?: Date,
compareEnd?: Date
): ChartOptions => {
@@ -164,7 +166,8 @@ export class HuiEnergySolarGraphCard
suggestedMax: end.getTime(),
adapters: {
date: {
- locale: locale,
+ locale,
+ config,
},
},
ticks: {
@@ -217,10 +220,11 @@ export class HuiEnergySolarGraphCard
}
const date = new Date(datasets[0].parsed.x);
return `${
- compare ? `${formatDateShort(date, locale)}: ` : ""
- }${formatTime(date, locale)} – ${formatTime(
+ compare ? `${formatDateShort(date, locale, config)}: ` : ""
+ }${formatTime(date, locale, config)} – ${formatTime(
addHours(date, 1),
- locale
+ locale,
+ config
)}`;
},
label: (context) =>
diff --git a/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts
index 693f5deb83..5b97bd290d 100644
--- a/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts
+++ b/src/panels/lovelace/cards/energy/hui-energy-usage-graph-card.ts
@@ -12,7 +12,7 @@ import {
isToday,
startOfToday,
} from "date-fns/esm";
-import { UnsubscribeFunc } from "home-assistant-js-websocket";
+import { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -105,6 +105,7 @@ export class HuiEnergyUsageGraphCard
this._start,
this._end,
this.hass.locale,
+ this.hass.config,
this._compareStart,
this._compareEnd
)}
@@ -129,6 +130,7 @@ export class HuiEnergyUsageGraphCard
start: Date,
end: Date,
locale: FrontendLocaleData,
+ config: HassConfig,
compareStart?: Date,
compareEnd?: Date
): ChartOptions => {
@@ -158,7 +160,8 @@ export class HuiEnergyUsageGraphCard
suggestedMax: end.getTime(),
adapters: {
date: {
- locale: locale,
+ locale,
+ config,
},
},
ticks: {
@@ -213,10 +216,11 @@ export class HuiEnergyUsageGraphCard
}
const date = new Date(datasets[0].parsed.x);
return `${
- compare ? `${formatDateShort(date, locale)}: ` : ""
- }${formatTime(date, locale)} – ${formatTime(
+ compare ? `${formatDateShort(date, locale, config)}: ` : ""
+ }${formatTime(date, locale, config)} – ${formatTime(
addHours(date, 1),
- locale
+ locale,
+ config
)}`;
},
label: (context) =>
diff --git a/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts b/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts
index 709921d45c..84f21089c2 100644
--- a/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts
+++ b/src/panels/lovelace/cards/energy/hui-energy-water-graph-card.ts
@@ -12,7 +12,7 @@ import {
isToday,
startOfToday,
} from "date-fns";
-import { UnsubscribeFunc } from "home-assistant-js-websocket";
+import { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
@@ -112,6 +112,7 @@ export class HuiEnergyWaterGraphCard
this._start,
this._end,
this.hass.locale,
+ this.hass.config,
this._unit,
this._compareStart,
this._compareEnd
@@ -137,6 +138,7 @@ export class HuiEnergyWaterGraphCard
start: Date,
end: Date,
locale: FrontendLocaleData,
+ config: HassConfig,
unit?: string,
compareStart?: Date,
compareEnd?: Date
@@ -167,7 +169,8 @@ export class HuiEnergyWaterGraphCard
suggestedMax: end.getTime(),
adapters: {
date: {
- locale: locale,
+ locale,
+ config,
},
},
ticks: {
@@ -221,10 +224,11 @@ export class HuiEnergyWaterGraphCard
}
const date = new Date(datasets[0].parsed.x);
return `${
- compare ? `${formatDateShort(date, locale)}: ` : ""
- }${formatTime(date, locale)} – ${formatTime(
+ compare ? `${formatDateShort(date, locale, config)}: ` : ""
+ }${formatTime(date, locale, config)} – ${formatTime(
addHours(date, 1),
- locale
+ locale,
+ config
)}`;
},
label: (context) =>
diff --git a/src/panels/lovelace/cards/hui-button-card.ts b/src/panels/lovelace/cards/hui-button-card.ts
index 6f00fc3dfa..1e9167e5a4 100644
--- a/src/panels/lovelace/cards/hui-button-card.ts
+++ b/src/panels/lovelace/cards/hui-button-card.ts
@@ -2,7 +2,11 @@ import { consume } from "@lit-labs/context";
import "@material/mwc-ripple";
import type { Ripple } from "@material/mwc-ripple";
import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers";
-import { HassEntities, HassEntity } from "home-assistant-js-websocket";
+import {
+ HassConfig,
+ HassEntities,
+ HassEntity,
+} from "home-assistant-js-websocket";
import {
CSSResultGroup,
LitElement,
@@ -27,6 +31,7 @@ import { iconColorCSS } from "../../../common/style/icon_color_css";
import "../../../components/ha-card";
import { HVAC_ACTION_TO_MODE } from "../../../data/climate";
import {
+ configContext,
entitiesContext,
localeContext,
localizeContext,
@@ -103,6 +108,10 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
@consume({ context: localeContext, subscribe: true })
_locale!: FrontendLocaleData;
+ @state()
+ @consume({ context: configContext, subscribe: true })
+ _hassConfig!: HassConfig;
+
@consume({ context: entitiesContext, subscribe: true })
@transform({
transformer: function (this: HuiButtonCard, value) {
@@ -223,6 +232,7 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
this._localize,
stateObj,
this._locale,
+ this._hassConfig,
this._entity
)}
`
diff --git a/src/panels/lovelace/cards/hui-entity-card.ts b/src/panels/lovelace/cards/hui-entity-card.ts
index 4d948cd0d7..548dbd80ec 100644
--- a/src/panels/lovelace/cards/hui-entity-card.ts
+++ b/src/panels/lovelace/cards/hui-entity-card.ts
@@ -163,6 +163,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
this._config.attribute!
)
@@ -180,6 +181,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}${showUnit
diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts
index f22ac84267..1e42db66c7 100644
--- a/src/panels/lovelace/cards/hui-glance-card.ts
+++ b/src/panels/lovelace/cards/hui-glance-card.ts
@@ -337,6 +337,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities
)}
diff --git a/src/panels/lovelace/cards/hui-humidifier-card.ts b/src/panels/lovelace/cards/hui-humidifier-card.ts
index a99331e67e..9e24121a29 100644
--- a/src/panels/lovelace/cards/hui-humidifier-card.ts
+++ b/src/panels/lovelace/cards/hui-humidifier-card.ts
@@ -140,6 +140,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"mode"
)}
diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts
index e41aef6afe..9c2041c7ba 100644
--- a/src/panels/lovelace/cards/hui-light-card.ts
+++ b/src/panels/lovelace/cards/hui-light-card.ts
@@ -161,6 +161,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
diff --git a/src/panels/lovelace/cards/hui-map-card.ts b/src/panels/lovelace/cards/hui-map-card.ts
index d84694d048..ec9dfa6138 100644
--- a/src/panels/lovelace/cards/hui-map-card.ts
+++ b/src/panels/lovelace/cards/hui-map-card.ts
@@ -374,11 +374,19 @@ class HuiMapCard extends LitElement implements LovelaceCard {
if ((config.hours_to_show! ?? DEFAULT_HOURS_TO_SHOW) > 144) {
// if showing > 6 days in the history trail, show the full
// date and time
- p.tooltip = formatDateTime(t, this.hass.locale);
+ p.tooltip = formatDateTime(t, this.hass.locale, this.hass.config);
} else if (isToday(t)) {
- p.tooltip = formatTimeWithSeconds(t, this.hass.locale);
+ p.tooltip = formatTimeWithSeconds(
+ t,
+ this.hass.locale,
+ this.hass.config
+ );
} else {
- p.tooltip = formatTimeWeekday(t, this.hass.locale);
+ p.tooltip = formatTimeWeekday(
+ t,
+ this.hass.locale,
+ this.hass.config
+ );
}
points.push(p);
}
diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts
index 665aad7f32..1d6c51fcd7 100644
--- a/src/panels/lovelace/cards/hui-picture-entity-card.ts
+++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts
@@ -123,6 +123,7 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
);
diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts
index 298a745026..b307d0f1d0 100644
--- a/src/panels/lovelace/cards/hui-picture-glance-card.ts
+++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts
@@ -257,6 +257,7 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities
)}`}
>
@@ -280,6 +281,7 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities
)}
diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts
index b186cf8e59..0438374c7a 100644
--- a/src/panels/lovelace/cards/hui-thermostat-card.ts
+++ b/src/panels/lovelace/cards/hui-thermostat-card.ts
@@ -235,6 +235,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"hvac_action"
)
@@ -242,6 +243,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)
}
@@ -254,6 +256,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"preset_mode"
)}
diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts
index 5f2b43b83a..0afb105c2f 100644
--- a/src/panels/lovelace/cards/hui-tile-card.ts
+++ b/src/panels/lovelace/cards/hui-tile-card.ts
@@ -228,6 +228,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities
);
diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts
index 066d14fa02..85f29fc0a4 100644
--- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts
+++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts
@@ -39,6 +39,7 @@ import { loadPolyfillIfNeeded } from "../../../resources/resize-observer.polyfil
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard, LovelaceCardEditor } from "../types";
import type { WeatherForecastCardConfig } from "./types";
+import { formatDateWeekdayShort } from "../../../common/datetime/format_date";
const DAY_IN_MILLISECONDS = 86400000;
@@ -222,6 +223,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
@@ -319,13 +321,15 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
? html`
${formatTime(
new Date(item.datetime),
- this.hass!.locale
+ this.hass!.locale,
+ this.hass!.config
)}
`
: html`
- ${new Date(item.datetime).toLocaleDateString(
- this.hass!.language,
- { weekday: "short" }
+ ${formatDateWeekdayShort(
+ new Date(item.datetime),
+ this.hass!.locale,
+ this.hass!.config
)}
`}
diff --git a/src/panels/lovelace/components/hui-energy-period-selector.ts b/src/panels/lovelace/components/hui-energy-period-selector.ts
index c4054e7e7c..9cd6666cd3 100644
--- a/src/panels/lovelace/components/hui-energy-period-selector.ts
+++ b/src/panels/lovelace/components/hui-energy-period-selector.ts
@@ -21,6 +21,7 @@ import {
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
+import { calcDate } from "../../../common/datetime/calc_date";
import { firstWeekdayIndex } from "../../../common/datetime/first_weekday";
import {
formatDate,
@@ -105,17 +106,27 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
${this._period === "day"
- ? formatDate(this._startDate, this.hass.locale)
+ ? formatDate(this._startDate, this.hass.locale, this.hass.config)
: this._period === "month"
- ? formatDateMonthYear(this._startDate, this.hass.locale)
+ ? formatDateMonthYear(
+ this._startDate,
+ this.hass.locale,
+ this.hass.config
+ )
: this._period === "year"
- ? formatDateYear(this._startDate, this.hass.locale)
+ ? formatDateYear(
+ this._startDate,
+ this.hass.locale,
+ this.hass.config
+ )
: `${formatDateShort(
this._startDate,
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)} – ${formatDateShort(
this._endDate || new Date(),
- this.hass.locale
+ this.hass.locale,
+ this.hass.config
)}`}
string;
+ [key: string]: (
+ ts: Date,
+ lang: FrontendLocaleData,
+ config: HassConfig
+ ) => string;
} = {
date: formatDate,
datetime: formatDateTime,
@@ -63,7 +68,9 @@ class HuiTimestampDisplay extends LitElement {
return html` ${this._relative} `;
}
if (format in FORMATS) {
- return html` ${FORMATS[format](this.ts, this.hass.locale)} `;
+ return html`
+ ${FORMATS[format](this.ts, this.hass.locale, this.hass.config)}
+ `;
}
return html`${this.hass.localize(
"ui.panel.lovelace.components.timestamp-display.invalid_format"
diff --git a/src/panels/lovelace/elements/hui-state-label-element.ts b/src/panels/lovelace/elements/hui-state-label-element.ts
index 4d52fb81f4..d7f3ce9872 100644
--- a/src/panels/lovelace/elements/hui-state-label-element.ts
+++ b/src/panels/lovelace/elements/hui-state-label-element.ts
@@ -87,6 +87,7 @@ class HuiStateLabelElement extends LitElement implements LovelaceElement {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)
: stateObj.attributes[this._config.attribute]}${this._config.suffix}
diff --git a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts
index 9dad7f8e6d..146943251e 100644
--- a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts
@@ -70,6 +70,7 @@ class HuiGroupEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
diff --git a/src/panels/lovelace/entity-rows/hui-humidifier-entity-row.ts b/src/panels/lovelace/entity-rows/hui-humidifier-entity-row.ts
index f2666cfe99..4aa7738253 100644
--- a/src/panels/lovelace/entity-rows/hui-humidifier-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-humidifier-entity-row.ts
@@ -54,6 +54,7 @@ class HuiHumidifierEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
"mode"
)})`
diff --git a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts
index ab81ff7eb1..6488d33843 100644
--- a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.ts
@@ -100,6 +100,7 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
stateObj.state
)}
diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
index 2dc020a493..f2f481ad46 100644
--- a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts
@@ -193,6 +193,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
>
diff --git a/src/panels/lovelace/entity-rows/hui-number-entity-row.ts b/src/panels/lovelace/entity-rows/hui-number-entity-row.ts
index 0046379e3f..bd55652798 100644
--- a/src/panels/lovelace/entity-rows/hui-number-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-number-entity-row.ts
@@ -104,6 +104,7 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
stateObj.state
)}
diff --git a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts
index c263519425..2d7d3c51e1 100644
--- a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts
@@ -82,6 +82,7 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities,
option
)}
diff --git a/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts b/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
index ce291b44cc..0d536ca9f9 100644
--- a/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts
@@ -83,6 +83,7 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
diff --git a/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts b/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts
index 98e1b44a43..23b4cb8720 100644
--- a/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-simple-entity-row.ts
@@ -53,6 +53,7 @@ class HuiSimpleEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)}
diff --git a/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts b/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts
index 7ea096e9ad..611fd2bdd5 100644
--- a/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts
@@ -65,6 +65,7 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass!.locale,
+ this.hass.config,
this.hass!.entities
)}
diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
index 088869be37..f8badf7b10 100644
--- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
+++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts
@@ -148,6 +148,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities
)
: html`
diff --git a/src/panels/lovelace/special-rows/hui-attribute-row.ts b/src/panels/lovelace/special-rows/hui-attribute-row.ts
index b0e95de02f..b8db4ebf56 100644
--- a/src/panels/lovelace/special-rows/hui-attribute-row.ts
+++ b/src/panels/lovelace/special-rows/hui-attribute-row.ts
@@ -75,6 +75,7 @@ class HuiAttributeRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
this._config.attribute,
attribute
diff --git a/src/panels/lovelace/tile-features/hui-fan-speed-tile-feature.ts b/src/panels/lovelace/tile-features/hui-fan-speed-tile-feature.ts
index fb0f23bf29..da69431ad0 100644
--- a/src/panels/lovelace/tile-features/hui-fan-speed-tile-feature.ts
+++ b/src/panels/lovelace/tile-features/hui-fan-speed-tile-feature.ts
@@ -59,6 +59,7 @@ class HuiFanSpeedTileFeature extends LitElement implements LovelaceTileFeature {
this.hass!.localize,
this.stateObj!,
this.hass!.locale,
+ this.hass!.config,
this.hass!.entities,
speed
);
diff --git a/src/panels/profile/ha-panel-profile.ts b/src/panels/profile/ha-panel-profile.ts
index 628c44ef38..47bccf93ea 100644
--- a/src/panels/profile/ha-panel-profile.ts
+++ b/src/panels/profile/ha-panel-profile.ts
@@ -28,6 +28,7 @@ import "./ha-pick-number-format-row";
import "./ha-pick-theme-row";
import "./ha-pick-time-format-row";
import "./ha-pick-date-format-row";
+import "./ha-pick-time-zone-row";
import "./ha-push-notifications-row";
import "./ha-refresh-tokens-card";
import "./ha-set-suspend-row";
@@ -101,6 +102,10 @@ class HaPanelProfile extends LitElement {
.narrow=${this.narrow}
.hass=${this.hass}
>
+
${Object.values(DateFormat).map((format) => {
- const formattedDate = formatDateNumeric(date, {
- ...this.hass.locale,
- date_format: format,
- });
+ const formattedDate = formatDateNumeric(
+ date,
+ {
+ ...this.hass.locale,
+ date_format: format,
+ },
+ this.hass.config
+ );
const value = this.hass.localize(
`ui.panel.profile.date_format.formats.${format}`
);
diff --git a/src/panels/profile/ha-pick-time-format-row.ts b/src/panels/profile/ha-pick-time-format-row.ts
index e890e10474..b9d24d597f 100644
--- a/src/panels/profile/ha-pick-time-format-row.ts
+++ b/src/panels/profile/ha-pick-time-format-row.ts
@@ -35,10 +35,14 @@ class TimeFormatRow extends LitElement {
naturalMenuWidth
>
${Object.values(TimeFormat).map((format) => {
- const formattedTime = formatTime(date, {
- ...this.hass.locale,
- time_format: format,
- });
+ const formattedTime = formatTime(
+ date,
+ {
+ ...this.hass.locale,
+ time_format: format,
+ },
+ this.hass.config
+ );
const value = this.hass.localize(
`ui.panel.profile.time_format.formats.${format}`
);
diff --git a/src/panels/profile/ha-pick-time-zone-row.ts b/src/panels/profile/ha-pick-time-zone-row.ts
new file mode 100644
index 0000000000..c1bd070406
--- /dev/null
+++ b/src/panels/profile/ha-pick-time-zone-row.ts
@@ -0,0 +1,76 @@
+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 { fireEvent } from "../../common/dom/fire_event";
+import "../../components/ha-card";
+import "../../components/ha-select";
+import "../../components/ha-settings-row";
+import { TimeZone } from "../../data/translation";
+import { HomeAssistant } from "../../types";
+
+@customElement("ha-pick-time-zone-row")
+class TimeZoneRow extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property() public narrow!: boolean;
+
+ protected render(): TemplateResult {
+ const date = new Date();
+ return html`
+
+
+ ${this.hass.localize("ui.panel.profile.time_zone.header")}
+
+
+ ${this.hass.localize("ui.panel.profile.time_zone.description")}
+
+
+ ${Object.values(TimeZone).map((format) => {
+ const formattedTime = formatDateTimeNumeric(
+ date,
+ {
+ ...this.hass.locale,
+ time_zone: format,
+ },
+ this.hass.config
+ );
+ return html`
+ ${this.hass.localize(
+ `ui.panel.profile.time_zone.options.${format}`,
+ {
+ timezone: (format === "server"
+ ? this.hass.config.time_zone
+ : Intl.DateTimeFormat?.().resolvedOptions?.().timeZone ||
+ ""
+ ).replace("_", " "),
+ }
+ )}
+ ${formattedTime}
+ `;
+ })}
+
+
+ `;
+ }
+
+ private async _handleFormatSelection(ev) {
+ fireEvent(this, "hass-time-zone-select", ev.target.value);
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-pick-time-zone-row": TimeZoneRow;
+ }
+}
diff --git a/src/state-summary/state-card-display.ts b/src/state-summary/state-card-display.ts
index 9214ecc1fb..a168d05711 100755
--- a/src/state-summary/state-card-display.ts
+++ b/src/state-summary/state-card-display.ts
@@ -42,7 +42,7 @@ export class StateCardDisplay extends LitElement {
this.stateObj.attributes.device_class ===
SENSOR_DEVICE_CLASS_TIMESTAMP &&
!isUnavailableState(this.stateObj.state)
- ? html`
diff --git a/src/state-summary/state-card-input_number.ts b/src/state-summary/state-card-input_number.ts
index d455a5a862..6cd218fb03 100644
--- a/src/state-summary/state-card-input_number.ts
+++ b/src/state-summary/state-card-input_number.ts
@@ -72,6 +72,7 @@ class StateCardInputNumber extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
this.stateObj.state
)}
diff --git a/src/state-summary/state-card-select.ts b/src/state-summary/state-card-select.ts
index 78c749c48e..354136c67e 100644
--- a/src/state-summary/state-card-select.ts
+++ b/src/state-summary/state-card-select.ts
@@ -36,6 +36,7 @@ class StateCardSelect extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
+ this.hass.config,
this.hass.entities,
option
)}
diff --git a/src/state/connection-mixin.ts b/src/state/connection-mixin.ts
index b02e26d837..c2c81cc87f 100644
--- a/src/state/connection-mixin.ts
+++ b/src/state/connection-mixin.ts
@@ -23,6 +23,7 @@ import {
NumberFormat,
DateFormat,
TimeFormat,
+ TimeZone,
} from "../data/translation";
import { subscribePanels } from "../data/ws-panels";
import { translationMetadata } from "../resources/translations-metadata";
@@ -63,6 +64,7 @@ export const connectionMixin = >(
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
},
resources: null as any,
diff --git a/src/state/translations-mixin.ts b/src/state/translations-mixin.ts
index 149c478925..66b86a140a 100644
--- a/src/state/translations-mixin.ts
+++ b/src/state/translations-mixin.ts
@@ -15,6 +15,7 @@ import {
TimeFormat,
DateFormat,
TranslationCategory,
+ TimeZone,
} from "../data/translation";
import { translationMetadata } from "../resources/translations-metadata";
import { Constructor, HomeAssistant } from "../types";
@@ -41,6 +42,9 @@ declare global {
"hass-date-format-select": {
date_format: DateFormat;
};
+ "hass-time-zone-select": {
+ time_zone: TimeZone;
+ };
"hass-first-weekday-select": {
first_weekday: FirstWeekday;
};
@@ -89,6 +93,9 @@ export default >(superClass: T) =>
this.addEventListener("hass-date-format-select", (e) => {
this._selectDateFormat((e as CustomEvent).detail, true);
});
+ this.addEventListener("hass-time-zone-select", (e) => {
+ this._selectTimeZone((e as CustomEvent).detail, true);
+ });
this.addEventListener("hass-first-weekday-select", (e) => {
this._selectFirstWeekday((e as CustomEvent).detail, true);
});
@@ -137,6 +144,13 @@ export default >(superClass: T) =>
// We just got date_format from backend, no need to save back
this._selectDateFormat(locale.date_format, false);
}
+ if (
+ locale?.time_zone &&
+ this.hass!.locale.time_zone !== locale.time_zone
+ ) {
+ // We just got time_zone from backend, no need to save back
+ this._selectTimeZone(locale.time_zone, false);
+ }
if (
locale?.first_weekday &&
this.hass!.locale.first_weekday !== locale.first_weekday
@@ -203,6 +217,15 @@ export default >(superClass: T) =>
}
}
+ private _selectTimeZone(time_zone: TimeZone, saveToBackend: boolean) {
+ this._updateHass({
+ locale: { ...this.hass!.locale, time_zone },
+ });
+ if (saveToBackend) {
+ saveTranslationPreferences(this.hass!, this.hass!.locale);
+ }
+ }
+
private _selectFirstWeekday(
first_weekday: FirstWeekday,
saveToBackend: boolean
diff --git a/src/translations/en.json b/src/translations/en.json
index a9f9608190..f03055696a 100755
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -4928,6 +4928,15 @@
"24": "24 hours"
}
},
+ "time_zone": {
+ "header": "Time Zone",
+ "dropdown_label": "Time zone",
+ "description": "Choose the time zone to use for displaying times.",
+ "options": {
+ "local": "Use your local time zone ({timezone})",
+ "server": "Use server time zone ({timezone})"
+ }
+ },
"date_format": {
"header": "Date Format",
"dropdown_label": "Date format",
diff --git a/src/util/common-translation.ts b/src/util/common-translation.ts
index be14097dd8..041d1fa537 100644
--- a/src/util/common-translation.ts
+++ b/src/util/common-translation.ts
@@ -77,6 +77,7 @@ export async function getUserLocale(
const number_format = result?.number_format;
const time_format = result?.time_format;
const date_format = result?.date_format;
+ const time_zone = result?.time_zone;
const first_weekday = result?.first_weekday;
if (language) {
const availableLanguage = findAvailableLanguage(language);
@@ -85,7 +86,8 @@ export async function getUserLocale(
language: availableLanguage,
number_format,
time_format,
- date_format: date_format,
+ date_format,
+ time_zone,
first_weekday,
};
}
@@ -93,7 +95,8 @@ export async function getUserLocale(
return {
number_format,
time_format,
- date_format: date_format,
+ date_format,
+ time_zone,
first_weekday,
};
}
diff --git a/test/common/datetime/format_date.ts b/test/common/datetime/format_date.ts
index 9d6841ea7d..d399b58e25 100644
--- a/test/common/datetime/format_date.ts
+++ b/test/common/datetime/format_date.ts
@@ -6,20 +6,27 @@ import {
TimeFormat,
FirstWeekday,
DateFormat,
+ TimeZone,
} from "../../../src/data/translation";
+import { demoConfig } from "../../../src/fake_data/demo_config";
describe("formatDate", () => {
const dateObj = new Date(2017, 10, 18, 11, 12, 13, 1400);
it("Formats English dates", () => {
assert.strictEqual(
- formatDate(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.language,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatDate(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.language,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"November 18, 2017"
);
});
diff --git a/test/common/datetime/format_date_time.ts b/test/common/datetime/format_date_time.ts
index 5632d60615..2f7988e5d3 100644
--- a/test/common/datetime/format_date_time.ts
+++ b/test/common/datetime/format_date_time.ts
@@ -9,30 +9,42 @@ import {
TimeFormat,
FirstWeekday,
DateFormat,
+ TimeZone,
} from "../../../src/data/translation";
+import { demoConfig } from "../../../src/fake_data/demo_config";
describe("formatDateTime", () => {
const dateObj = new Date(2017, 10, 18, 23, 12, 13, 400);
it("Formats English date times", () => {
assert.strictEqual(
- formatDateTime(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.am_pm,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatDateTime(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.am_pm,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"November 18, 2017 at 11:12 PM"
);
assert.strictEqual(
- formatDateTime(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.twenty_four,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatDateTime(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.twenty_four,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"November 18, 2017 at 23:12"
);
});
@@ -43,23 +55,34 @@ describe("formatDateTimeWithSeconds", () => {
it("Formats English date times with seconds", () => {
assert.strictEqual(
- formatDateTimeWithSeconds(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.am_pm,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatDateTimeWithSeconds(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.am_pm,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"November 18, 2017 at 11:12:13 PM"
);
assert.strictEqual(
- formatDateTimeWithSeconds(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.twenty_four,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatDateTimeWithSeconds(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.twenty_four,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"November 18, 2017 at 23:12:13"
);
});
diff --git a/test/common/datetime/format_time.ts b/test/common/datetime/format_time.ts
index 3c7e7899c7..3dbbcfd0a8 100644
--- a/test/common/datetime/format_time.ts
+++ b/test/common/datetime/format_time.ts
@@ -10,30 +10,42 @@ import {
TimeFormat,
FirstWeekday,
DateFormat,
+ TimeZone,
} from "../../../src/data/translation";
+import { demoConfig } from "../../../src/fake_data/demo_config";
describe("formatTime", () => {
const dateObj = new Date(2017, 10, 18, 23, 12, 13, 1400);
it("Formats English times", () => {
assert.strictEqual(
- formatTime(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.am_pm,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatTime(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.am_pm,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"11:12 PM"
);
assert.strictEqual(
- formatTime(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.twenty_four,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatTime(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.twenty_four,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"23:12"
);
});
@@ -44,23 +56,33 @@ describe("formatTimeWithSeconds", () => {
it("Formats English times with seconds", () => {
assert.strictEqual(
- formatTimeWithSeconds(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.am_pm,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatTimeWithSeconds(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.am_pm,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"11:12:13 PM"
);
assert.strictEqual(
- formatTimeWithSeconds(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.twenty_four,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatTimeWithSeconds(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.twenty_four,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"23:12:13"
);
});
@@ -71,23 +93,33 @@ describe("formatTimeWeekday", () => {
it("Formats English times", () => {
assert.strictEqual(
- formatTimeWeekday(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.am_pm,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatTimeWeekday(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.am_pm,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"Saturday 11:12 PM"
);
assert.strictEqual(
- formatTimeWeekday(dateObj, {
- language: "en",
- number_format: NumberFormat.language,
- time_format: TimeFormat.twenty_four,
- date_format: DateFormat.language,
- first_weekday: FirstWeekday.language,
- }),
+ formatTimeWeekday(
+ dateObj,
+ {
+ language: "en",
+ number_format: NumberFormat.language,
+ time_format: TimeFormat.twenty_four,
+ date_format: DateFormat.language,
+ time_zone: TimeZone.local,
+ first_weekday: FirstWeekday.language,
+ },
+ demoConfig
+ ),
"Saturday 23:12"
);
});
diff --git a/test/common/datetime/relative_time.ts b/test/common/datetime/relative_time.ts
index ebdf39185b..a99ed08765 100644
--- a/test/common/datetime/relative_time.ts
+++ b/test/common/datetime/relative_time.ts
@@ -6,6 +6,7 @@ import {
TimeFormat,
FirstWeekday,
DateFormat,
+ TimeZone,
} from "../../../src/data/translation";
describe("relativeTime", () => {
@@ -14,6 +15,7 @@ describe("relativeTime", () => {
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
};
@@ -22,6 +24,7 @@ describe("relativeTime", () => {
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.monday,
};
diff --git a/test/common/entity/compute_state_display.ts b/test/common/entity/compute_state_display.ts
index f09df55c5d..2cfc130a56 100644
--- a/test/common/entity/compute_state_display.ts
+++ b/test/common/entity/compute_state_display.ts
@@ -7,7 +7,9 @@ import {
TimeFormat,
FirstWeekday,
DateFormat,
+ TimeZone,
} from "../../../src/data/translation";
+import { demoConfig } from "../../../src/fake_data/demo_config";
let localeData: FrontendLocaleData;
@@ -22,6 +24,7 @@ describe("computeStateDisplay", () => {
number_format: NumberFormat.comma_decimal,
time_format: TimeFormat.am_pm,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
};
});
@@ -33,7 +36,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"component.binary_sensor.entity_component._.state.off"
);
});
@@ -47,7 +50,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"component.binary_sensor.state.moisture.off"
);
});
@@ -67,7 +70,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(altLocalize, stateObj, localeData, {}),
+ computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
"component.binary_sensor.state.invalid_device_class.off"
);
});
@@ -81,7 +84,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"123 m"
);
});
@@ -95,7 +98,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"1,234.5 m"
);
});
@@ -109,7 +112,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"1,234.5"
);
});
@@ -129,7 +132,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(altLocalize, stateObj, localeData, {}),
+ computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
"state.default.unknown"
);
});
@@ -149,7 +152,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(altLocalize, stateObj, localeData, {}),
+ computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
"state.default.unavailable"
);
});
@@ -169,7 +172,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
- computeStateDisplay(altLocalize, stateObj, localeData, {}),
+ computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
"component.sensor.entity_component._.state.custom_state"
);
});
@@ -191,14 +194,14 @@ describe("computeStateDisplay", () => {
};
it("Uses am/pm time format", () => {
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"November 18, 2017 at 11:12 PM"
);
});
it("Uses 24h time format", () => {
localeData.time_format = TimeFormat.twenty_four;
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"November 18, 2017 at 23:12"
);
});
@@ -220,7 +223,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"November 18, 2017"
);
});
@@ -243,14 +246,14 @@ describe("computeStateDisplay", () => {
it("Uses am/pm time format", () => {
localeData.time_format = TimeFormat.am_pm;
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"11:12 PM"
);
});
it("Uses 24h time format", () => {
localeData.time_format = TimeFormat.twenty_four;
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, {}),
"23:12"
);
});
@@ -277,6 +280,7 @@ describe("computeStateDisplay", () => {
localize,
stateObj,
localeData,
+ demoConfig,
{},
"2021-07-04 15:40:03"
),
@@ -290,6 +294,7 @@ describe("computeStateDisplay", () => {
localize,
stateObj,
localeData,
+ demoConfig,
{},
"2021-07-04 15:40:03"
),
@@ -314,7 +319,14 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}, "2021-07-04"),
+ computeStateDisplay(
+ localize,
+ stateObj,
+ localeData,
+ demoConfig,
+ {},
+ "2021-07-04"
+ ),
"July 4, 2021"
);
});
@@ -337,14 +349,28 @@ describe("computeStateDisplay", () => {
it("Uses am/pm time format", () => {
localeData.time_format = TimeFormat.am_pm;
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}, "17:05:07"),
+ computeStateDisplay(
+ localize,
+ stateObj,
+ localeData,
+ demoConfig,
+ {},
+ "17:05:07"
+ ),
"5:05 PM"
);
});
it("Uses 24h time format", () => {
localeData.time_format = TimeFormat.twenty_four;
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, {}, "17:05:07"),
+ computeStateDisplay(
+ localize,
+ stateObj,
+ localeData,
+ demoConfig,
+ {},
+ "17:05:07"
+ ),
"17:05"
);
});
@@ -363,7 +389,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
- computeStateDisplay(altLocalize, stateObj, localeData, {}),
+ computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
"state.default.unavailable"
);
});
@@ -378,7 +404,7 @@ describe("computeStateDisplay", () => {
attributes: {},
};
assert.strictEqual(
- computeStateDisplay(altLocalize, stateObj, localeData, {}),
+ computeStateDisplay(altLocalize, stateObj, localeData, demoConfig, {}),
"My Custom State"
);
});
@@ -396,7 +422,7 @@ describe("computeStateDisplay", () => {
},
};
assert.strictEqual(
- computeStateDisplay(localize, stateObj, localeData, entities),
+ computeStateDisplay(localize, stateObj, localeData, demoConfig, entities),
"component.custom_integration.entity.sensor.custom_translation.state.custom_state"
);
});
diff --git a/test/common/string/format_number.ts b/test/common/string/format_number.ts
index 986ab9a01b..2004b06234 100644
--- a/test/common/string/format_number.ts
+++ b/test/common/string/format_number.ts
@@ -12,6 +12,7 @@ import {
TimeFormat,
FirstWeekday,
DateFormat,
+ TimeZone,
} from "../../../src/data/translation";
describe("formatNumber", () => {
@@ -21,6 +22,7 @@ describe("formatNumber", () => {
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
+ time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
};