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 8992f92
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 10 deletions.
31 changes: 23 additions & 8 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": "^3.6.0",
"date-fns-tz": "^3.1.3",
"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');
});
});
32 changes: 32 additions & 0 deletions packages/react-components/src/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ import type { TimeInNanos } from '@aws-sdk/client-iotsitewise';
import { NANO_SECOND_IN_MS } from '@iot-app-kit/core';
import parse from 'parse-duration';

/* eslint-disable */
const { toZonedTime, format } = require('date-fns-tz');

// import * as timezones from "date-fns-tz";
// const { toZonedTime, format } = timezones;

export const SECOND_IN_MS = 1000;
export const MINUTE_IN_MS = 60 * SECOND_IN_MS;
export const HOUR_IN_MS = 60 * MINUTE_IN_MS;
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 +173,28 @@ 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 = toZonedTime(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 8992f92

Please sign in to comment.