Skip to content

Commit

Permalink
Make export date/time respect configured timezone in config (#10750)
Browse files Browse the repository at this point in the history
* Make export page timezone aware

* Fix changeover
  • Loading branch information
NickM-27 authored Mar 30, 2024
1 parent 4d522be commit 5b5606c
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 10 deletions.
49 changes: 40 additions & 9 deletions web/src/components/overlay/ExportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
66 changes: 66 additions & 0 deletions web/src/components/overlay/ReviewActivityCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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}
/>
);
}
2 changes: 1 addition & 1 deletion web/src/utils/dateUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 5b5606c

Please sign in to comment.