Skip to content

Commit

Permalink
Substitute timezone name for fixed offset timezones
Browse files Browse the repository at this point in the history
  • Loading branch information
thatsmydoing committed Feb 9, 2023
1 parent e781052 commit 03f2391
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 16 deletions.
56 changes: 41 additions & 15 deletions src/impl/locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,13 @@ class PolyNumberFormatter {
class PolyDateFormatter {
constructor(dt, intl, opts) {
this.opts = opts;
this.originalZone = undefined;

let z = undefined;
if (dt.zone.isUniversal) {
if (this.opts.timeZone) {
// Don't apply any workarounds if a timeZone is explicitly provided in opts
this.dt = dt;
} else if (dt.zone.isUniversal) {
// UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like.
// That is why fixed-offset TZ is set to that unless it is:
// 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT.
Expand All @@ -212,25 +216,23 @@ class PolyDateFormatter {
z = offsetZ;
this.dt = dt;
} else {
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata.
// So we have to make do. Two cases:
// 1. The format options tell us to show the zone. We can't do that, so the best
// we can do is format the date in UTC.
// 2. The format options don't tell us to show the zone. Then we can adjust them
// the time and tell the formatter to show it to us in UTC, so that the time is right
// and the bad zone doesn't show up.
// Not all fixed-offset zones like Etc/+4:30 are present in tzdata so
// we manually apply the offset and substitute the zone as needed.
z = "UTC";
if (opts.timeZoneName) {
this.dt = dt;
} else {
this.dt = dt.offset === 0 ? dt : DateTime.fromMillis(dt.ts + dt.offset * 60 * 1000);
}
this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
this.originalZone = dt.zone;
}
} else if (dt.zone.type === "system") {
this.dt = dt;
} else {
} else if (dt.zone.type === "iana") {
this.dt = dt;
z = dt.zone.name;
} else {
// Custom zones can have any offset / offsetName so we just manually
// apply the offset and substitute the offsetName as needed.
z = "UTC";
this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset });
this.originalZone = dt.zone;
}

const intlOpts = { ...this.opts };
Expand All @@ -239,11 +241,35 @@ class PolyDateFormatter {
}

format() {
if (this.originalZone) {
// If we have to substitute in the actual zone name, we have to use
// formatToParts so that the timezone can be replaced.
return this.formatToParts()
.map(({ value }) => value)
.join("");
}
return this.dtf.format(this.dt.toJSDate());
}

formatToParts() {
return this.dtf.formatToParts(this.dt.toJSDate());
const parts = this.dtf.formatToParts(this.dt.toJSDate());
if (this.originalZone) {
return parts.map((part) => {
if (part.type === "timeZoneName") {
const offsetName = this.originalZone.offsetName(this.dt.ts, {
locale: this.dt.locale,
format: this.opts.timeZoneName,
});
return {
...part,
value: offsetName,
};
} else {
return part;
}
});
}
return parts;
}

resolvedOptions() {
Expand Down
8 changes: 7 additions & 1 deletion test/datetime/format.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,13 @@ test("DateTime#toLocaleString() shows things with UTC if fixed-offset zone with

test("DateTime#toLocaleString() does the best it can with unsupported fixed-offset zone when showing the zone", () => {
expect(dt.setZone("UTC+4:30").toLocaleString(DateTime.DATETIME_FULL)).toBe(
"May 25, 1982 at 9:23 AM UTC"
"May 25, 1982 at 1:53 PM UTC+4:30"
);
});

test("DateTime#toLocaleString() does the best it can with unsupported fixed-offset zone with timeStyle full", () => {
expect(dt.setZone("UTC+4:30").toLocaleString({ timeStyle: "full" })).toBe(
"1:53:54 PM UTC+4:30"
);
});

Expand Down

0 comments on commit 03f2391

Please sign in to comment.