diff --git a/fields/core/date/edit-component.tsx b/fields/core/date/edit-component.tsx index 4c7657e98..888241efc 100644 --- a/fields/core/date/edit-component.tsx +++ b/fields/core/date/edit-component.tsx @@ -4,6 +4,22 @@ import { forwardRef } from "react"; import { Input } from "@/components/ui/input"; import { cn } from "@/lib/utils"; +// Server passes/receives UTC wall-clock strings (yyyy-MM-dd'T'HH:mm). Browser converts to/from local. +const toLocal = (value: string, time: boolean) => { + if (!time) return value; + if (!value) return ""; + + const date = new Date(`${value}Z`); + return date.toLocaleString("sv-SE").replace(" ", "T").slice(0, 16); +}; +const toUtc = (value: string, time: boolean) => { + if (!time) return value; + if (!value) return ""; + + const date = new Date(value); + return date.toISOString().slice(0, 16); +}; + const EditComponent = forwardRef((props: any, ref: React.Ref) => { const { field, value, onChange } = props; @@ -14,8 +30,8 @@ const EditComponent = forwardRef((props: any, ref: React.Ref) step={field?.options?.step ?? undefined} ref={ref} type={field?.options?.time ? "datetime-local" : "date"} - value={value} - onChange={onChange} + value={toLocal(value, field?.options?.time)} + onChange={(e) => onChange(toUtc(e.target.value, field?.options?.time))} className={cn("w-auto text-base", field?.readonly && "focus-visible:border-input focus-visible:ring-0")} readOnly={field?.readonly} /> diff --git a/fields/core/date/index.ts b/fields/core/date/index.ts index 531d3b1cd..280024068 100644 --- a/fields/core/date/index.ts +++ b/fields/core/date/index.ts @@ -5,9 +5,10 @@ import { ViewComponent } from "./view-component"; import { parse, format, isValid, isBefore, isAfter } from "date-fns"; const defaultValue = (field: Field) => { - const inputType = field?.options?.time ? "datetime-local" : "date"; - const inputFormat = inputType === "datetime-local" ? "yyyy-MM-dd'T'HH:mm" : "yyyy-MM-dd"; - return format(new Date(), inputFormat); + const inputType = field?.options?.time ? "datetime-local" : "date"; + return (inputType === "datetime-local") + ? new Date().toISOString().slice(0, 16) + : format(new Date(), "yyyy-MM-dd"); }; const read = (value: any, field: Field) => { diff --git a/fields/core/date/view-component.tsx b/fields/core/date/view-component.tsx index 3d52bd765..1bd412a98 100644 --- a/fields/core/date/view-component.tsx +++ b/fields/core/date/view-component.tsx @@ -16,11 +16,13 @@ const ViewComponent = ({ const firstValue = Array.isArray(value) ? value[0] : value; if (firstValue == null) return null; const extraValuesCount = Array.isArray(value) ? value.length - 1 : 0; - const inputFormat = field.options?.time ? "yyyy-MM-dd'T'HH:mm" : "yyyy-MM-dd"; - const outputFormat = field.options?.time ? "MMM d, yyyy - HH:mm" : "MMM d, yyyy"; + const inputType = field?.options?.time ? "datetime-local" : "date"; + const outputFormat = inputType === "datetime-local" ? "MMM d, yyyy - HH:mm" : "MMM d, yyyy"; const formatDate = (date: string) => { - const parsedDate = parse(date, inputFormat, new Date()); + const parsedDate = inputType === "datetime-local" + ? new Date(`${date}Z`) + : parse(date, "yyyy-MM-dd", new Date()); if (!isValid(parsedDate)) { console.warn(`Date for field '${field.name}' is saved in the wrong format or invalid: ${date}.`); return null;