Skip to content

feat(formatDate): add locale option to be extensible for absolute format #19157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,7 @@
]
},
{

"login": "murito",
"name": "Francisco Alcalá",
"avatar_url": "https://avatars.githubusercontent.com/u/2628140?v=4",
Expand All @@ -1858,6 +1859,15 @@
"code"
]
},
{
"login": "dkaushik95",
"name": "Dishant Kaushik",
"avatar_url": "https://avatars.githubusercontent.com/u/8481567?v=4",
"profile": "https://github.com/dkaushik95",
"contributions": [
"code"
]
},
{
"login": "Code-Suji",
"name": "SUJITH C S",
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,10 @@ check out our [Contributing Guide](/.github/CONTRIBUTING.md) and our
<td align="center"><a href="https://github.com/maisonsmd"><img src="https://avatars.githubusercontent.com/u/16435155?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Son H. Mai (Mason)</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=maisonsmd" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/warrenmblood"><img src="https://avatars.githubusercontent.com/u/69060697?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Warren Blood</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=warrenmblood" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vcherneny"><img src="https://avatars.githubusercontent.com/u/11604315?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vlad Cherneny</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=vcherneny" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/dkaushik95"><img src="https://avatars.githubusercontent.com/u/8481567?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dishant Kaushik</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=dkaushik95" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/jose-biescas"><img src="https://avatars.githubusercontent.com/u/188625806?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jose Biescas</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=jose-biescas" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/murito"><img src="https://avatars.githubusercontent.com/u/2628140?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Francisco Alcalá</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=murito" title="Code">💻</a></td>
<td align="center"><a href="https://www.linkedin.com/in/sujithcs"><img src="https://avatars.githubusercontent.com/u/43125517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>SUJITH C S</b></sub></a><br /><a href="https://github.com/carbon-design-system/carbon/commits?author=Code-Suji" title="Code">💻</a></td>
</tr>
Expand Down
19 changes: 19 additions & 0 deletions packages/utilities/src/dateTimeFormat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,22 @@ dateTimeFormat.absolute.formatRange(startDate, sameDayEndDate, {
});
// 3:47 – 4:29 PM
```

#### Timezone

For `absolute` functions, you can provide `timeZone` as an optional property.
This is useful when (for example) you want to display utc time instead of a
local timezone.
Copy link
Contributor

@preetibansalui preetibansalui May 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is useful when (for example) you want to display UTC time instead of a
local time zone.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks! Fixed :)


```js
import { dateTimeFormat } from '@carbon/utilities';

dateTimeFormat.absolute.format(timestamp);
// Apr 4, 2024 at 3:47 PM

dateTimeFormat.absolute.format(timestamp, { timeZone: 'UTC' });
// Apr 4, 2024 at 10:47 PM
```

Timezone options are according to
[ECMAScript® 2026 Internationalization API Specification](https://tc39.es/ecma402/#datetimeformat-objects)
77 changes: 76 additions & 1 deletion packages/utilities/src/dateTimeFormat/absolute-test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2024
* Copyright IBM Corp. 2024, 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
Expand All @@ -12,6 +12,7 @@ const styles = ['full', 'long', 'medium', 'short'];
const date = new Date('2016-04-28T19:12:47Z');
const endDate = new Date('2018-07-01T09:00:02Z');
const sameDayEndDate = new Date('2016-04-28T21:04:30Z');
const timeZones = ['UTC', 'Asia/Tokyo'];

describe(locale, () => {
describe('formatTime', () => {
Expand All @@ -24,6 +25,24 @@ describe(locale, () => {
expect(actualOutput).toBe(expectedOutput);
});
});

timeZones.forEach((timeZone) => {
const style = styles[0];
const dtf = new Intl.DateTimeFormat(locale, {
timeStyle: style,
timeZone,
});
const expectedOutput = dtf.format(date);

test(`timeZone ${timeZone} → ${expectedOutput}`, () => {
const actualOutput = absolute.formatTime(date, {
locale,
style,
timeZone,
});
expect(actualOutput).toBe(expectedOutput);
});
});
});

describe('formatDate', () => {
Expand All @@ -36,6 +55,24 @@ describe(locale, () => {
expect(actualOutput).toBe(expectedOutput);
});
});

timeZones.forEach((timeZone) => {
const style = styles[0];
const dtf = new Intl.DateTimeFormat(locale, {
dateStyle: style,
timeZone,
});
const expectedOutput = dtf.format(date);

test(`timeZone ${timeZone} → ${expectedOutput}`, () => {
const actualOutput = absolute.formatDate(date, {
locale,
style,
timeZone,
});
expect(actualOutput).toBe(expectedOutput);
});
});
});

describe('format', () => {
Expand Down Expand Up @@ -71,6 +108,25 @@ describe(locale, () => {
});
});

timeZones.forEach((timeZone) => {
const timeStyle = styles[0];
const dtf = new Intl.DateTimeFormat(locale, {
timeStyle,
dateStyle: timeStyle,
timeZone,
});
const expectedOutput = dtf.format(date);

test(`timeZone ${timeZone} → ${expectedOutput}`, () => {
const actualOutput = absolute.format(date, {
locale,
style: timeStyle,
timeZone,
});
expect(actualOutput).toBe(expectedOutput);
});
});

const dtf = new Intl.DateTimeFormat(locale, {
timeStyle: 'long',
dateStyle: 'full',
Expand Down Expand Up @@ -136,5 +192,24 @@ describe(locale, () => {
});
});
});

timeZones.forEach((timeZone) => {
const dateStyle = styles[0];
const dtf = new Intl.DateTimeFormat(locale, {
timeStyle: dateStyle,
dateStyle,
timeZone,
});
const expectedOutput = dtf.formatRange(date, endDate);

test(`timeZone ${timeZone} → ${expectedOutput}`, () => {
const actualOutput = absolute.formatRange(date, endDate, {
locale,
style: dateStyle,
timeZone,
});
expect(actualOutput).toBe(expectedOutput);
});
});
});
});
10 changes: 9 additions & 1 deletion packages/utilities/src/dateTimeFormat/absolute.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright IBM Corp. 2024
* Copyright IBM Corp. 2024, 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
Expand All @@ -10,10 +10,12 @@ export function formatTime(
options?: Partial<{
locale: string;
style: Intl.DateTimeFormatOptions['timeStyle'];
timeZone: Intl.DateTimeFormatOptions['timeZone'];
}>
): string {
const dtf = new Intl.DateTimeFormat(options?.locale, {
timeStyle: options?.style ?? 'short',
timeZone: options?.timeZone,
});

return dtf.format(date);
Expand All @@ -24,10 +26,12 @@ export function formatDate(
options?: Partial<{
locale: string;
style: Intl.DateTimeFormatOptions['dateStyle'];
timeZone: Intl.DateTimeFormatOptions['timeZone'];
}>
): string {
const dtf = new Intl.DateTimeFormat(options?.locale, {
dateStyle: options?.style ?? 'medium',
timeZone: options?.timeZone,
});

return dtf.format(date);
Expand All @@ -40,6 +44,7 @@ export function format(
style: Intl.DateTimeFormatOptions['timeStyle'] | 'tooltip';
timeStyle: Intl.DateTimeFormatOptions['timeStyle'];
dateStyle: Intl.DateTimeFormatOptions['dateStyle'];
timeZone: Intl.DateTimeFormatOptions['timeZone'];
}>
) {
const timeStyle =
Expand All @@ -55,6 +60,7 @@ export function format(
const dtf = new Intl.DateTimeFormat(options?.locale, {
timeStyle,
dateStyle,
timeZone: options?.timeZone,
});

return dtf.format(date);
Expand All @@ -68,6 +74,7 @@ export function formatRange(
style: Intl.DateTimeFormatOptions['timeStyle'];
timeStyle: Intl.DateTimeFormatOptions['timeStyle'] | null;
dateStyle: Intl.DateTimeFormatOptions['dateStyle'] | null;
timeZone: Intl.DateTimeFormatOptions['timeZone'];
}>
) {
const timeStyle =
Expand All @@ -83,6 +90,7 @@ export function formatRange(
const dtf = new Intl.DateTimeFormat(options?.locale, {
timeStyle,
dateStyle,
timeZone: options?.timeZone,
});

return dtf.formatRange(startDate, endDate);
Expand Down
Loading