Skip to content

fix(common): include minutes in the short GMT timezone format#69239

Closed
erkamyaman wants to merge 1 commit into
angular:mainfrom
erkamyaman:fix-common-short-gmt-minutes
Closed

fix(common): include minutes in the short GMT timezone format#69239
erkamyaman wants to merge 1 commit into
angular:mainfrom
erkamyaman:fix-common-short-gmt-minutes

Conversation

@erkamyaman
Copy link
Copy Markdown
Contributor

The short localized GMT format (z, zz, zzz, O) returned the hours only, so in zones with a non-zero minute offset it dropped them, for example GMT+5 in India instead of GMT+5:30. Per CLDR (UTS #35), the short localized GMT format omits the leading zero on the hours but still includes the minutes when they are non-zero; this also affects the named long and longTime formats, which use z. The format now appends the minutes when they are non-zero, leaving whole-hour zones (such as GMT-4) unchanged.

While in the same timezone-format area, this also corrects the DatePipe JSDoc format table, where the ZZZZ ("Long localized GMT format") example showed GMT-8:00 instead of the zero-padded GMT-08:00 that the format actually produces (and that the OOOO row already shows).

PR Checklist

Please check that your PR fulfills the following requirements:

  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other

What is the current behavior?

formatDate / DatePipe renders the short localized GMT timezone format (z, zz, zzz, O, and the named long / longTime formats that use z) with the hours only. In a timezone whose offset has non-zero minutes, the minutes are dropped:

  • India +5:30 renders GMT+5 (should be GMT+5:30)
  • Nepal +5:45 renders GMT+5 (should be GMT+5:45)

This diverges from CLDR / Intl, whose short localized GMT format keeps non-zero minutes (Intl.DateTimeFormat('en', {timeZoneName: 'shortOffset', timeZone: 'Asia/Kolkata'})GMT+5:30).

What is the new behavior?

The short GMT format appends the minutes when they are non-zero:

  • India +5:30GMT+5:30
  • Nepal +5:45GMT+5:45
  • Newfoundland -3:30GMT-3:30
  • Whole-hour zones unchanged (GMT-4, GMT-5)

The PR also fixes a small typo in the DatePipe JSDoc format table (ZZZZ example GMT-8:00GMT-08:00) in the same timezone-format area.

Does this PR introduce a breaking change?

  • Yes
  • No

The short localized GMT format (`z`, `zz`, `zzz`, `O`) returned the hours only, so in zones with a non-zero minute offset it dropped them, for example `GMT+5` in India instead of `GMT+5:30`. Per CLDR (UTS angular#35), the short localized GMT format omits the leading zero on the hours but still includes the minutes when they are non-zero; this also affects the named `long` and `longTime` formats, which use `z`. The format now appends the minutes when they are non-zero, leaving whole-hour zones (such as `GMT-4`) unchanged.

While in the same timezone-format area, this also corrects the `DatePipe` JSDoc format table, where the `ZZZZ` ("Long localized GMT format") example showed `GMT-8:00` instead of the zero-padded `GMT-08:00` that the format actually produces (and that the `OOOO` row already shows).
@pullapprove pullapprove Bot requested a review from atscott June 8, 2026 18:43
@angular-robot angular-robot Bot added the area: common Issues related to APIs in the @angular/common package label Jun 8, 2026
@ngbot ngbot Bot added this to the Backlog milestone Jun 8, 2026
Comment on lines +476 to +487
case ZoneWidth.ShortGMT: {
// The short localized GMT format omits a leading zero on the hours but,
// per CLDR, still includes the minutes when they are non-zero (e.g.
// `GMT+5:30` for India, `GMT-4` for New York).
const minutes = Math.abs(zone % 60);
return (
'GMT' +
(zone >= 0 ? '+' : '') +
padNumber(hours, 1, minusSign) +
(minutes ? ':' + padNumber(minutes, 2, minusSign) : '')
);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is that true for every locale ? (the CLDR is a funny rabbithole)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good question, it is a bit of a rabbit hole indeed. No, the full format isn't identical across locales. I checked Intl short offsets for a +5:30 zone:

  • most locales (en, de, ja, hi, tr, …): GMT+5:30
  • fr: UTC+5:30 (UTC, not GMT)
  • fi: UTC+5.30 (UTC and a . separator)
  • ar: غرينتش+5:30 (translated label)
  • fa: ‎+۵:۳۰ گرینویچ (Persian digits, label after the offset, RTL)

So the literal, separator, digits and order are all locale-dependent. What is universal is that the minutes are kept when they're non-zero, and that's the only thing this change touches.

timeZoneGetter already renders a locale-independent GMT±H[:mm] for every locale (same as the Long/Extended widths), so this doesn't add locale divergence, it just stops the short form dropping the minutes the long form already keeps.

I can reword the code comment to call that out if you think it's worth it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My point is more : This is not worth fixing and users should rely on Intl if they want top-tier date i18n.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It makes sense, agreed that Intl is the right call for proper date i18n. I'll close this out. Thanks for the look, I appreciate it.

@erkamyaman erkamyaman closed this Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: common Issues related to APIs in the @angular/common package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants