Allow to show times in the UI in the timezone of the server (#16799)

This commit is contained in:
Bram Kragten 2023-06-13 12:12:13 +02:00 committed by GitHub
parent f7722a270f
commit 780de42e4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
120 changed files with 1169 additions and 442 deletions

View File

@ -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 {
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatDateNumeric(date, {
...defaultLocale,
language: key,
date_format: DateFormat.language,
})}
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.language,
},
this.hass.config
)}
</div>
<div class="center">
${formatDateNumeric(date, {
...defaultLocale,
language: key,
date_format: DateFormat.DMY,
})}
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.DMY,
},
this.hass.config
)}
</div>
<div class="center">
${formatDateNumeric(date, {
...defaultLocale,
language: key,
date_format: DateFormat.MDY,
})}
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.MDY,
},
this.hass.config
)}
</div>
<div class="center">
${formatDateNumeric(date, {
...defaultLocale,
language: key,
date_format: DateFormat.YMD,
})}
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.YMD,
},
this.hass.config
)}
</div>
</div>
`

View File

@ -354,6 +354,7 @@ export class DemoEntityState extends LitElement {
hass.localize,
entry.stateObj,
hass.locale,
hass.config,
hass.entities
)}`,
},

View File

@ -143,7 +143,11 @@ export class SupervisorBackupContent extends LitElement {
: this._localize("partial_backup")}
(${Math.ceil(this.backup.size * 10) / 10 + " MB"})<br />
${this.hass
? formatDateTime(new Date(this.backup.date), this.hass.locale)
? formatDateTime(
new Date(this.backup.date),
this.hass.locale,
this.hass.config
)
: this.backup.date}
</div>`
: html`<paper-input
@ -336,7 +340,9 @@ export class SupervisorBackupContent extends LitElement {
const data: any = {};
if (!this.backup) {
data.name = this.backupName || formatDate(new Date(), this.hass.locale);
data.name =
this.backupName ||
formatDate(new Date(), this.hass.locale, this.hass.config);
}
if (this.backupHasPassword) {

View File

@ -1,4 +1,5 @@
import { isSameDay, isSameYear } from "date-fns";
import { HassConfig } from "home-assistant-js-websocket";
import { FrontendLocaleData } from "../../data/translation";
import {
formatShortDateTime,
@ -9,15 +10,16 @@ import { formatTime } from "./format_time";
export const absoluteTime = (
from: Date,
locale: FrontendLocaleData,
config: HassConfig,
to?: Date
): string => {
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);
};

View File

@ -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);

View File

@ -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,
})
);

View File

@ -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
)}`;

View File

@ -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,
})
);

View File

@ -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

View File

@ -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;
}

View File

@ -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)
)
);

View File

@ -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)
)
);

View File

@ -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 "";
}

View File

@ -71,6 +71,7 @@ class StateHistoryChartLine extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
config: this.hass.config,
},
},
suggestedMax: this.endTime,

View File

@ -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,
];
},

View File

@ -146,6 +146,7 @@ class StatisticsChart extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
config: this.hass.config,
},
},
ticks: {

View File

@ -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

View File

@ -192,6 +192,7 @@ export class HaStateLabelBadge extends LitElement {
this.hass!.localize,
entityState,
this.hass!.locale,
this.hass!.config,
this.hass!.entities
);
}

View File

@ -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
);
}
}
}

View File

@ -62,6 +62,7 @@ class HaAttributes extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
this.hass.config,
this.hass.entities,
attribute
)}

View File

@ -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})`

View File

@ -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}

View File

@ -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)}
>
<div slot="input" class="date-range-inputs">
<ha-svg-icon .path=${mdiCalendar}></ha-svg-icon>
<ha-textfield
.value=${this.timePicker
? formatDateTime(this.startDate, this.hass.locale)
: formatDate(this.startDate, this.hass.locale)}
? formatDateTime(
this.startDate,
this.hass.locale,
this.hass.config
)
: formatDate(this.startDate, this.hass.locale, this.hass.config)}
.label=${this.hass.localize(
"ui.components.date-range-picker.start_date"
)}
@ -83,8 +159,8 @@ export class HaDateRangePicker extends LitElement {
></ha-textfield>
<ha-textfield
.value=${this.timePicker
? formatDateTime(this.endDate, this.hass.locale)
: formatDate(this.endDate, this.hass.locale)}
? formatDateTime(this.endDate, this.hass.locale, this.hass.config)
: formatDate(this.endDate, this.hass.locale, this.hass.config)}
.label=${this.hass.localize(
"ui.components.date-range-picker.end_date"
)}

View File

@ -127,7 +127,8 @@ export class HaTracePathDetails extends LitElement {
Executed:
${formatDateTimeWithSeconds(
new Date(timestamp),
this.hass.locale
this.hass.locale,
this.hass.config
)}<br />
${result
? html`Result:

View File

@ -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:
${(

View File

@ -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) {

View File

@ -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<HomeAssistant["areas"]>("areas");
export const localizeContext =
createContext<HomeAssistant["localize"]>("localize");
export const localeContext = createContext<HomeAssistant["locale"]>("locale");
export const configContext = createContext<HomeAssistant["config"]>("config");
export const configContext = createContext<HassConfig>("config");
export const themesContext = createContext<HomeAssistant["themes"]>("themes");
export const selectedThemeContext =
createContext<HomeAssistant["selectedTheme"]>("selectedTheme");

View File

@ -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();

View File

@ -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,

View File

@ -439,6 +439,7 @@ export const localizeStateMessage = (
localize,
stateObj,
hass.locale,
hass.config,
hass.entities,
state
)

View File

@ -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
)})`;
}

View File

@ -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 {

View File

@ -72,6 +72,7 @@ export class HaMoreInfoFanSpeed extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities,
speed
);

View File

@ -39,6 +39,7 @@ export class HaMoreInfoStateHeader extends LitElement {
this.hass!.localize,
stateObj,
this.hass!.locale,
this.hass!.config,
this.hass!.entities
);

View File

@ -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

View File

@ -83,6 +83,7 @@ class MoreInfoCover extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
this.hass.config,
this.hass.entities,
forcedState
);

View File

@ -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

View File

@ -83,6 +83,7 @@ class MoreInfoHumidifier extends LitElement {
hass.localize,
stateObj,
hass.locale,
this.hass.config,
hass.entities,
"mode",
mode

View File

@ -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

View File

@ -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

View File

@ -44,6 +44,7 @@ class MoreInfoRemote extends LitElement {
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities,
"activity",
activity

View File

@ -44,7 +44,8 @@ class MoreInfoSun extends LitElement {
<div class="value">
${formatTime(
item === "ris" ? risingDate : settingDate,
this.hass.locale
this.hass.locale,
this.hass.config
)}
</div>
</div>

View File

@ -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
)}
</strong>
@ -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"
)}

View File

@ -164,7 +164,8 @@ class MoreInfoWeather extends LitElement {
<div class="main">
${formatTimeWeekday(
new Date(item.datetime),
this.hass.locale
this.hass.locale,
this.hass.config
)}
</div>
`
@ -172,7 +173,8 @@ class MoreInfoWeather extends LitElement {
<div class="main">
${formatDateWeekdayDay(
new Date(item.datetime),
this.hass.locale
this.hass.locale,
this.hass.config
)}
</div>
`}

View File

@ -38,6 +38,7 @@ export class HuiConfiguratorNotificationItem extends LitElement {
this.hass.localize,
this.notification,
this.hass.locale,
this.hass.config,
this.hass.entities
)}</mwc-button
>

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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)
}`;
}

View File

@ -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);
}
)
);

View File

@ -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")}
</div>
@ -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")}
`;

View File

@ -192,7 +192,8 @@ export class HaAutomationTrace extends LitElement {
html`<option value=${trace.run_id}>
${formatDateTimeWithSeconds(
new Date(trace.timestamp.start),
this.hass.locale
this.hass.locale,
this.hass.config
)}
</option>`
)}

View File

@ -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
)
: ""
)

View File

@ -49,7 +49,8 @@ class DialogCloudCertificate extends LitElement {
)}
${formatDateTime(
new Date(certificateInfo.expire_date),
this.hass!.locale
this.hass!.locale,
this.hass!.config
)}<br />
(${this.hass!.localize(
"ui.panel.config.cloud.dialog_certificate.will_be_auto_renewed"

View File

@ -55,7 +55,8 @@ class MQTTMessages extends LitElement {
${this.direction}
${formatTimeWithSeconds(
new Date(message.time),
this.hass.locale
this.hass.locale,
this.hass.config
)}
</div>
${this._renderSingleMessage(message)}

View File

@ -170,6 +170,7 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
adapters: {
date: {
locale: this.hass.locale,
config: this.hass.config,
},
},
gridLines: {

View File

@ -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"

View File

@ -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[] => {

View File

@ -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)
)}
<pre>${msg.payload}</pre>
<div class="bottom">

View File

@ -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) <br />
`
: ""}
Last logged:
${formatSystemLogTime(item.timestamp, this.hass!.locale)}
${formatSystemLogTime(
item.timestamp,
this.hass!.locale,
this.hass!.config
)}
</p>
${item.message.length > 1
? html`

View File

@ -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
);

View File

@ -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);
};

View File

@ -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
)
: ""}
</div>

View File

@ -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];

View File

@ -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")}
`;

View File

@ -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")}
</div>
@ -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")}
`;

View File

@ -191,7 +191,8 @@ export class HaScriptTrace extends LitElement {
html`<option value=${trace.run_id}>
${formatDateTimeWithSeconds(
new Date(trace.timestamp.start),
this.hass.locale
this.hass.locale,
this.hass.config
)}
</option>`
)}

View File

@ -64,7 +64,8 @@ export class AssistPipelineDebug extends LitElement {
html`<option value=${run.pipeline_run_id}>
${formatDateTimeWithSeconds(
new Date(run.timestamp),
this.hass.locale
this.hass.locale,
this.hass.config
)}
</option>`
)}

View File

@ -80,7 +80,8 @@ class EventSubscribeCard extends LitElement {
)}
${formatTime(
new Date(event.event.time_fired),
this.hass!.locale
this.hass!.locale,
this.hass!.config
)}:
<ha-yaml-editor
.defaultValue=${event.event}

View File

@ -158,7 +158,11 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
>
<span>${growth} ${unit}</span>
<span slot="secondary">
${formatDateTime(new Date(stat.start), this.hass.locale)}
${formatDateTime(
new Date(stat.start),
this.hass.locale,
this.hass.config
)}
</span>
<ha-svg-icon slot="meta" .path=${mdiChevronRight}></ha-svg-icon>
</mwc-list-item>
@ -213,7 +217,8 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
<span
>${formatDateTime(
new Date(this._chosenStat!.start),
this.hass.locale
this.hass.locale,
this.hass.config
)}</span
>
</div>
@ -223,7 +228,8 @@ export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
<span
>${formatDateTime(
new Date(this._chosenStat!.end),
this.hass.locale
this.hass.locale,
this.hass.config
)}</span
>
</div>

View File

@ -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}
></ha-date-range-picker>
<ha-target-picker
@ -220,24 +206,6 @@ class HaPanelHistory extends SubscribeMixin(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)],
};
const searchParams = extractSearchParamsObject();
const entityIds = searchParams.entity_id;
const deviceIds = searchParams.device_id;

View File

@ -192,7 +192,11 @@ class HaLogbookRenderer extends LitElement {
new Date(previous.when * 1000).toDateString())
? html`
<h4 class="date">
${formatDate(new Date(item.when * 1000), this.hass.locale)}
${formatDate(
new Date(item.when * 1000),
this.hass.locale,
this.hass.config
)}
</h4>
`
: nothing}
@ -229,7 +233,8 @@ class HaLogbookRenderer extends LitElement {
<span
>${formatTimeWithSeconds(
new Date(item.when * 1000),
this.hass.locale
this.hass.locale,
this.hass.config
)}</span
>
-

View File

@ -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}
></ha-date-range-picker>
@ -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();
}

View File

@ -60,18 +60,27 @@ export class HuiEnergyCompareCard
<ha-alert dismissable @alert-dismissed-clicked=${this._stopCompare}>
${this.hass.localize("ui.panel.energy.compare.info", {
start: html`<b
>${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
)}`
: ""}</b
>`,
end: html`<b
>${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)}`
: ""}</b
>`,
})}

View File

@ -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) =>

View File

@ -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) =>

View File

@ -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) =>

View File

@ -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) =>

View File

@ -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<any>({ context: entitiesContext, subscribe: true })
@transform<HomeAssistant["entities"], EntityRegistryDisplayEntry>({
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
)}
</span>`

View File

@ -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
)}</span
>${showUnit

View File

@ -337,6 +337,7 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass!.locale,
this.hass!.config,
this.hass!.entities
)}
</div>

View File

@ -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"
)}

View File

@ -161,6 +161,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
)}
</div>

View File

@ -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);
}

View File

@ -123,6 +123,7 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
);

View File

@ -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
)}
</div>

View File

@ -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"
)}

View File

@ -228,6 +228,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
this.hass!.localize,
stateObj,
this.hass!.locale,
this.hass!.config,
this.hass!.entities
);

View File

@ -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
)}
</div>
@ -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
)}
`}
</div>

View File

@ -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) {
<div class="row">
<div class="label">
${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
)}`}
<ha-icon-button-prev
.label=${this.hass.localize(
@ -186,12 +197,14 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
this._setDate(
this._period === "day"
? startOfDay(start)
? calcDate(start, startOfDay, this.hass.locale, this.hass.config)
: this._period === "week"
? startOfWeek(start, { weekStartsOn })
? calcDate(start, startOfWeek, this.hass.locale, this.hass.config, {
weekStartsOn,
})
: this._period === "month"
? startOfMonth(start)
: startOfYear(start)
? calcDate(start, startOfMonth, this.hass.locale, this.hass.config)
: calcDate(start, startOfYear, this.hass.locale, this.hass.config)
);
}
@ -200,12 +213,20 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
this._setDate(
this._period === "day"
? startOfToday()
? calcDate(new Date(), startOfDay, this.hass.locale, this.hass.config)
: this._period === "week"
? startOfWeek(new Date(), { weekStartsOn })
? calcDate(
new Date(),
startOfWeek,
this.hass.locale,
this.hass.config,
{
weekStartsOn,
}
)
: this._period === "month"
? startOfMonth(new Date())
: startOfYear(new Date())
? calcDate(new Date(), startOfMonth, this.hass.locale, this.hass.config)
: calcDate(new Date(), startOfYear, this.hass.locale, this.hass.config)
);
}
@ -238,12 +259,14 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
const endDate =
this._period === "day"
? endOfDay(startDate)
? calcDate(startDate, endOfDay, this.hass.locale, this.hass.config)
: this._period === "week"
? endOfWeek(startDate, { weekStartsOn })
? calcDate(startDate, endOfWeek, this.hass.locale, this.hass.config, {
weekStartsOn,
})
: this._period === "month"
? endOfMonth(startDate)
: endOfYear(startDate);
? calcDate(startDate, endOfMonth, this.hass.locale, this.hass.config)
: calcDate(startDate, endOfYear, this.hass.locale, this.hass.config);
const energyCollection = getEnergyDataCollection(this.hass, {
key: this.collectionKey,

View File

@ -1,3 +1,4 @@
import { HassConfig } from "home-assistant-js-websocket";
import { html, LitElement, PropertyValues, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { formatDate } from "../../../common/datetime/format_date";
@ -10,7 +11,11 @@ import { HomeAssistant } from "../../../types";
import { TimestampRenderingFormat } from "./types";
const FORMATS: {
[key: string]: (ts: Date, lang: FrontendLocaleData) => 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"

View File

@ -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}

View File

@ -70,6 +70,7 @@ class HuiGroupEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
)}
</div>

View File

@ -54,6 +54,7 @@ class HuiHumidifierEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities,
"mode"
)})`

View File

@ -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
)}

View File

@ -193,6 +193,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow {
this.hass.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
)}
>

View File

@ -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
)}

View File

@ -82,6 +82,7 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass!.locale,
this.hass!.config,
this.hass!.entities,
option
)}

View File

@ -83,6 +83,7 @@ class HuiSensorEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
)}
</div>

View File

@ -53,6 +53,7 @@ class HuiSimpleEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
)}
</hui-generic-entity-row>

View File

@ -65,6 +65,7 @@ class HuiToggleEntityRow extends LitElement implements LovelaceRow {
this.hass!.localize,
stateObj,
this.hass!.locale,
this.hass.config,
this.hass!.entities
)}
</div>

Some files were not shown because too many files have changed in this diff Show More