mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-22 08:57:20 -06:00
Make export date/time respect configured timezone in config (#10750)
* Make export page timezone aware * Fix changeover
This commit is contained in:
parent
4d522be7fb
commit
5b5606cb8a
@ -20,11 +20,12 @@ import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
||||
import useSWR from "swr";
|
||||
import { FrigateConfig } from "@/types/frigateConfig";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
||||
import ReviewActivityCalendar from "./ReviewActivityCalendar";
|
||||
import { TimezoneAwareCalendar } from "./ReviewActivityCalendar";
|
||||
import { SelectSeparator } from "../ui/select";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer";
|
||||
import SaveExportOverlay from "./SaveExportOverlay";
|
||||
import { getUTCOffset } from "@/utils/dateUtil";
|
||||
|
||||
const EXPORT_OPTIONS = [
|
||||
"1",
|
||||
@ -305,14 +306,42 @@ function CustomTimeSelector({
|
||||
|
||||
// times
|
||||
|
||||
const startTime = useMemo(
|
||||
() => range?.after || latestTime - 3600,
|
||||
[range, latestTime],
|
||||
const timezoneOffset = useMemo(
|
||||
() =>
|
||||
config?.ui.timezone
|
||||
? Math.round(getUTCOffset(new Date(), config.ui.timezone))
|
||||
: undefined,
|
||||
[config?.ui.timezone],
|
||||
);
|
||||
const endTime = useMemo(
|
||||
() => range?.before || latestTime,
|
||||
[range, latestTime],
|
||||
const localTimeOffset = useMemo(
|
||||
() =>
|
||||
Math.round(
|
||||
getUTCOffset(
|
||||
new Date(),
|
||||
Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
),
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
const startTime = useMemo(() => {
|
||||
let time = range?.after || latestTime - 3600;
|
||||
|
||||
if (timezoneOffset) {
|
||||
time = time + (timezoneOffset - localTimeOffset) * 60;
|
||||
}
|
||||
|
||||
return time;
|
||||
}, [range, latestTime, timezoneOffset, localTimeOffset]);
|
||||
const endTime = useMemo(() => {
|
||||
let time = range?.before || latestTime;
|
||||
|
||||
if (timezoneOffset) {
|
||||
time = time + (timezoneOffset - localTimeOffset) * 60;
|
||||
}
|
||||
|
||||
return time;
|
||||
}, [range, latestTime, timezoneOffset, localTimeOffset]);
|
||||
const formattedStart = useFormattedTimestamp(
|
||||
startTime,
|
||||
config?.ui.time_format == "24hour"
|
||||
@ -367,7 +396,8 @@ function CustomTimeSelector({
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="flex flex-col items-center">
|
||||
<ReviewActivityCalendar
|
||||
<TimezoneAwareCalendar
|
||||
timezone={config?.ui.timezone}
|
||||
selectedDay={new Date(startTime * 1000)}
|
||||
onSelect={(day) => {
|
||||
if (!day) {
|
||||
@ -428,7 +458,8 @@ function CustomTimeSelector({
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="flex flex-col items-center">
|
||||
<ReviewActivityCalendar
|
||||
<TimezoneAwareCalendar
|
||||
timezone={config?.ui.timezone}
|
||||
selectedDay={new Date(endTime * 1000)}
|
||||
onSelect={(day) => {
|
||||
if (!day) {
|
||||
|
@ -2,6 +2,7 @@ import { ReviewSummary } from "@/types/review";
|
||||
import { Calendar } from "../ui/calendar";
|
||||
import { useMemo } from "react";
|
||||
import { FaCircle } from "react-icons/fa";
|
||||
import { getUTCOffset } from "@/utils/dateUtil";
|
||||
|
||||
type ReviewActivityCalendarProps = {
|
||||
reviewSummary?: ReviewSummary;
|
||||
@ -76,3 +77,68 @@ function ReviewActivityDay({ reviewSummary, day }: ReviewActivityDayProps) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type TimezoneAwareCalendarProps = {
|
||||
timezone?: string;
|
||||
selectedDay?: Date;
|
||||
onSelect: (day?: Date) => void;
|
||||
};
|
||||
export function TimezoneAwareCalendar({
|
||||
timezone,
|
||||
selectedDay,
|
||||
onSelect,
|
||||
}: TimezoneAwareCalendarProps) {
|
||||
const timezoneOffset = useMemo(
|
||||
() =>
|
||||
timezone ? Math.round(getUTCOffset(new Date(), timezone)) : undefined,
|
||||
[timezone],
|
||||
);
|
||||
const disabledDates = useMemo(() => {
|
||||
const tomorrow = new Date();
|
||||
|
||||
if (timezoneOffset) {
|
||||
tomorrow.setHours(
|
||||
tomorrow.getHours() + 24,
|
||||
tomorrow.getMinutes() + timezoneOffset,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
} else {
|
||||
tomorrow.setHours(tomorrow.getHours() + 24, -1, 0, 0);
|
||||
}
|
||||
|
||||
const future = new Date();
|
||||
future.setFullYear(tomorrow.getFullYear() + 10);
|
||||
return { from: tomorrow, to: future };
|
||||
}, [timezoneOffset]);
|
||||
|
||||
const today = useMemo(() => {
|
||||
if (!timezoneOffset) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
const utc = Date.UTC(
|
||||
date.getUTCFullYear(),
|
||||
date.getUTCMonth(),
|
||||
date.getUTCDate(),
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
);
|
||||
const todayUtc = new Date(utc);
|
||||
todayUtc.setMinutes(todayUtc.getMinutes() + timezoneOffset, 0, 0);
|
||||
return todayUtc;
|
||||
}, [timezoneOffset]);
|
||||
|
||||
return (
|
||||
<Calendar
|
||||
mode="single"
|
||||
disabled={disabledDates}
|
||||
showOutsideDays={false}
|
||||
today={today}
|
||||
selected={selectedDay}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ export const getDurationFromTimestamps = (
|
||||
* @param timezone string representation of the timezone the user is requesting
|
||||
* @returns number of minutes offset from UTC
|
||||
*/
|
||||
const getUTCOffset = (date: Date, timezone: string): number => {
|
||||
export const getUTCOffset = (date: Date, timezone: string): number => {
|
||||
// If timezone is in UTC±HH:MM format, parse it to get offset
|
||||
const utcOffsetMatch = timezone.match(/^UTC([+-])(\d{2}):(\d{2})$/);
|
||||
if (utcOffsetMatch) {
|
||||
|
Loading…
Reference in New Issue
Block a user