fix chart and timezone issues, pass consistent dates to DB.
Some checks failed
Create docker images (cloud) / Build, push, and deploy (push) Waiting to run
Node.js CI / build (postgresql, 18.18, 10) (push) Has been cancelled

Closes #3700
This commit is contained in:
Francis Cao 2025-11-13 15:52:24 -08:00
parent 81bedec6d5
commit 6751bf88bb
10 changed files with 157 additions and 79 deletions

View file

@ -5,13 +5,13 @@ export function useDateParameters() {
const {
dateRange: { startDate, endDate, unit },
} = useDateRange();
const { timezone, toUtc, canonicalizeTimezone } = useTimezone();
const { timezone, localToUtc, canonicalizeTimezone } = useTimezone();
return {
startAt: +toUtc(startDate),
endAt: +toUtc(endDate),
startDate: toUtc(startDate).toISOString(),
endDate: toUtc(endDate).toISOString(),
startAt: +localToUtc(startDate),
endAt: +localToUtc(endDate),
startDate: localToUtc(startDate).toISOString(),
endDate: localToUtc(endDate).toISOString(),
unit,
timezone: canonicalizeTimezone(timezone),
};

View file

@ -5,7 +5,7 @@ import { useLocale } from '@/components/hooks/useLocale';
import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
import { getItem } from '@/lib/storage';
export function useDateRange(options: { ignoreOffset?: boolean } = {}) {
export function useDateRange(options: { ignoreOffset?: boolean; timezone?: string } = {}) {
const {
query: { date = '', offset = 0, compare = 'prev' },
} = useNavigation();
@ -15,6 +15,7 @@ export function useDateRange(options: { ignoreOffset?: boolean } = {}) {
const dateRangeObject = parseDateRange(
date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE,
locale,
options.timezone,
);
return !options.ignoreOffset && offset

View file

@ -3,11 +3,13 @@ import { TIMEZONE_CONFIG, TIMEZONE_LEGACY } from '@/lib/constants';
import { formatInTimeZone, zonedTimeToUtc, utcToZonedTime } from 'date-fns-tz';
import { useApp, setTimezone } from '@/store/app';
import { useLocale } from './useLocale';
import { getTimezone } from '@/lib/date';
const selector = (state: { timezone: string }) => state.timezone;
export function useTimezone() {
const timezone = useApp(selector);
const localTimeZone = getTimezone();
const { dateLocale } = useLocale();
const saveTimezone = (value: string) => {
@ -26,6 +28,38 @@ export function useTimezone() {
);
};
const formatSeriesTimezone = (data: any, column: string, timezone: string) => {
return data.map(item => {
const date = new Date(item[column]);
const format = new Intl.DateTimeFormat('en-US', {
timeZone: timezone,
hour12: false,
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
});
const parts = format.formatToParts(date);
const get = type => parts.find(p => p.type === type)?.value;
const year = get('year');
const month = get('month');
const day = get('day');
const hour = get('hour');
const minute = get('minute');
const second = get('second');
return {
...item,
[column]: `${year}-${month}-${day} ${hour}:${minute}:${second}`,
};
});
};
const toUtc = (date: Date | string | number) => {
return zonedTimeToUtc(date, timezone);
};
@ -34,16 +68,28 @@ export function useTimezone() {
return utcToZonedTime(date, timezone);
};
const localToUtc = (date: Date | string | number) => {
return zonedTimeToUtc(date, localTimeZone);
};
const localFromUtc = (date: Date | string | number) => {
return utcToZonedTime(date, localTimeZone);
};
const canonicalizeTimezone = (timezone: string): string => {
return TIMEZONE_LEGACY[timezone] ?? timezone;
};
return {
timezone,
saveTimezone,
formatTimezoneDate,
localTimeZone,
toUtc,
fromUtc,
localToUtc,
localFromUtc,
saveTimezone,
formatTimezoneDate,
formatSeriesTimezone,
canonicalizeTimezone,
};
}