summaryrefslogtreecommitdiff
path: root/std/datetime/formatter.ts
diff options
context:
space:
mode:
authorTim Reichen <timreichen@users.noreply.github.com>2020-09-25 00:06:22 +0200
committerGitHub <noreply@github.com>2020-09-24 18:06:22 -0400
commit9c75e4876f68b36cb8a79bfe5a734d2783c527ce (patch)
tree849f775356d72b0578fce4ed09a5ac5017220e78 /std/datetime/formatter.ts
parent82db91372f597a0de834937dbb5edabeb68b0138 (diff)
fix(std/datetime):: 12 and 24 support (#7661)
Diffstat (limited to 'std/datetime/formatter.ts')
-rw-r--r--std/datetime/formatter.ts67
1 files changed, 51 insertions, 16 deletions
diff --git a/std/datetime/formatter.ts b/std/datetime/formatter.ts
index 14fb552cd..6f11090f0 100644
--- a/std/datetime/formatter.ts
+++ b/std/datetime/formatter.ts
@@ -5,6 +5,7 @@ import {
TestFunction,
TestResult,
Tokenizer,
+ ReceiverResult,
} from "./tokenizer.ts";
function digits(value: string | number, count = 2): string {
@@ -52,7 +53,7 @@ function createMatchTestFunction(match: RegExp): TestFunction {
};
}
-// according to unicode symbols (http://userguide.icu-project.org/formatparse/datetime)
+// according to unicode symbols (http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
const defaultRules = [
{
test: createLiteralTestFunction("yyyy"),
@@ -81,14 +82,30 @@ const defaultRules = [
},
{
- test: createLiteralTestFunction("hh"),
+ test: createLiteralTestFunction("HH"),
fn: (): CallbackResult => ({ type: "hour", value: "2-digit" }),
},
{
- test: createLiteralTestFunction("h"),
+ test: createLiteralTestFunction("H"),
fn: (): CallbackResult => ({ type: "hour", value: "numeric" }),
},
{
+ test: createLiteralTestFunction("hh"),
+ fn: (): CallbackResult => ({
+ type: "hour",
+ value: "2-digit",
+ hour12: true,
+ }),
+ },
+ {
+ test: createLiteralTestFunction("h"),
+ fn: (): CallbackResult => ({
+ type: "hour",
+ value: "numeric",
+ hour12: true,
+ }),
+ },
+ {
test: createLiteralTestFunction("mm"),
fn: (): CallbackResult => ({ type: "minute", value: "2-digit" }),
},
@@ -143,7 +160,11 @@ const defaultRules = [
},
];
-type FormatPart = { type: DateTimeFormatPartTypes; value: string | number };
+type FormatPart = {
+ type: DateTimeFormatPartTypes;
+ value: string | number;
+ hour12?: boolean;
+};
type Format = FormatPart[];
export class DateTimeFormatter {
@@ -151,19 +172,23 @@ export class DateTimeFormatter {
constructor(formatString: string, rules: Rule[] = defaultRules) {
const tokenizer = new Tokenizer(rules);
- this.#format = tokenizer.tokenize(formatString, ({ type, value }) => ({
- type,
- value,
- })) as Format;
+ this.#format = tokenizer.tokenize(
+ formatString,
+ ({ type, value, hour12 }) => {
+ const result = {
+ type,
+ value,
+ } as unknown as ReceiverResult;
+ if (hour12) result.hour12 = hour12 as boolean;
+ return result;
+ },
+ ) as Format;
}
format(date: Date, options: Options = {}): string {
let string = "";
const utc = options.timeZone === "UTC";
- const hour12 = this.#format.find(
- (token: FormatPart) => token.type === "dayPeriod",
- );
for (const token of this.#format) {
const type = token.type;
@@ -225,7 +250,7 @@ export class DateTimeFormatter {
}
case "hour": {
let value = utc ? date.getUTCHours() : date.getHours();
- value -= hour12 && date.getHours() > 12 ? 12 : 0;
+ value -= token.hour12 && date.getHours() > 12 ? 12 : 0;
switch (token.value) {
case "numeric": {
string += value;
@@ -290,7 +315,7 @@ export class DateTimeFormatter {
// break
}
case "dayPeriod": {
- string += hour12 ? (date.getHours() >= 12 ? "PM" : "AM") : "";
+ string += token.value ? (date.getHours() >= 12 ? "PM" : "AM") : "";
break;
}
case "literal": {
@@ -377,10 +402,20 @@ export class DateTimeFormatter {
switch (token.value) {
case "numeric": {
value = /^\d{1,2}/.exec(string)?.[0] as string;
+ if (token.hour12 && parseInt(value) > 12) {
+ console.error(
+ `Trying to parse hour greater than 12. Use 'H' instead of 'h'.`,
+ );
+ }
break;
}
case "2-digit": {
value = /^\d{2}/.exec(string)?.[0] as string;
+ if (token.hour12 && parseInt(value) > 12) {
+ console.error(
+ `Trying to parse hour greater than 12. Use 'HH' instead of 'hh'.`,
+ );
+ }
break;
}
default:
@@ -425,9 +460,8 @@ export class DateTimeFormatter {
break;
}
case "fractionalSecond": {
- value = new RegExp(`^\\d{${token.value}}`).exec(
- string,
- )?.[0] as string;
+ value = new RegExp(`^\\d{${token.value}}`).exec(string)
+ ?.[0] as string;
break;
}
case "timeZoneName": {
@@ -463,6 +497,7 @@ export class DateTimeFormatter {
);
}
parts.push({ type, value });
+
string = string.slice(value.length);
}