Skip to content

Commit

Permalink
[Fix] Date formatting in local timezone (#12469)
Browse files Browse the repository at this point in the history
* improve date formatting local timezone

* add helper to get local timezone

* add timezone to parser

* document timezone addition

* fix typo

* handle date type

* remove local timezone helper

* document no timezone for format behaviour

* improve documentation for timezone behaviour

* remove errant import

* add timezone based format tests

* add test same timezone when provided

* remove only on describe
  • Loading branch information
esizer authored Jan 17, 2025
1 parent d9f3972 commit 7216aba
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/date-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@types/jest": "^29.5.14",
"eslint": "^8.57.0",
"jest": "^29.7.0",
"timezone-mock": "^1.3.6",
"tsconfig": "workspace:*",
"typescript": "^5.7.2"
}
Expand Down
49 changes: 49 additions & 0 deletions packages/date-helpers/src/date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import { createIntl, createIntlCache } from "react-intl";
import { parseISO } from "date-fns";
import { tz } from "@date-fns/tz";
import { register } from "timezone-mock";

import {
convertDateTimeToDate,
convertDateTimeZone,
DATETIME_FORMAT_STRING,
formatDate,
parseDateTimeUtc,
relativeClosingDate,
} from "./index";
Expand Down Expand Up @@ -144,3 +147,49 @@ describe("parse DateTime UTC to native Date tests", () => {
expect(actualValue?.valueOf()).toBe(expectedValue.valueOf());
});
});

describe("format date in different timezones", () => {
const f = formatDate;
const intlCache = createIntlCache();
const intl = createIntl(
{
locale: "en",
},
intlCache,
);

test("it formats with timezone UTC provided", () => {
register("US/Eastern");
const actual = f({
date: parseDateTimeUtc("2022-01-01 00:00:00+00:00"),
formatString: DATETIME_FORMAT_STRING,
intl,
});

expect(actual).toBe("2021-12-31 19:00:00");
});

test("it formats with timzone Eastern provide", () => {
// NOTE: This is odd but +5 is actually -5
// REF: https://www.npmjs.com/package/timezone-mock#:~:text=Etc/GMT%2B5%20timezone%20is%20equivalent%20to%20US%20Eastern%20Standard%20Time%20(UTC%2D5).
register("Etc/GMT+5");
const actual = f({
date: parseDateTimeUtc("2022-01-01 00:00:00-05:00"),
formatString: DATETIME_FORMAT_STRING,
intl,
});

expect(actual).toBe("2022-01-01 00:00:00");
});

test("it formats with no timezone provided", () => {
register("US/Pacific");
const actual = f({
date: parseDateTimeUtc("2022-01-01 00:00:00"),
formatString: DATETIME_FORMAT_STRING,
intl,
});

expect(actual).toBe("2021-12-31 16:00:00");
});
});
22 changes: 19 additions & 3 deletions packages/date-helpers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export const currentDate = (): string => new Date().toISOString().slice(0, 10);

/**
* Format a date in given format and locale, optionally in a different time zone
* If no timezone is provided, the timezone will be priority based:
* 1. If the timezone is included in the date object (Date, TZDate) that will be used
* 2. Otherwise, the users local timezone will be used
*
* @returns String in the given format
*/
export const formatDate = ({
Expand Down Expand Up @@ -153,9 +157,21 @@ export const convertDateTimeToDate = (
return d.substring(0, DATE_FORMAT_STRING.length);
};

// Parse an API scalar DateTime as UTC to a native Date object
export const parseDateTimeUtc = (d: Scalars["DateTime"]["input"]): Date =>
parseISO(d, { in: tz("UTC") });
/**
* Parse an API scalar DateTime as UTC to a native Date object
*
* Adds a timezone offset if we think it does not exist
* to support parsing the date into users local timezone properly
*/
export const parseDateTimeUtc = (d: Scalars["DateTime"]["input"]): Date => {
let dateWithTimezone: string = d;
// 1970-01-01 00:00:00 = 19 chars
// 1970-01-01 = 10 chars
if (d.length <= 19 && d.length > 10 && !dateWithTimezone.includes("+")) {
dateWithTimezone = `${d}+00:00`;
}
return parseISO(dateWithTimezone);
};

/**
* Take the current time, convert it to UTC, and then return that time in DATETIME_FORMAT_STRING
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit 7216aba

Please sign in to comment.