diff --git a/src/panels/lovelace/card-features/hui-date-set-card-feature.ts b/src/panels/lovelace/card-features/hui-date-set-card-feature.ts
new file mode 100644
index 0000000000..b4041ebbb9
--- /dev/null
+++ b/src/panels/lovelace/card-features/hui-date-set-card-feature.ts
@@ -0,0 +1,143 @@
+import { html, LitElement, nothing } from "lit";
+import { customElement, property, state } from "lit/decorators";
+import { computeDomain } from "../../../common/entity/compute_domain";
+import "../../../components/ha-control-slider";
+import type { HomeAssistant } from "../../../types";
+import type { LovelaceCardFeature } from "../types";
+import { cardFeatureStyles } from "./common/card-feature-styles";
+import type {
+ LovelaceCardFeatureContext,
+ DateSetCardFeatureConfig,
+} from "./types";
+import { fireEvent } from "../../../common/dom/fire_event";
+import type { DatePickerDialogParams } from "../../../components/ha-date-input";
+import { firstWeekdayIndex } from "../../../common/datetime/first_weekday";
+import "../../../components/ha-control-button";
+import "../../../components/ha-control-button-group";
+
+const loadDatePickerDialog = () =>
+ import("../../../components/ha-dialog-date-picker");
+
+export const supportsDateSetCardFeature = (
+ hass: HomeAssistant,
+ context: LovelaceCardFeatureContext
+) => {
+ const stateObj = context.entity_id
+ ? hass.states[context.entity_id]
+ : undefined;
+ if (!stateObj) return false;
+ const domain = computeDomain(stateObj.entity_id);
+ return (
+ (domain === "input_datetime" && stateObj.attributes.has_date) ||
+ ["datetime", "date"].includes(domain)
+ );
+};
+
+@customElement("hui-date-set-card-feature")
+class HuiDateSetCardFeature extends LitElement implements LovelaceCardFeature {
+ @property({ attribute: false }) public hass?: HomeAssistant;
+
+ @property({ attribute: false }) public context?: LovelaceCardFeatureContext;
+
+ @property({ attribute: false }) public color?: string;
+
+ @state() private _config?: DateSetCardFeatureConfig;
+
+ private get _stateObj() {
+ if (!this.hass || !this.context || !this.context.entity_id) {
+ return undefined;
+ }
+ return this.hass.states[this.context.entity_id!] ?? undefined;
+ }
+
+ private _pressButton() {
+ if (!this.hass || !this._stateObj) return;
+
+ const dialogParams: DatePickerDialogParams = {
+ min: "1970-01-01",
+ value: this._stateObj.state,
+ onChange: (value) => this._dateChanged(value),
+ locale: this.hass.locale.language,
+ firstWeekday: firstWeekdayIndex(this.hass.locale),
+ };
+
+ fireEvent(this, "show-dialog", {
+ dialogTag: "ha-dialog-date-picker",
+ dialogImport: loadDatePickerDialog,
+ dialogParams,
+ });
+ }
+
+ private _dateChanged(value: string | undefined) {
+ if (!this.hass || !this._stateObj || !value) return;
+
+ const domain = computeDomain(this._stateObj.entity_id);
+ const service = domain === "input_datetime" ? "set_datetime" : "set_value";
+
+ // datetime requires a full datetime string
+ if (domain === "datetime") {
+ const dateObj = new Date(this._stateObj.state);
+ const selectedDate = new Date(`${value}T00:00:00`);
+ dateObj.setFullYear(
+ selectedDate.getFullYear(),
+ selectedDate.getMonth(),
+ selectedDate.getDate()
+ );
+
+ this.hass.callService(domain, service, {
+ entity_id: this._stateObj.entity_id,
+ datetime: dateObj.toISOString(),
+ });
+ } else {
+ this.hass.callService(domain, service, {
+ entity_id: this._stateObj.entity_id,
+ date: value,
+ });
+ }
+ }
+
+ static getStubConfig(): DateSetCardFeatureConfig {
+ return {
+ type: "date-set",
+ };
+ }
+
+ public setConfig(config: DateSetCardFeatureConfig): void {
+ if (!config) {
+ throw new Error("Invalid configuration");
+ }
+ this._config = config;
+ }
+
+ protected render() {
+ if (
+ !this._config ||
+ !this.hass ||
+ !this.context ||
+ !this._stateObj ||
+ !supportsDateSetCardFeature(this.hass, this.context)
+ ) {
+ return nothing;
+ }
+
+ return html`
+
+
+ ${this.hass.localize("ui.card.date.set_date")}
+
+
+ `;
+ }
+
+ static styles = cardFeatureStyles;
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hui-date-set-card-feature": HuiDateSetCardFeature;
+ }
+}
diff --git a/src/panels/lovelace/card-features/types.ts b/src/panels/lovelace/card-features/types.ts
index 0b15db11d5..a31e533c1c 100644
--- a/src/panels/lovelace/card-features/types.ts
+++ b/src/panels/lovelace/card-features/types.ts
@@ -101,6 +101,10 @@ export interface CounterActionsCardFeatureConfig {
actions?: CounterActions[];
}
+export interface DateSetCardFeatureConfig {
+ type: "date-set";
+}
+
export interface SelectOptionsCardFeatureConfig {
type: "select-options";
options?: string[];
@@ -213,6 +217,7 @@ export type LovelaceCardFeatureConfig =
| CoverPositionCardFeatureConfig
| CoverTiltPositionCardFeatureConfig
| CoverTiltCardFeatureConfig
+ | DateSetCardFeatureConfig
| FanDirectionCardFeatureConfig
| FanPresetModesCardFeatureConfig
| FanSpeedCardFeatureConfig
diff --git a/src/panels/lovelace/create-element/create-card-feature-element.ts b/src/panels/lovelace/create-element/create-card-feature-element.ts
index bdbc44999d..bd12120d59 100644
--- a/src/panels/lovelace/create-element/create-card-feature-element.ts
+++ b/src/panels/lovelace/create-element/create-card-feature-element.ts
@@ -10,6 +10,7 @@ import "../card-features/hui-cover-open-close-card-feature";
import "../card-features/hui-cover-position-card-feature";
import "../card-features/hui-cover-tilt-card-feature";
import "../card-features/hui-cover-tilt-position-card-feature";
+import "../card-features/hui-date-set-card-feature";
import "../card-features/hui-fan-direction-card-feature";
import "../card-features/hui-fan-preset-modes-card-feature";
import "../card-features/hui-fan-speed-card-feature";
@@ -53,6 +54,7 @@ const TYPES = new Set([
"cover-position",
"cover-tilt-position",
"cover-tilt",
+ "date-set",
"fan-direction",
"fan-preset-modes",
"fan-speed",
diff --git a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts
index 3b09645c39..678f04a9e7 100644
--- a/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts
+++ b/src/panels/lovelace/editor/config-elements/hui-card-features-editor.ts
@@ -30,6 +30,7 @@ import { supportsCoverOpenCloseCardFeature } from "../../card-features/hui-cover
import { supportsCoverPositionCardFeature } from "../../card-features/hui-cover-position-card-feature";
import { supportsCoverTiltCardFeature } from "../../card-features/hui-cover-tilt-card-feature";
import { supportsCoverTiltPositionCardFeature } from "../../card-features/hui-cover-tilt-position-card-feature";
+import { supportsDateSetCardFeature } from "../../card-features/hui-date-set-card-feature";
import { supportsFanDirectionCardFeature } from "../../card-features/hui-fan-direction-card-feature";
import { supportsFanPresetModesCardFeature } from "../../card-features/hui-fan-preset-modes-card-feature";
import { supportsFanSpeedCardFeature } from "../../card-features/hui-fan-speed-card-feature";
@@ -78,6 +79,7 @@ const UI_FEATURE_TYPES = [
"cover-position",
"cover-tilt-position",
"cover-tilt",
+ "date-set",
"fan-direction",
"fan-preset-modes",
"fan-speed",
@@ -141,6 +143,7 @@ const SUPPORTS_FEATURE_TYPES: Record<
"cover-position": supportsCoverPositionCardFeature,
"cover-tilt-position": supportsCoverTiltPositionCardFeature,
"cover-tilt": supportsCoverTiltCardFeature,
+ "date-set": supportsDateSetCardFeature,
"fan-direction": supportsFanDirectionCardFeature,
"fan-preset-modes": supportsFanPresetModesCardFeature,
"fan-speed": supportsFanSpeedCardFeature,
diff --git a/src/translations/en.json b/src/translations/en.json
index fa899bfa8a..e5d394505b 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -147,6 +147,9 @@
"close_tilt_cover": "Close cover tilt",
"stop_cover": "Stop cover"
},
+ "date": {
+ "set_date": "Set date"
+ },
"fan": {
"preset_mode": "Preset mode",
"oscillate": "Oscillate",
@@ -7861,6 +7864,9 @@
"cover-tilt-position": {
"label": "Cover tilt position"
},
+ "date-set": {
+ "label": "Set date"
+ },
"fan-direction": {
"label": "Fan direction"
},