@prairielearn/formatter 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/date.d.ts +2 -1
- package/dist/date.js +5 -1
- package/dist/date.js.map +1 -1
- package/dist/date.test.js +4 -0
- package/dist/date.test.js.map +1 -1
- package/package.json +6 -6
- package/src/date.test.ts +4 -0
- package/src/date.ts +9 -1
package/CHANGELOG.md
CHANGED
package/dist/date.d.ts
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* @param param2.longTz Whether to use the long time zone name (default false).
|
|
8
8
|
* @returns Human-readable string representing the date.
|
|
9
9
|
*/
|
|
10
|
-
export declare function formatDate(date: Date, timeZone: string, { includeTz, longTz }?: {
|
|
10
|
+
export declare function formatDate(date: Date, timeZone: string, { includeTz, longTz, includeMs, }?: {
|
|
11
11
|
includeTz?: boolean;
|
|
12
12
|
longTz?: boolean;
|
|
13
|
+
includeMs?: boolean;
|
|
13
14
|
}): string;
|
|
14
15
|
/**
|
|
15
16
|
* Format a date to a human-readable string like '2020-03-27'.
|
package/dist/date.js
CHANGED
|
@@ -8,7 +8,7 @@ import keyBy from 'lodash/keyBy.js';
|
|
|
8
8
|
* @param param2.longTz Whether to use the long time zone name (default false).
|
|
9
9
|
* @returns Human-readable string representing the date.
|
|
10
10
|
*/
|
|
11
|
-
export function formatDate(date, timeZone, { includeTz = true, longTz = false } = {}) {
|
|
11
|
+
export function formatDate(date, timeZone, { includeTz = true, longTz = false, includeMs = false, } = {}) {
|
|
12
12
|
const options = {
|
|
13
13
|
timeZone,
|
|
14
14
|
hourCycle: 'h23',
|
|
@@ -18,10 +18,14 @@ export function formatDate(date, timeZone, { includeTz = true, longTz = false }
|
|
|
18
18
|
hour: '2-digit',
|
|
19
19
|
minute: '2-digit',
|
|
20
20
|
second: '2-digit',
|
|
21
|
+
fractionalSecondDigits: includeMs ? 3 : undefined,
|
|
21
22
|
timeZoneName: longTz ? 'long' : 'short',
|
|
22
23
|
};
|
|
23
24
|
const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);
|
|
24
25
|
let dateFormatted = `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;
|
|
26
|
+
if (includeMs) {
|
|
27
|
+
dateFormatted = `${dateFormatted}.${parts.fractionalSecond.value}`;
|
|
28
|
+
}
|
|
25
29
|
if (includeTz) {
|
|
26
30
|
dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;
|
|
27
31
|
}
|
package/dist/date.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date.js","sourceRoot":"","sources":["../src/date.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,IAAU,EACV,QAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"date.js","sourceRoot":"","sources":["../src/date.ts"],"names":[],"mappings":"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","sourcesContent":["import keyBy from 'lodash/keyBy.js';\n\n/**\n * Format a date to a human-readable string like '2020-03-27T12:34:56 (CDT)'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @param param2.includeTz Whether to include the time zone in the output (default true).\n * @param param2.longTz Whether to use the long time zone name (default false).\n * @returns Human-readable string representing the date.\n */\nexport function formatDate(\n date: Date,\n timeZone: string,\n {\n includeTz = true,\n longTz = false,\n includeMs = false,\n }: { includeTz?: boolean; longTz?: boolean; includeMs?: boolean } = {},\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: includeMs ? 3 : undefined,\n timeZoneName: longTz ? 'long' : 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n let dateFormatted = `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;\n if (includeMs) {\n dateFormatted = `${dateFormatted}.${parts.fractionalSecond.value}`;\n }\n if (includeTz) {\n dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;\n }\n return dateFormatted;\n}\n\n/**\n * Format a date to a human-readable string like '2020-03-27'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateYMD(date: Date, timeZone: string): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n return `${parts.year.value}-${parts.month.value}-${parts.day.value}`;\n}\n\n/**\n * Format a date to a human-readable string like '2020-03-27 14:27'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateYMDHM(date: Date, timeZone: string): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n return `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}`;\n}\n"]}
|
package/dist/date.test.js
CHANGED
|
@@ -18,6 +18,10 @@ describe('date formatting', () => {
|
|
|
18
18
|
const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));
|
|
19
19
|
assert.equal(formatDate(date, 'UTC'), '2018-01-01 00:01:00 (UTC)');
|
|
20
20
|
});
|
|
21
|
+
it('formats dates with milliseconds', () => {
|
|
22
|
+
const date = new Date(Date.UTC(2018, 0, 1, 4, 1, 3, 12));
|
|
23
|
+
assert.equal(formatDate(date, 'UTC', { includeMs: true }), '2018-01-01 04:01:03.012 (UTC)');
|
|
24
|
+
});
|
|
21
25
|
it('formats dates without the timezone', () => {
|
|
22
26
|
const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));
|
|
23
27
|
assert.equal(formatDate(date, 'UTC', { includeTz: false }), '2018-01-01 12:00:00');
|
package/dist/date.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date.test.js","sourceRoot":"","sources":["../src/date.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert } from 'chai';\n\nimport { formatDate, formatDateYMD, formatDateYMDHM } from './date.js';\n\ndescribe('date formatting', () => {\n describe('formatDate', () => {\n it('formats a UTC date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'UTC'), '2018-01-01 12:00:00 (UTC)');\n });\n it('formats a CST date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'America/Chicago'), '2018-01-01 06:00:00 (CST)');\n });\n it('formats a CDT date', () => {\n const date = new Date(Date.UTC(2018, 6, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'America/Chicago'), '2018-07-01 07:00:00 (CDT)');\n });\n it('formats dates with zero hours', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));\n assert.equal(formatDate(date, 'UTC'), '2018-01-01 00:01:00 (UTC)');\n });\n it('formats dates without the timezone', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'UTC', { includeTz: false }), '2018-01-01 12:00:00');\n });\n it('formats dates with the long timezone name', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(\n formatDate(date, 'America/Chicago', { longTz: true }),\n '2018-01-01 06:00:00 (Central Standard Time)',\n );\n });\n });\n\n describe('formatDateYMD()', () => {\n it('should handle a UTC date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDateYMD(date, 'UTC'), '2018-01-01');\n });\n it('should handle a CST date', () => {\n const date = new Date(Date.UTC(2018, 0, 3, 5, 0, 0));\n assert.equal(formatDateYMD(date, 'America/Chicago'), '2018-01-02');\n });\n it('should handle a CDT date', () => {\n const date = new Date(Date.UTC(2018, 6, 1, 12, 0, 0));\n assert.equal(formatDateYMD(date, 'America/Chicago'), '2018-07-01');\n });\n it('should correctly format dates with zero hours', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));\n assert.equal(formatDateYMD(date, 'UTC'), '2018-01-01');\n });\n });\n\n describe('formatDateYMDHM()', () => {\n it('should handle a UTC date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 34, 7));\n assert.equal(formatDateYMDHM(date, 'UTC'), '2018-01-01 12:34');\n });\n it('should handle a CST date', () => {\n const date = new Date(Date.UTC(2018, 0, 3, 5, 10, 50));\n assert.equal(formatDateYMDHM(date, 'America/Chicago'), '2018-01-02 23:10');\n });\n it('should handle a CDT date', () => {\n const date = new Date(Date.UTC(2018, 6, 1, 19, 8, 19));\n assert.equal(formatDateYMDHM(date, 'America/Chicago'), '2018-07-01 14:08');\n });\n it('should correctly format dates with zero hours', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));\n assert.equal(formatDateYMDHM(date, 'UTC'), '2018-01-01 00:01');\n });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"date.test.js","sourceRoot":"","sources":["../src/date.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert } from 'chai';\n\nimport { formatDate, formatDateYMD, formatDateYMDHM } from './date.js';\n\ndescribe('date formatting', () => {\n describe('formatDate', () => {\n it('formats a UTC date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'UTC'), '2018-01-01 12:00:00 (UTC)');\n });\n it('formats a CST date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'America/Chicago'), '2018-01-01 06:00:00 (CST)');\n });\n it('formats a CDT date', () => {\n const date = new Date(Date.UTC(2018, 6, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'America/Chicago'), '2018-07-01 07:00:00 (CDT)');\n });\n it('formats dates with zero hours', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));\n assert.equal(formatDate(date, 'UTC'), '2018-01-01 00:01:00 (UTC)');\n });\n it('formats dates with milliseconds', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 4, 1, 3, 12));\n assert.equal(formatDate(date, 'UTC', { includeMs: true }), '2018-01-01 04:01:03.012 (UTC)');\n });\n it('formats dates without the timezone', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDate(date, 'UTC', { includeTz: false }), '2018-01-01 12:00:00');\n });\n it('formats dates with the long timezone name', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(\n formatDate(date, 'America/Chicago', { longTz: true }),\n '2018-01-01 06:00:00 (Central Standard Time)',\n );\n });\n });\n\n describe('formatDateYMD()', () => {\n it('should handle a UTC date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));\n assert.equal(formatDateYMD(date, 'UTC'), '2018-01-01');\n });\n it('should handle a CST date', () => {\n const date = new Date(Date.UTC(2018, 0, 3, 5, 0, 0));\n assert.equal(formatDateYMD(date, 'America/Chicago'), '2018-01-02');\n });\n it('should handle a CDT date', () => {\n const date = new Date(Date.UTC(2018, 6, 1, 12, 0, 0));\n assert.equal(formatDateYMD(date, 'America/Chicago'), '2018-07-01');\n });\n it('should correctly format dates with zero hours', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));\n assert.equal(formatDateYMD(date, 'UTC'), '2018-01-01');\n });\n });\n\n describe('formatDateYMDHM()', () => {\n it('should handle a UTC date', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 12, 34, 7));\n assert.equal(formatDateYMDHM(date, 'UTC'), '2018-01-01 12:34');\n });\n it('should handle a CST date', () => {\n const date = new Date(Date.UTC(2018, 0, 3, 5, 10, 50));\n assert.equal(formatDateYMDHM(date, 'America/Chicago'), '2018-01-02 23:10');\n });\n it('should handle a CDT date', () => {\n const date = new Date(Date.UTC(2018, 6, 1, 19, 8, 19));\n assert.equal(formatDateYMDHM(date, 'America/Chicago'), '2018-07-01 14:08');\n });\n it('should correctly format dates with zero hours', () => {\n const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));\n assert.equal(formatDateYMDHM(date, 'UTC'), '2018-01-01 00:01');\n });\n });\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/formatter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@prairielearn/tsconfig": "^0.0.0",
|
|
21
|
-
"@types/node": "^20.
|
|
22
|
-
"c8": "^
|
|
21
|
+
"@types/node": "^20.14.9",
|
|
22
|
+
"c8": "^10.1.2",
|
|
23
23
|
"chai": "^5.1.1",
|
|
24
|
-
"mocha": "^10.
|
|
25
|
-
"tsx": "^4.
|
|
26
|
-
"typescript": "^5.
|
|
24
|
+
"mocha": "^10.6.0",
|
|
25
|
+
"tsx": "^4.16.2",
|
|
26
|
+
"typescript": "^5.5.3"
|
|
27
27
|
},
|
|
28
28
|
"c8": {
|
|
29
29
|
"reporter": [
|
package/src/date.test.ts
CHANGED
|
@@ -20,6 +20,10 @@ describe('date formatting', () => {
|
|
|
20
20
|
const date = new Date(Date.UTC(2018, 0, 1, 0, 1, 0));
|
|
21
21
|
assert.equal(formatDate(date, 'UTC'), '2018-01-01 00:01:00 (UTC)');
|
|
22
22
|
});
|
|
23
|
+
it('formats dates with milliseconds', () => {
|
|
24
|
+
const date = new Date(Date.UTC(2018, 0, 1, 4, 1, 3, 12));
|
|
25
|
+
assert.equal(formatDate(date, 'UTC', { includeMs: true }), '2018-01-01 04:01:03.012 (UTC)');
|
|
26
|
+
});
|
|
23
27
|
it('formats dates without the timezone', () => {
|
|
24
28
|
const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));
|
|
25
29
|
assert.equal(formatDate(date, 'UTC', { includeTz: false }), '2018-01-01 12:00:00');
|
package/src/date.ts
CHANGED
|
@@ -12,7 +12,11 @@ import keyBy from 'lodash/keyBy.js';
|
|
|
12
12
|
export function formatDate(
|
|
13
13
|
date: Date,
|
|
14
14
|
timeZone: string,
|
|
15
|
-
{
|
|
15
|
+
{
|
|
16
|
+
includeTz = true,
|
|
17
|
+
longTz = false,
|
|
18
|
+
includeMs = false,
|
|
19
|
+
}: { includeTz?: boolean; longTz?: boolean; includeMs?: boolean } = {},
|
|
16
20
|
): string {
|
|
17
21
|
const options: Intl.DateTimeFormatOptions = {
|
|
18
22
|
timeZone,
|
|
@@ -23,10 +27,14 @@ export function formatDate(
|
|
|
23
27
|
hour: '2-digit',
|
|
24
28
|
minute: '2-digit',
|
|
25
29
|
second: '2-digit',
|
|
30
|
+
fractionalSecondDigits: includeMs ? 3 : undefined,
|
|
26
31
|
timeZoneName: longTz ? 'long' : 'short',
|
|
27
32
|
};
|
|
28
33
|
const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);
|
|
29
34
|
let dateFormatted = `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;
|
|
35
|
+
if (includeMs) {
|
|
36
|
+
dateFormatted = `${dateFormatted}.${parts.fractionalSecond.value}`;
|
|
37
|
+
}
|
|
30
38
|
if (includeTz) {
|
|
31
39
|
dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;
|
|
32
40
|
}
|