Skip to content

Commit

Permalink
feat: add timezone converter util
Browse files Browse the repository at this point in the history
  • Loading branch information
dpportet committed Jul 16, 2024
1 parent 19a7fca commit 47097c8
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 12 deletions.
44 changes: 34 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@
"d3-array": "^3.2.3",
"d3-format": "^3.1.0",
"d3-shape": "^3.2.0",
"date-fns": "^3.4.0",
"date-fns": "^2.30.0",
"date-fns-tz": "^2.0.1",
"dompurify": "3.0.5",
"echarts": "^5.4.3",
"is-hotkey": "^0.2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HistoricalViewport } from '@iot-app-kit/core';
import { sub } from 'date-fns/sub';
import { sub } from 'date-fns';

export const DEFAULT_ANOMALY_DATA_SOURCE_VIEWPORT: HistoricalViewport = {
start: sub(Date.now(), { days: 7 }),
Expand Down
27 changes: 27 additions & 0 deletions packages/react-components/src/utils/time.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SECOND_IN_MS,
toTimestamp,
YEAR_IN_MS,
formatDate,
} from './time';

describe('convert from milliseconds', () => {
Expand Down Expand Up @@ -285,3 +286,29 @@ describe('toTimestamp', () => {
).toBe(0);
});
});

describe('formatDate', () => {
it('correctly converts to a different timezone', () => {
const date = new Date(0).getTime();

const formattedDate = formatDate(date, { timeZone: 'America/Denver' });

// UTC-7
expect(formattedDate).toBe('1969-12-31, 05:00:00 p.m.');

const formattedDate2 = formatDate(date, { timeZone: 'Asia/Tokyo' });

// UTC+9
expect(formattedDate2).toBe('1970-01-01, 09:00:00 a.m.');
});

it('converts date to specified pattern', () => {
const date = new Date(0).getTime();

const formattedDate = formatDate(date, {
timeZone: 'America/Denver',
pattern: 'hh:mm a',
});
expect(formattedDate).toBe('05:00 PM');
});
});
28 changes: 28 additions & 0 deletions packages/react-components/src/utils/time.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { TimeInNanos } from '@aws-sdk/client-iotsitewise';
import { NANO_SECOND_IN_MS } from '@iot-app-kit/core';
import parse from 'parse-duration';
import { utcToZonedTime, format } from 'date-fns-tz';

export const SECOND_IN_MS = 1000;
export const MINUTE_IN_MS = 60 * SECOND_IN_MS;
Expand All @@ -9,6 +10,7 @@ export const DAY_IN_MS = 24 * HOUR_IN_MS;
// Not precisely accurate, only estimates. exact duration depends on start date. use with care.
export const MONTH_IN_MS = 30 * DAY_IN_MS;
export const YEAR_IN_MS = 12 * MONTH_IN_MS;
export const DEFAULT_DATE_TIME = 'yyy-MM-dd, hh:mm:ss aaaa';

// Global time format strings
export const SHORT_TIME = 'hh:mm a';
Expand Down Expand Up @@ -166,3 +168,29 @@ export const toTimestamp = (time: TimeInNanos | undefined): number =>
(time.offsetInNanos || 0) * NANO_SECOND_IN_MS
)) ||
0;

// https://date-fns.org/v3.6.0/docs/Time-Zones#date-fns-tz
// converts an epoch date to a formatted string in a specific timeZone
export const formatDate = (
dateTime: number,
options?: { timeZone?: string; pattern?: string }
) => {
const formatPattern = options?.pattern ?? DEFAULT_DATE_TIME;

const userTimeZone =
options?.timeZone ?? Intl.DateTimeFormat().resolvedOptions().timeZone;

// Convert epoch time to a zoned date object
const zonedDate = utcToZonedTime(new Date(dateTime), userTimeZone);

// Take offset from zoned date to get a date with the days/hours modified based on offset for display
const dateWithOffset = new Date(
zonedDate.valueOf() + zonedDate.getTimezoneOffset() * 60 * 1000
);

const formattedString = format(dateWithOffset, formatPattern, {
timeZone: userTimeZone,
});

return formattedString;
};

0 comments on commit 47097c8

Please sign in to comment.