Make export date/time respect configured timezone in config (#10750)

* Make export page timezone aware

* Fix changeover
This commit is contained in:
Nicolas Mowen 2024-03-30 13:07:30 -06:00 committed by GitHub
parent 4d522be7fb
commit 5b5606cb8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 107 additions and 10 deletions

View File

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

View File

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

View File

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