Skip to content
Open
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
15 changes: 15 additions & 0 deletions CHANGELOG.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
{
"name": "@microsoft/globe",
"entries": [
{
"date": "Fri, 06 Mar 2026 10:25:10 GMT",
"version": "4.6.0",
"tag": "@microsoft/globe_v4.6.0",
"comments": {
"minor": [
{
"author": "ligia.e.popescu@gmail.com",
"package": "@microsoft/globe",
"commit": "e9adec04f83b0099883e83f24259f07092805e02",
"comment": "Add omitYear year-removal support"
}
]
}
},
{
"date": "Tue, 02 Dec 2025 18:44:44 GMT",
"version": "4.5.0",
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Change Log - @microsoft/globe

<!-- This log was last generated on Tue, 02 Dec 2025 18:44:44 GMT and should not be manually modified. -->
<!-- This log was last generated on Fri, 06 Mar 2026 10:25:10 GMT and should not be manually modified. -->

<!-- Start content -->

## 4.6.0

Fri, 06 Mar 2026 10:25:10 GMT

### Minor changes

- Add omitYear year-removal support (ligia.e.popescu@gmail.com)

## 4.5.0

Tue, 02 Dec 2025 18:44:44 GMT
Expand Down
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Respects the OS date and time format configuration.
## Usage

```typescript
import { TimeStringFormat, DateTimeFormatOptions, DateTimeFormatter } from 'globe';
import { TimeStringFormat, DateTimeFormatOptions, DateTimeFormatter, DateTimeFormattingBehaviorOptions } from 'globe';

// Instantiate the formatter
const dateTimeFormatter = new DateTimeFormatter(locale: string | ILocaleInfo);
Expand Down Expand Up @@ -39,13 +39,20 @@ To format a date and time value:
* Localize the date/time
* @param date The date/time to localize
* @param format The format to be used for the localization
* @param options Optional formatting options
* @returns The localized date/time string
*/
function formatDateTime(date: number | Date, format: DateTimeFormatOptions) {
return dateTimeFormatter.formatDateTime(date, format);
function formatDateTime(
date: number | Date,
format: DateTimeFormatOptions,
options?: DateTimeFormattingBehaviorOptions
) {
return dateTimeFormatter.formatDateTime(date, format, options);
}
```

Set `options.omitYear` to `true` to remove the year portion while preserving locale-specific date formatting behavior.

**The function throws** in case an unexpected OS date and time format string is
provided! Most likely this will happen if you feed it the OS strings verbatim and
the OS is configured with a custom date/time format string. If you don't desire
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@microsoft/globe",
"version": "4.5.0",
"version": "4.6.0",
"description": "Globalization Service",
"author": "Microsoft",
"license": "MIT",
Expand Down
166 changes: 166 additions & 0 deletions src/date-time-formatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,4 +602,170 @@ describe("date-time-format-options", () => {
expect(result).toBe("6/28/2020 3:40 PM");
});
});

describe("omitYear", () => {
const date = new Date(2026, 2, 6, 15, 40, 25);

const createWindowsLocaleInfo = (
regionalFormat: string,
shortDate: string
): ILocaleInfo => ({
platform: "windows",
regionalFormat,
shortDate,
longDate: shortDate,
shortTime: "h:mm tt",
longTime: "h:mm:ss tt",
});

const formatShortDate = (
localeInfo: ILocaleInfo,
format = SHORT_DATE
) => {
const dateTimeFormatter = new DateTimeFormatter(localeInfo);
return {
withYear: dateTimeFormatter.formatDateTime(date, format),
withoutYear: dateTimeFormatter.formatDateTime(date, format, { omitYear: true }),
};
};

it("omits year for en-US short date", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("en-US", "M/d/yyyy")
);
expect(formatted.withYear).toBe("3/6/2026");
expect(formatted.withoutYear).toBe("3/6");
});

it("omits year for de-DE numeric date while preserving trailing dot", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("de-DE", "d.M.yyyy")
);
expect(formatted.withYear).toBe("6.3.2026");
expect(formatted.withoutYear).toBe("6.3.");
});

it("omits year for de-DE long month date", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("de-DE", "d. MMMM yyyy")
);
expect(formatted.withYear).toBe("6. März 2026");
expect(formatted.withoutYear).toBe("6. März");
});

it("omits year for ja-JP dates with 年 suffix", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("ja-JP", "yyyy年M月d日")
);
expect(formatted.withYear).toBe("2026年3月6日");
expect(formatted.withoutYear).toBe("3月6日");
});

it("omits year for ko-KR dates with 년 suffix", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("ko-KR", "yyyy년 M월 d일")
);
expect(formatted.withYear).toBe("2026년 3월 6일");
expect(formatted.withoutYear).toBe("3월 6일");
});

it("omits year and г. suffix for ru-RU", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("ru-RU", "d MMMM yyyy 'г.'")
);
expect(formatted.withYear).toBe("6 марта 2026 г.");
expect(formatted.withoutYear).toBe("6 марта");
});

it("omits year and р. suffix for uk-UA", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("uk-UA", "d MMMM yyyy 'р.'")
);
expect(formatted.withYear).toBe("6 березня 2026 р.");
expect(formatted.withoutYear).toBe("6 березня");
});

it("omits year and gada token for lv-LV", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("lv-LV", "yyyy. 'gada' d. MMMM")
);
expect(formatted.withYear).toBe("2026. gada 6. marts");
expect(formatted.withoutYear).toBe("6. marts");
});

it("omits year when lt-LT uses 'm' token", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("lt-LT", "M/d/yyyy 'm'")
);
expect(formatted.withYear).toBe("03/06/2026 m");
expect(formatted.withoutYear).toBe("03/6");
});

it("omits year when eu-ES uses ('e')'ko' pattern", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("eu-ES", "yyyy('e')'ko' M/d")
);
expect(formatted.withYear).toBe("2026(e)ko 3/6");
expect(formatted.withoutYear).toBe("3/6");
});

it("omits year for es-ES de-construction", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("es-ES", "d 'de' MMMM 'de' yyyy")
);
expect(formatted.withYear).toBe("6 de marzo de 2026");
expect(formatted.withoutYear).toBe("6 de marzo");
});

it("omits year for fr-CH while preserving trailing dot", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("fr-CH", "d.M.yyyy")
);
expect(formatted.withYear).toBe("06.03.2026");
expect(formatted.withoutYear).toBe("06.03.");
});

it("does not omit year for WITH_YEAR OS formats", () => {
const formatted = formatShortDate(
createWindowsLocaleInfo("en-US", "M/d/yyyy"),
SHORT_DATE_WITH_YEAR
);
expect(formatted.withYear).toBe("3/6/2026");
expect(formatted.withoutYear).toBe("3/6/2026");
});

it("omits year in Intl path and matches no-year format", () => {
const dateTimeFormatter = new DateTimeFormatter("en-US");
const result = dateTimeFormatter.formatDateTime(
date,
SHORT_DATE_WITH_YEAR,
{ omitYear: true }
);
expect(result).toBe(dateTimeFormatter.formatDateTime(date, SHORT_DATE));
});

it("keeps time-only formats unchanged when omitYear is true", () => {
const dateTimeFormatter = new DateTimeFormatter(
createWindowsLocaleInfo("en-US", "M/d/yyyy")
);
const withOmitYear = dateTimeFormatter.formatDateTime(
date,
SHORT_TIME,
{ omitYear: true }
);
const withoutOmitYear = dateTimeFormatter.formatDateTime(date, SHORT_TIME);
expect(withOmitYear).toBe(withoutOmitYear);
});

it("keeps no-year Intl formats unchanged when omitYear is true", () => {
const dateTimeFormatter = new DateTimeFormatter("en-US");
const withOmitYear = dateTimeFormatter.formatDateTime(
date,
SHORT_DATE,
{ omitYear: true }
);
const withoutOmitYear = dateTimeFormatter.formatDateTime(date, SHORT_DATE);
expect(withOmitYear).toBe(withoutOmitYear);
});
});
});
Loading