Fix browser time format handling (#22694)

* implement hook to return resolved "24hour" | "12hour" string

delegate to existing use24HourTime(), which correctly detects the browser's locale preference via Intl.DateTimeFormat

* update frontend to use use24HourTime(config) or useTimeFormat(config) instead of directly comparing config.ui.time_format
This commit is contained in:
Josh Hawkins 2026-03-29 14:03:07 -05:00 committed by GitHub
parent f44f485f48
commit 257dae11c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 165 additions and 133 deletions

View File

@ -8,6 +8,7 @@ import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { useTranslation } from "react-i18next";
import { useTimeFormat } from "@/hooks/use-date-utils";
const GRAPH_COLORS = ["#3b82f6", "#ef4444"]; // RMS, dBFS
@ -72,7 +73,7 @@ export function AudioLevelGraph({ cameraName }: AudioLevelGraphProps) {
return [last.rms, last.dBFS];
}, [audioData]);
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const formatString = useMemo(
() =>
t(`time.formattedTimestampHourMinuteSecond.${timeFormat}`, {

View File

@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { useDateLocale } from "@/hooks/use-date-locale";
import { useTimeFormat } from "@/hooks/use-date-utils";
import { useMemo } from "react";
type DownloadVideoButtonProps = {
@ -26,7 +27,7 @@ export function DownloadVideoButton({
const { data: config } = useSWR<FrigateConfig>("config");
const locale = useDateLocale();
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = useMemo(() => {
return t(`time.formattedTimestampFilename.${timeFormat}`, { ns: "common" });
}, [t, timeFormat]);

View File

@ -1,5 +1,5 @@
import { baseUrl } from "@/api/baseUrl";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import { FrigateConfig } from "@/types/frigateConfig";
import { REVIEW_PADDING, ReviewSegment } from "@/types/review";
import { getIconForLabel } from "@/utils/iconUtil";
@ -55,9 +55,10 @@ export default function ReviewCard({
const { t } = useTranslation(["components/dialog"]);
const { data: config } = useSWR<FrigateConfig>("config");
const [imgRef, imgLoaded, onImgLoad] = useImageLoaded();
const is24Hour = use24HourTime(config);
const formattedDate = useFormattedTimestamp(
event.start_time,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestampHourMinute.24hour", { ns: "common" })
: t("time.formattedTimestampHourMinute.12hour", { ns: "common" }),
config?.ui.timezone,

View File

@ -1,7 +1,7 @@
import TimeAgo from "../dynamic/TimeAgo";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import { SearchResult } from "@/types/search";
import ActivityIndicator from "../indicators/activity-indicator";
import SearchResultActions from "../menu/SearchResultActions";
@ -29,9 +29,10 @@ export default function SearchThumbnailFooter({
const { data: config } = useSWR<FrigateConfig>("config");
// date
const is24Hour = use24HourTime(config);
const formattedDate = useFormattedTimestamp(
searchResult.start_time,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestampMonthDayHourMinute.24hour", { ns: "common" })
: t("time.formattedTimestampMonthDayHourMinute.12hour", { ns: "common" }),
config?.ui.timezone,

View File

@ -43,6 +43,7 @@ import {
SelectItem,
} from "@/components/ui/select";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import { use24HourTime } from "@/hooks/use-date-utils";
import FilterSwitch from "@/components/filter/FilterSwitch";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Trans, useTranslation } from "react-i18next";
@ -752,6 +753,7 @@ export function CameraNotificationSwitch({
};
const locale = useDateLocale();
const is24Hour = use24HourTime(config);
const formatSuspendedUntil = (timestamp: string) => {
if (timestamp === "0") return t("time.untilForRestart", { ns: "common" });
@ -760,14 +762,13 @@ export function CameraNotificationSwitch({
time_style: "medium",
date_style: "medium",
timezone: config?.ui.timezone,
date_format:
config?.ui.time_format == "24hour"
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
ns: "common",
})
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
ns: "common",
}),
date_format: is24Hour
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
ns: "common",
})
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
ns: "common",
}),
locale: locale,
});
return t("time.untilForTime", { ns: "common", time });

View File

@ -8,6 +8,7 @@ import { isMobileOnly } from "react-device-detect";
import { useTranslation } from "react-i18next";
import { MdCircle } from "react-icons/md";
import useSWR from "swr";
import { useTimeFormat } from "@/hooks/use-date-utils";
const GRAPH_COLORS = ["#5C7CFA", "#ED5CFA", "#FAD75C"];
@ -48,7 +49,7 @@ export function CameraLineGraph({
const locale = useDateLocale();
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = useMemo(() => {
return t(`time.formattedTimestampHourMinute.${timeFormat}`, {
ns: "common",
@ -203,7 +204,7 @@ export function EventsPerSecondsLineGraph({
const locale = useDateLocale();
const { t } = useTranslation(["common"]);
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = useMemo(() => {
return t(`time.formattedTimestampHourMinute.${timeFormat}`, {
ns: "common",

View File

@ -8,6 +8,7 @@ import Chart from "react-apexcharts";
import { isMobileOnly } from "react-device-detect";
import { useTranslation } from "react-i18next";
import useSWR from "swr";
import { useTimeFormat } from "@/hooks/use-date-utils";
type ThresholdBarGraphProps = {
graphId: string;
@ -53,7 +54,7 @@ export function ThresholdBarGraph({
const locale = useDateLocale();
const { t } = useTranslation(["common"]);
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = useMemo(() => {
return t(`time.formattedTimestampHourMinute.${timeFormat}`, {
ns: "common",

View File

@ -50,6 +50,7 @@ import {
import { toast } from "sonner";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { use24HourTime } from "@/hooks/use-date-utils";
import { MdImageSearch } from "react-icons/md";
import { useTranslation } from "react-i18next";
import { getTranslatedLabel } from "@/utils/i18n";
@ -80,6 +81,8 @@ export default function InputWithTags({
const { data: config } = useSWR<FrigateConfig>("config", {
revalidateOnFocus: false,
});
const is24Hour = use24HourTime(config);
const resolvedTimeFormat = is24Hour ? "24hour" : ("12hour" as const);
const allAudioListenLabels = useMemo<Set<string>>(() => {
if (!config) {
@ -431,12 +434,8 @@ export default function InputWithTags({
const [startTime, endTime] = (filterValues as string)
.replace("-", ",")
.split(",");
return `${
config?.ui.time_format === "24hour"
? startTime
: convertTo12Hour(startTime)
} - ${
config?.ui.time_format === "24hour" ? endTime : convertTo12Hour(endTime)
return `${is24Hour ? startTime : convertTo12Hour(startTime)} - ${
is24Hour ? endTime : convertTo12Hour(endTime)
}`;
} else if (filterType === "min_score" || filterType === "max_score") {
return Math.round(Number(filterValues) * 100).toString() + "%";
@ -478,7 +477,7 @@ export default function InputWithTags({
(filterType === "time_range" &&
isValidTimeRange(
trimmedValue.replace("-", ","),
config?.ui.time_format,
resolvedTimeFormat,
)) ||
((filterType === "min_score" || filterType === "max_score") &&
!isNaN(Number(trimmedValue)) &&
@ -495,7 +494,7 @@ export default function InputWithTags({
? trimmedValue
.replace("-", ",")
.split(",")
.map((time) => to24Hour(time.trim(), config?.ui.time_format))
.map((time) => to24Hour(time.trim(), resolvedTimeFormat))
.join(",")
: trimmedValue,
);
@ -511,7 +510,7 @@ export default function InputWithTags({
setCurrentFilterType(null);
}
},
[allSuggestions, createFilter, config],
[allSuggestions, createFilter, resolvedTimeFormat],
);
const handleInputChange = useCallback(
@ -598,7 +597,7 @@ export default function InputWithTags({
suggestion = suggestion
.replace("-", ",")
.split(",")
.map((time) => to24Hour(time.trim(), config?.ui.time_format))
.map((time) => to24Hour(time.trim(), resolvedTimeFormat))
.join(",");
}
createFilter(currentFilterType, suggestion);
@ -627,7 +626,7 @@ export default function InputWithTags({
inputRef.current?.focus();
},
[createFilter, currentFilterType, allSuggestions, config],
[createFilter, currentFilterType, allSuggestions, resolvedTimeFormat],
);
const handleSearch = useCallback(
@ -779,10 +778,7 @@ export default function InputWithTags({
</li>
<li>
{t("filter.tips.desc.step5", {
exampleTime:
config?.ui.time_format == "24hour"
? "15:00-16:00"
: "3:00PM-4:00PM",
exampleTime: is24Hour ? "15:00-16:00" : "3:00PM-4:00PM",
})}
</li>
<li>{t("filter.tips.desc.step6")}</li>

View File

@ -46,6 +46,7 @@ import {
} from "@/api/ws";
import { useTranslation } from "react-i18next";
import { useDateLocale } from "@/hooks/use-date-locale";
import { use24HourTime } from "@/hooks/use-date-utils";
import { useIsAdmin } from "@/hooks/use-is-admin";
import { CameraNameLabel } from "../camera/FriendlyNameLabel";
import { LiveStreamMetadata } from "@/types/live";
@ -247,6 +248,8 @@ export default function LiveContextMenu({
const locale = useDateLocale();
const is24Hour = use24HourTime(config);
const formatSuspendedUntil = (timestamp: string) => {
// Some languages require a change in word order
if (timestamp === "0") return t("time.untilForRestart", { ns: "common" });
@ -255,14 +258,13 @@ export default function LiveContextMenu({
time_style: "medium",
date_style: "medium",
timezone: config?.ui.timezone,
date_format:
config?.ui.time_format == "24hour"
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
ns: "common",
})
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
ns: "common",
}),
date_format: is24Hour
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
ns: "common",
})
: t("time.formattedTimestampMonthDayHourMinute.12hour", {
ns: "common",
}),
locale: locale,
});
return t("time.untilForTime", { ns: "common", time });

View File

@ -3,7 +3,7 @@ import { Button } from "../ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { SelectSeparator } from "../ui/select";
import { TimeRange } from "@/types/timeline";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import { getUTCOffset } from "@/utils/dateUtil";
import { TimezoneAwareCalendar } from "./ReviewActivityCalendar";
import { FaArrowRight, FaCalendarAlt } from "react-icons/fa";
@ -69,16 +69,18 @@ export function CustomTimeSelector({
return time;
}, [range, latestTime, timezoneOffset, localTimeOffset]);
const is24Hour = use24HourTime(config);
const formattedStart = useFormattedTimestamp(
startTime,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestamp.24hour")
: t("time.formattedTimestamp.12hour"),
);
const formattedEnd = useFormattedTimestamp(
endTime,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestamp.24hour")
: t("time.formattedTimestamp.12hour"),
);

View File

@ -2,7 +2,7 @@ import { isDesktop, isIOS, isMobile, isSafari } from "react-device-detect";
import { SearchResult } from "@/types/search";
import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import { getIconForLabel } from "@/utils/iconUtil";
import { useApiHost } from "@/api";
import { Button } from "../../ui/button";
@ -769,9 +769,10 @@ function ObjectDetailsTab({
setShowNavigationButtons,
]);
const is24Hour = use24HourTime(config);
const formattedDate = useFormattedTimestamp(
search?.start_time ?? 0,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestampMonthDayYearHourMinute.24hour", {
ns: "common",
})

View File

@ -7,6 +7,7 @@ import ActivityIndicator from "@/components/indicators/activity-indicator";
import { TrackingDetailsSequence } from "@/types/timeline";
import { FrigateConfig } from "@/types/frigateConfig";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import { use24HourTime } from "@/hooks/use-date-utils";
import { getIconForLabel } from "@/utils/iconUtil";
import { LuCircle, LuFolderX } from "react-icons/lu";
import { cn } from "@/lib/utils";
@ -428,17 +429,18 @@ export function TrackingDetails({
[annotationOffset, displaySource, timestampToVideoTime],
);
const is24Hour = use24HourTime(config);
const formattedStart = config
? formatUnixTimestampToDateTime(event.start_time ?? 0, {
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t("time.formattedTimestamp.24hour", {
ns: "common",
})
: t("time.formattedTimestamp.12hour", {
ns: "common",
}),
date_format: is24Hour
? t("time.formattedTimestamp.24hour", {
ns: "common",
})
: t("time.formattedTimestamp.12hour", {
ns: "common",
}),
time_style: "medium",
date_style: "medium",
})
@ -448,14 +450,13 @@ export function TrackingDetails({
config && event.end_time != null
? formatUnixTimestampToDateTime(event.end_time, {
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t("time.formattedTimestamp.24hour", {
ns: "common",
})
: t("time.formattedTimestamp.12hour", {
ns: "common",
}),
date_format: is24Hour
? t("time.formattedTimestamp.24hour", {
ns: "common",
})
: t("time.formattedTimestamp.12hour", {
ns: "common",
}),
time_style: "medium",
date_style: "medium",
})
@ -917,24 +918,25 @@ function LifecycleIconRow({
[effectiveTime, item.timestamp],
);
const is24Hour = use24HourTime(config);
const formattedEventTimestamp = useMemo(
() =>
config
? formatUnixTimestampToDateTime(item.timestamp ?? 0, {
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t("time.formattedTimestampHourMinuteSecond.24hour", {
ns: "common",
})
: t("time.formattedTimestampHourMinuteSecond.12hour", {
ns: "common",
}),
date_format: is24Hour
? t("time.formattedTimestampHourMinuteSecond.24hour", {
ns: "common",
})
: t("time.formattedTimestampHourMinuteSecond.12hour", {
ns: "common",
}),
time_style: "medium",
date_style: "medium",
})
: "",
[config, item.timestamp, t],
[config, is24Hour, item.timestamp, t],
);
const ratio = useMemo(

View File

@ -12,7 +12,7 @@ import useSWR from "swr";
import { FrigateConfig } from "@/types/frigateConfig";
import { isIOS, isMobile, isSafari } from "react-device-detect";
import Chip from "@/components/indicators/Chip";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import useImageLoaded from "@/hooks/use-image-loaded";
import { useSwipeable } from "react-swipeable";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
@ -174,9 +174,10 @@ export default function PreviewThumbnailPlayer({
// date
const is24Hour = use24HourTime(config);
const formattedDate = useFormattedTimestamp(
review.start_time,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestampMonthDayHourMinute.24hour", { ns: "common" })
: t("time.formattedTimestampMonthDayHourMinute.12hour", { ns: "common" }),
config?.ui?.timezone,

View File

@ -8,6 +8,7 @@ import {
formatUnixTimestampToDateTime,
getDurationFromTimestamps,
} from "@/utils/dateUtil";
import { use24HourTime } from "@/hooks/use-date-utils";
import { useTranslation } from "react-i18next";
import AnnotationOffsetSlider from "@/components/overlay/detail/AnnotationOffsetSlider";
import { FrigateConfig } from "@/types/frigateConfig";
@ -398,12 +399,12 @@ function ReviewGroup({
}
}, [isActive, alwaysExpandActive]);
const is24Hour = use24HourTime(config);
const displayTime = formatUnixTimestampToDateTime(start, {
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t("time.formattedTimestampHourMinuteSecond.24hour", { ns: "common" })
: t("time.formattedTimestampHourMinuteSecond.12hour", { ns: "common" }),
date_format: is24Hour
? t("time.formattedTimestampHourMinuteSecond.24hour", { ns: "common" })
: t("time.formattedTimestampHourMinuteSecond.12hour", { ns: "common" }),
time_style: "medium",
date_style: "medium",
});
@ -787,17 +788,17 @@ function LifecycleItem({
);
}, [config, item]);
const is24Hour = use24HourTime(config);
const formattedEventTimestamp = config
? formatUnixTimestampToDateTime(item?.timestamp ?? 0, {
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t("time.formattedTimestampHourMinuteSecond.24hour", {
ns: "common",
})
: t("time.formattedTimestampHourMinuteSecond.12hour", {
ns: "common",
}),
date_format: is24Hour
? t("time.formattedTimestampHourMinuteSecond.24hour", {
ns: "common",
})
: t("time.formattedTimestampHourMinuteSecond.12hour", {
ns: "common",
}),
time_style: "medium",
date_style: "medium",
})

View File

@ -1,4 +1,4 @@
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, useTimeFormat } from "@/hooks/use-date-utils";
import { FrigateConfig } from "@/types/frigateConfig";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
@ -36,7 +36,7 @@ export function MinimapBounds({
}: MinimapSegmentProps) {
const { data: config } = useSWR<FrigateConfig>("config");
const { t } = useTranslation(["common"]);
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const formatKey = dense
? `time.formattedTimestampHourMinute.${timeFormat}`
@ -104,7 +104,7 @@ export function Timestamp({
const { t } = useTranslation(["common"]);
const { data: config } = useSWR<FrigateConfig>("config");
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = t(`time.formattedTimestampHourMinute.${timeFormat}`);
const formattedTimestamp = useFormattedTimestamp(

View File

@ -84,6 +84,18 @@ export function use24HourTime(config: FrigateConfig | undefined) {
}, [config, localeUses24HourTime]);
}
/**
* Returns the resolved time format key ("24hour" | "12hour") based on config
* and browser locale. Use this instead of checking config.ui.time_format directly
* to correctly handle the "browser" setting.
*/
export function useTimeFormat(
config: FrigateConfig | undefined,
): "24hour" | "12hour" {
const is24Hour = use24HourTime(config);
return is24Hour ? "24hour" : "12hour";
}
export function useFormattedHour(
config: FrigateConfig | undefined,
time: string, // hour is assumed to be in 24 hour format per the Date object

View File

@ -4,6 +4,7 @@ import { FrigateConfig } from "@/types/frigateConfig";
import useSWR from "swr";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import { useDateLocale } from "./use-date-locale";
import { useTimeFormat } from "./use-date-utils";
import { useTranslation } from "react-i18next";
import useUserInteraction from "./use-user-interaction";
@ -168,7 +169,7 @@ function useDraggableElement({
const { t } = useTranslation(["common"]);
const locale = useDateLocale();
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = useMemo(() => {
const formatKey = `time.${
segmentDuration < 60 && !dense

View File

@ -19,7 +19,7 @@ import { useResizeObserver } from "@/hooks/resize-observer";
import { Skeleton } from "@/components/ui/skeleton";
import ActivityIndicator from "@/components/indicators/activity-indicator";
import TimeAgo from "@/components/dynamic/TimeAgo";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import { FrigateConfig } from "@/types/frigateConfig";
const MOTION_HEATMAP_GRID_SIZE = 16;
@ -165,9 +165,10 @@ function MotionPreviewClip({
const [fallbackFrameIndex, setFallbackFrameIndex] = useState(0);
const [fallbackFramesReady, setFallbackFramesReady] = useState(false);
const is24Hour = use24HourTime(config);
const formattedDate = useFormattedTimestamp(
range.start_time,
config?.ui.time_format == "24hour"
is24Hour
? t("time.formattedTimestampMonthDayHourMinute.24hour", {
ns: "common",
})

View File

@ -43,8 +43,9 @@ import { TimezoneAwareCalendar } from "@/components/overlay/ReviewActivityCalend
import { useApiHost } from "@/api";
import { useResizeObserver } from "@/hooks/resize-observer";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import { getUTCOffset } from "@/utils/dateUtil";
import useSWR from "swr";
import { cn } from "@/lib/utils";
import MotionSearchROICanvas from "./MotionSearchROICanvas";
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
@ -452,7 +453,6 @@ export default function MotionSearchDialog({
range={searchRange}
setRange={setSearchRange}
defaultRange={defaultRange}
timeFormat={config.ui?.time_format}
timezone={timezone}
/>
@ -476,7 +476,6 @@ type SearchRangeSelectorProps = {
range?: TimeRange;
setRange: React.Dispatch<React.SetStateAction<TimeRange | undefined>>;
defaultRange: TimeRange;
timeFormat?: "browser" | "12hour" | "24hour";
timezone?: string;
};
@ -484,7 +483,6 @@ function SearchRangeSelector({
range,
setRange,
defaultRange,
timeFormat,
timezone,
}: SearchRangeSelectorProps) {
const { t } = useTranslation(["views/motionSearch", "common"]);
@ -527,15 +525,18 @@ function SearchRangeSelector({
return time;
}, [range, defaultRange, timezoneOffset, localTimeOffset]);
const { data: config } = useSWR<FrigateConfig>("config");
const is24Hour = use24HourTime(config);
const formattedStart = useFormattedTimestamp(
startTime,
timeFormat === "24hour"
is24Hour
? t("time.formattedTimestamp.24hour", { ns: "common" })
: t("time.formattedTimestamp.12hour", { ns: "common" }),
);
const formattedEnd = useFormattedTimestamp(
endTime,
timeFormat === "24hour"
is24Hour
? t("time.formattedTimestamp.24hour", { ns: "common" })
: t("time.formattedTimestamp.12hour", { ns: "common" }),
);

View File

@ -51,7 +51,7 @@ import {
RecordingSegment,
} from "@/types/record";
import { VideoResolutionType } from "@/types/live";
import { useFormattedTimestamp } from "@/hooks/use-date-utils";
import { useFormattedTimestamp, use24HourTime } from "@/hooks/use-date-utils";
import MotionSearchROICanvas from "./MotionSearchROICanvas";
import MotionSearchDialog from "./MotionSearchDialog";
import { IoMdArrowRoundBack } from "react-icons/io";
@ -94,12 +94,13 @@ export default function MotionSearchView({
]);
const navigate = useNavigate();
const is24Hour = use24HourTime(config);
const resultTimestampFormat = useMemo(
() =>
config.ui?.time_format === "24hour"
is24Hour
? t("time.formattedTimestamp.24hour", { ns: "common" })
: t("time.formattedTimestamp.12hour", { ns: "common" }),
[config.ui?.time_format, t],
[is24Hour, t],
);
// Refs

View File

@ -31,6 +31,7 @@ import Chip from "@/components/indicators/Chip";
import { TooltipPortal } from "@radix-ui/react-tooltip";
import SearchActionGroup from "@/components/filter/SearchActionGroup";
import { Trans, useTranslation } from "react-i18next";
import { use24HourTime } from "@/hooks/use-date-utils";
import { useNavigate } from "react-router-dom";
import { useAllowedCameras } from "@/hooks/use-allowed-cameras";
@ -77,6 +78,7 @@ export default function SearchView({
const { data: config } = useSWR<FrigateConfig>("config", {
revalidateOnFocus: false,
});
const is24Hour = use24HourTime(config);
const navigate = useNavigate();
const { data: exploreEvents } = useSWR<SearchResult[]>(
@ -191,10 +193,7 @@ export default function SearchView({
sub_labels: allSubLabels,
...(hasCustomClassificationModels && { attributes: allAttributes }),
search_type: ["thumbnail", "description"] as SearchSource[],
time_range:
config?.ui.time_format == "24hour"
? ["00:00-23:59"]
: ["12:00AM-11:59PM"],
time_range: is24Hour ? ["00:00-23:59"] : ["12:00AM-11:59PM"],
before: [formatDateToLocaleString()],
after: [formatDateToLocaleString(-5)],
min_score: ["50"],
@ -209,6 +208,7 @@ export default function SearchView({
}),
[
config,
is24Hour,
allLabels,
allZones,
allSubLabels,

View File

@ -39,6 +39,7 @@ import { Trigger, TriggerAction, TriggerType } from "@/types/trigger";
import { useSearchEffect } from "@/hooks/use-overlay-state";
import { cn } from "@/lib/utils";
import { formatUnixTimestampToDateTime } from "@/utils/dateUtil";
import { use24HourTime } from "@/hooks/use-date-utils";
import { Link } from "react-router-dom";
import { useTriggers } from "@/api/ws";
import { useCameraFriendlyName } from "@/hooks/use-camera-friendly-name";
@ -89,6 +90,7 @@ export default function TriggerView({
const { t } = useTranslation("views/settings");
const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config");
const is24Hour = use24HourTime(config);
const { data: trigger_status, mutate } = useSWR(
config?.cameras[selectedCamera]?.semantic_search?.triggers &&
Object.keys(config.cameras[selectedCamera].semantic_search.triggers)
@ -581,20 +583,19 @@ export default function TriggerView({
?.last_triggered,
{
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t(
"time.formattedTimestamp2.24hour",
{
ns: "common",
},
)
: t(
"time.formattedTimestamp2.12hour",
{
ns: "common",
},
),
date_format: is24Hour
? t(
"time.formattedTimestamp2.24hour",
{
ns: "common",
},
)
: t(
"time.formattedTimestamp2.12hour",
{
ns: "common",
},
),
time_style: "medium",
date_style: "medium",
},
@ -742,20 +743,19 @@ export default function TriggerView({
?.last_triggered,
{
timezone: config.ui.timezone,
date_format:
config.ui.time_format == "24hour"
? t(
"time.formattedTimestamp2.24hour",
{
ns: "common",
},
)
: t(
"time.formattedTimestamp2.12hour",
{
ns: "common",
},
),
date_format: is24Hour
? t(
"time.formattedTimestamp2.24hour",
{
ns: "common",
},
)
: t(
"time.formattedTimestamp2.12hour",
{
ns: "common",
},
),
time_style: "medium",
date_style: "medium",
},

View File

@ -10,7 +10,11 @@ import {
import useSWR from "swr";
import { CiCircleAlert } from "react-icons/ci";
import { FrigateConfig } from "@/types/frigateConfig";
import { useFormattedTimestamp, useTimezone } from "@/hooks/use-date-utils";
import {
useFormattedTimestamp,
useTimeFormat,
useTimezone,
} from "@/hooks/use-date-utils";
import { RecordingsSummary } from "@/types/review";
import { useTranslation } from "react-i18next";
import { TZDate } from "react-day-picker";
@ -81,7 +85,7 @@ export default function StorageMetrics({
: null;
}, [recordingsSummary, timezone]);
const timeFormat = config?.ui.time_format === "24hour" ? "24hour" : "12hour";
const timeFormat = useTimeFormat(config);
const format = useMemo(() => {
return t(`time.formattedTimestampMonthDayYear.${timeFormat}`, {
ns: "common",