@prairielearn/formatter 1.3.14 → 1.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"interval.test.js","sourceRoot":"","sources":["../src/interval.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,mBAAmB,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,CAAC,KAAK,CACV,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAC1D,uBAAuB,CACxB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { assert, describe, it } from 'vitest';\n\nimport { formatInterval } from './interval.js';\n\ndescribe('interval formatting', () => {\n describe('formatInterval()', () => {\n it('should handle seconds', () => {\n assert.equal(formatInterval(7000), '7 s');\n });\n it('should handle fractional seconds', () => {\n assert.equal(formatInterval(7321), '7 s');\n });\n it('should handle minutes', () => {\n assert.equal(formatInterval(2 * 60 * 1000), '2 min');\n });\n it('should handle hours', () => {\n assert.equal(formatInterval(3 * 60 * 60 * 1000), '3 h');\n });\n it('should handle hours', () => {\n assert.equal(formatInterval(4 * 24 * 60 * 60 * 1000), '4 d');\n });\n it('should handle complex intervals', () => {\n assert.equal(formatInterval((((4 * 24 + 3) * 60 + 2) * 60 + 7) * 1000), '4 d 3 h 2 min 7 s');\n });\n it('should handle zero', () => {\n assert.equal(formatInterval(0), '0 s');\n });\n it('should handle negative intervals', () => {\n assert.equal(\n formatInterval(-(((4 * 24 + 3) * 60 + 2) * 60 + 7) * 1000),\n '-4 d -3 h -2 min -7 s',\n );\n });\n });\n});\n"]}
1
+ {"version":3,"file":"interval.test.js","sourceRoot":"","sources":["../src/interval.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert, describe, it } from 'vitest';\n\nimport {\n formatInterval,\n formatIntervalHM,\n formatIntervalMinutes,\n formatIntervalRelative,\n makeInterval,\n} from './interval.js';\n\ndescribe('interval formatting', () => {\n describe('formatInterval()', () => {\n it('should handle seconds', () => {\n assert.equal(formatInterval(7000), '7 s');\n });\n it('should handle fractional seconds', () => {\n assert.equal(formatInterval(7321), '7 s');\n });\n it('should handle minutes', () => {\n assert.equal(formatInterval(2 * 60 * 1000), '2 min');\n });\n it('should handle hours', () => {\n assert.equal(formatInterval(3 * 60 * 60 * 1000), '3 h');\n });\n it('should handle hours', () => {\n assert.equal(formatInterval(4 * 24 * 60 * 60 * 1000), '4 d');\n });\n it('should handle complex intervals', () => {\n assert.equal(formatInterval((((4 * 24 + 3) * 60 + 2) * 60 + 7) * 1000), '4 d 3 h 2 min 7 s');\n });\n it('should handle zero', () => {\n assert.equal(formatInterval(0), '0 s');\n });\n it('should handle negative intervals', () => {\n assert.equal(\n formatInterval(-(((4 * 24 + 3) * 60 + 2) * 60 + 7) * 1000),\n '-4 d -3 h -2 min -7 s',\n );\n });\n });\n describe('formatIntervalRelative()', () => {\n it('should handle positive intervals', () => {\n assert.equal(\n formatIntervalRelative(3 * 1000, 'Until', 'the start time'),\n 'Until 3 s after the start time',\n );\n });\n it('should handle negative intervals', () => {\n assert.equal(\n formatIntervalRelative(-7 * 60 * 1000, 'From', 'the start time'),\n 'From 7 min before the start time',\n );\n });\n it('should handle zero intervals', () => {\n assert.equal(formatIntervalRelative(0, 'From', 'the start time'), 'From the start time');\n });\n });\n\n describe('formatIntervalMinutes()', () => {\n it('should correctly round up', () => {\n assert.equal(formatIntervalMinutes(3.2 * 60 * 1000), '4 minutes');\n });\n it('should correctly handle 1 minute', () => {\n assert.equal(formatIntervalMinutes(17 * 1000), '1 minute');\n });\n it('should correctly handle zero', () => {\n assert.equal(formatIntervalMinutes(0), '0 minutes');\n });\n it('should correctly handle -1 minute', () => {\n assert.equal(formatIntervalMinutes(-17 * 1000), '-1 minute');\n });\n it('should correctly handle negative intervals', () => {\n assert.equal(formatIntervalMinutes(-3.2 * 60 * 1000), '-4 minutes');\n });\n });\n\n describe('formatIntervalHM()', () => {\n it('should correctly handle postive minutes', () => {\n assert.equal(formatIntervalHM(3.2 * 60 * 1000), '00:03');\n });\n it('should correctly handle postive hours', () => {\n assert.equal(formatIntervalHM((4 * 60 + 17.8) * 60 * 1000), '04:17');\n });\n it('should correctly handle large postive hours', () => {\n assert.equal(formatIntervalHM((143 * 60 + 17.8) * 60 * 1000), '143:17');\n });\n it('should correctly handle an explicit sign', () => {\n assert.equal(formatIntervalHM((4 * 60 + 17.8) * 60 * 1000, { signed: true }), '+04:17');\n });\n it('should correctly handle negative minutes', () => {\n assert.equal(formatIntervalHM(-3.2 * 60 * 1000), '-00:03');\n });\n it('should correctly handle negative hours', () => {\n assert.equal(formatIntervalHM(-(4 * 60 + 17.8) * 60 * 1000), '-04:17');\n });\n });\n\n describe('makeInterval()', () => {\n it('should handle seconds', () => {\n assert.equal(makeInterval({ seconds: 7 }), 7 * 1000);\n });\n it('should handle minutes', () => {\n assert.equal(makeInterval({ minutes: 2 }), 2 * 60 * 1000);\n });\n it('should handle hours', () => {\n assert.equal(makeInterval({ hours: 3 }), 3 * 60 * 60 * 1000);\n });\n it('should handle days', () => {\n assert.equal(makeInterval({ days: 4 }), 4 * 24 * 60 * 60 * 1000);\n });\n it('should default to zero', () => {\n assert.equal(makeInterval({}), 0);\n });\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/formatter",
3
- "version": "1.3.14",
3
+ "version": "1.4.1",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,14 +14,15 @@
14
14
  "test": "vitest run --coverage"
15
15
  },
16
16
  "dependencies": {
17
+ "@js-temporal/polyfill": "^0.5.1",
17
18
  "lodash": "^4.17.21"
18
19
  },
19
20
  "devDependencies": {
20
21
  "@prairielearn/tsconfig": "^0.0.0",
21
- "@types/node": "^22.15.29",
22
- "@vitest/coverage-v8": "^3.2.2",
23
- "tsx": "^4.19.4",
22
+ "@types/node": "^22.15.34",
23
+ "@vitest/coverage-v8": "^3.2.4",
24
+ "tsx": "^4.20.3",
24
25
  "typescript": "^5.8.3",
25
- "vitest": "^3.2.2"
26
+ "vitest": "^3.2.4"
26
27
  }
27
28
  }
package/src/date.test.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import { assert, describe, it } from 'vitest';
2
2
 
3
- import { formatDate, formatDateYMD, formatDateYMDHM } from './date.js';
3
+ import {
4
+ formatDate,
5
+ formatDateFriendly,
6
+ formatDateRangeFriendly,
7
+ formatDateWithinRange,
8
+ formatDateYMD,
9
+ formatDateYMDHM,
10
+ } from './date.js';
4
11
 
5
12
  describe('date formatting', () => {
6
13
  describe('formatDate', () => {
@@ -74,4 +81,345 @@ describe('date formatting', () => {
74
81
  assert.equal(formatDateYMDHM(date, 'UTC'), '2018-01-01 00:01');
75
82
  });
76
83
  });
84
+
85
+ describe('formatDateWithinRange()', () => {
86
+ it('should handle a date within the same day in UTC', () => {
87
+ const date = new Date(Date.UTC(2018, 0, 1, 12, 34, 7));
88
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));
89
+ const end = new Date(Date.UTC(2018, 0, 1, 12, 59, 59));
90
+ assert.equal(formatDateWithinRange(date, start, end, 'UTC'), '12:34');
91
+ });
92
+ it('should handle a date within the same day in CST', () => {
93
+ const date = new Date(Date.UTC(2018, 0, 1, 23, 8, 57));
94
+ const start = new Date(Date.UTC(2018, 0, 1, 21, 0, 0));
95
+ const end = new Date(Date.UTC(2018, 0, 2, 2, 14, 0));
96
+ assert.equal(formatDateWithinRange(date, start, end, 'America/Chicago'), '17:08');
97
+ });
98
+ it('should handle a date within the same year in UTC', () => {
99
+ const date = new Date(Date.UTC(2018, 0, 1, 12, 34, 7));
100
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));
101
+ const end = new Date(Date.UTC(2018, 0, 4, 12, 59, 59));
102
+ assert.equal(formatDateWithinRange(date, start, end, 'UTC'), 'Jan 1, 12:34');
103
+ });
104
+ it('should handle a date within different years in UTC', () => {
105
+ const date = new Date(Date.UTC(2018, 0, 1, 12, 34, 7));
106
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));
107
+ const end = new Date(Date.UTC(2019, 0, 1, 12, 59, 59));
108
+ assert.equal(formatDateWithinRange(date, start, end, 'UTC'), '2018-01-01 12:34');
109
+ });
110
+ });
111
+
112
+ describe('formatDateFriendly()', () => {
113
+ it('should handle a date on the same day at the same time', () => {
114
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
115
+ const date = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
116
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 12:34pm (UTC)');
117
+ });
118
+
119
+ it('should handle a date on the same day at a later time', () => {
120
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
121
+ const date = new Date(Date.UTC(2018, 0, 1, 16, 34, 0));
122
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 4:34pm (UTC)');
123
+ });
124
+
125
+ it('should handle a date on the same day at an earlier time', () => {
126
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
127
+ const date = new Date(Date.UTC(2018, 0, 1, 9, 34, 0));
128
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 9:34am (UTC)');
129
+ });
130
+
131
+ it('should handle a date on the next day at the same time', () => {
132
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
133
+ const date = new Date(Date.UTC(2018, 0, 2, 12, 34, 0));
134
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'tomorrow, 12:34pm (UTC)');
135
+ });
136
+
137
+ it('should handle a date on the next day at a later time', () => {
138
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
139
+ const date = new Date(Date.UTC(2018, 0, 2, 16, 34, 0));
140
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'tomorrow, 4:34pm (UTC)');
141
+ });
142
+
143
+ it('should handle a date on the next day at an earlier time', () => {
144
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
145
+ const date = new Date(Date.UTC(2018, 0, 2, 9, 34, 0));
146
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'tomorrow, 9:34am (UTC)');
147
+ });
148
+
149
+ it('should handle a date on the previous day at the same time', () => {
150
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
151
+ const date = new Date(Date.UTC(2017, 11, 31, 12, 34, 0));
152
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'yesterday, 12:34pm (UTC)');
153
+ });
154
+
155
+ it('should handle a date on the previous day at a later time', () => {
156
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
157
+ const date = new Date(Date.UTC(2017, 11, 31, 16, 34, 0));
158
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'yesterday, 4:34pm (UTC)');
159
+ });
160
+
161
+ it('should handle a date on the previous day at an earlier time', () => {
162
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
163
+ const date = new Date(Date.UTC(2017, 11, 31, 9, 34, 0));
164
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'yesterday, 9:34am (UTC)');
165
+ });
166
+
167
+ it('should handle a date in the near future', () => {
168
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
169
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
170
+ assert.equal(
171
+ formatDateFriendly(date, 'UTC', { baseDate }),
172
+ 'Sun, Apr\u00a015, 12:34am (UTC)',
173
+ );
174
+ });
175
+
176
+ it('should handle a date in the far future', () => {
177
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
178
+ const date = new Date(Date.UTC(2018, 9, 15, 0, 34, 0));
179
+ assert.equal(
180
+ formatDateFriendly(date, 'UTC', { baseDate }),
181
+ 'Mon, Oct\u00a015, 2018, 12:34am (UTC)',
182
+ );
183
+ });
184
+
185
+ it('should handle a date in the near past', () => {
186
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
187
+ const date = new Date(Date.UTC(2017, 9, 15, 0, 34, 0));
188
+ assert.equal(
189
+ formatDateFriendly(date, 'UTC', { baseDate }),
190
+ 'Sun, Oct\u00a015, 12:34am (UTC)',
191
+ );
192
+ });
193
+
194
+ it('should handle a date in the far past', () => {
195
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
196
+ const date = new Date(Date.UTC(2017, 3, 15, 0, 34, 0));
197
+ assert.equal(
198
+ formatDateFriendly(date, 'UTC', { baseDate }),
199
+ 'Sat, Apr\u00a015, 2017, 12:34am (UTC)',
200
+ );
201
+ });
202
+
203
+ it('should display without the timezone', () => {
204
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
205
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
206
+ assert.equal(
207
+ formatDateFriendly(date, 'UTC', { baseDate, includeTz: false }),
208
+ 'Sun, Apr\u00a015, 12:34am',
209
+ );
210
+ });
211
+
212
+ it('should handle a date in CDT', () => {
213
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
214
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
215
+ assert.equal(
216
+ formatDateFriendly(date, 'America/Chicago', { baseDate }),
217
+ 'Sat, Apr\u00a014, 7:34pm (CDT)',
218
+ );
219
+ });
220
+
221
+ it('should handle a date in CDT without the timezone', () => {
222
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
223
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
224
+ assert.equal(
225
+ formatDateFriendly(date, 'America/Chicago', { baseDate, includeTz: false }),
226
+ 'Sat, Apr\u00a014, 7:34pm',
227
+ );
228
+ });
229
+
230
+ it('should handle displaying only the date', () => {
231
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
232
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
233
+ assert.equal(
234
+ formatDateFriendly(date, 'UTC', { baseDate, dateOnly: true }),
235
+ 'Sun, Apr\u00a015 (UTC)',
236
+ );
237
+ });
238
+
239
+ it('should handle displaying only the date without the timezone', () => {
240
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
241
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
242
+ assert.equal(
243
+ formatDateFriendly(date, 'UTC', { baseDate, dateOnly: true, includeTz: false }),
244
+ 'Sun, Apr\u00a015',
245
+ );
246
+ });
247
+
248
+ it('should handle displaying only the time', () => {
249
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
250
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
251
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate, timeOnly: true }), '12:34am (UTC)');
252
+ });
253
+
254
+ it('should handle displaying only the time without the timezone', () => {
255
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
256
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
257
+ assert.equal(
258
+ formatDateFriendly(date, 'UTC', { baseDate, timeOnly: true, includeTz: false }),
259
+ '12:34am',
260
+ );
261
+ });
262
+
263
+ it('should handle displaying dates with the time first', () => {
264
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
265
+ const date = new Date(Date.UTC(2018, 3, 15, 0, 34, 0));
266
+ assert.equal(
267
+ formatDateFriendly(date, 'UTC', { baseDate, timeFirst: true }),
268
+ '12:34am Sun, Apr\u00a015 (UTC)',
269
+ );
270
+ });
271
+
272
+ it('should handle a time with seconds', () => {
273
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 2));
274
+ const date = new Date(Date.UTC(2018, 0, 1, 13, 34, 7));
275
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 1:34:07pm (UTC)');
276
+ });
277
+
278
+ it('should handle a time with minutes', () => {
279
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 2));
280
+ const date = new Date(Date.UTC(2018, 0, 1, 13, 34, 0));
281
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 1:34pm (UTC)');
282
+ });
283
+
284
+ it('should handle a time with hours', () => {
285
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 2));
286
+ const date = new Date(Date.UTC(2018, 0, 1, 13, 0, 0));
287
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 1pm (UTC)');
288
+ });
289
+
290
+ it('should handle midnight', () => {
291
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 2));
292
+ const date = new Date(Date.UTC(2018, 0, 1, 0, 0, 0));
293
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 12am (UTC)');
294
+ });
295
+
296
+ it('should handle noon', () => {
297
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 2));
298
+ const date = new Date(Date.UTC(2018, 0, 1, 12, 0, 0));
299
+ assert.equal(formatDateFriendly(date, 'UTC', { baseDate }), 'today, 12pm (UTC)');
300
+ });
301
+ });
302
+
303
+ describe('formatDateRangeFriendly()', () => {
304
+ it('should handle two different dates', () => {
305
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
306
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
307
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
308
+ assert.equal(
309
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate }),
310
+ 'today, 12:34pm to Wed, Jan\u00a03, 10am (UTC)',
311
+ );
312
+ });
313
+
314
+ it('should handle the same date with different times', () => {
315
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
316
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
317
+ const end = new Date(Date.UTC(2018, 0, 1, 13, 0, 0));
318
+ assert.equal(
319
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate }),
320
+ 'today, 12:34pm to 1pm (UTC)',
321
+ );
322
+ });
323
+
324
+ it('should handle the same date with the same time', () => {
325
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
326
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
327
+ const end = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
328
+ assert.equal(
329
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate }),
330
+ 'today, 12:34pm (UTC)',
331
+ );
332
+ });
333
+
334
+ it('should handle two different dates with the time first', () => {
335
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
336
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
337
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
338
+ assert.equal(
339
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate, timeFirst: true }),
340
+ '12:34pm today to 10am Wed, Jan\u00a03 (UTC)',
341
+ );
342
+ });
343
+
344
+ it('should handle the same date with different times with the time first', () => {
345
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
346
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
347
+ const end = new Date(Date.UTC(2018, 0, 1, 13, 0, 0));
348
+ assert.equal(
349
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate, timeFirst: true }),
350
+ '12:34pm to 1pm today (UTC)',
351
+ );
352
+ });
353
+
354
+ it('should handle the same date with the same time and the time first', () => {
355
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
356
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
357
+ const end = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
358
+ assert.equal(
359
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate, timeFirst: true }),
360
+ '12:34pm today (UTC)',
361
+ );
362
+ });
363
+
364
+ it('should handle two different dates without the timezone', () => {
365
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
366
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
367
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
368
+ assert.equal(
369
+ formatDateRangeFriendly(start, end, 'UTC', { baseDate, includeTz: false }),
370
+ 'today, 12:34pm to Wed, Jan\u00a03, 10am',
371
+ );
372
+ });
373
+
374
+ it('should handle two different dates with only dates and without the timezone', () => {
375
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
376
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
377
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
378
+ assert.equal(
379
+ formatDateRangeFriendly(start, end, 'UTC', {
380
+ baseDate,
381
+ dateOnly: true,
382
+ includeTz: false,
383
+ }),
384
+ 'today to Wed, Jan\u00a03',
385
+ );
386
+ });
387
+
388
+ it('should handle two different dates with time first and without the timezone', () => {
389
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
390
+ const start = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
391
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
392
+ assert.equal(
393
+ formatDateRangeFriendly(start, end, 'UTC', {
394
+ baseDate,
395
+ timeFirst: true,
396
+ includeTz: false,
397
+ }),
398
+ '12:34pm today to 10am Wed, Jan\u00a03',
399
+ );
400
+ });
401
+
402
+ it('should handle two different dates in CST', () => {
403
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
404
+ const start = new Date(Date.UTC(2018, 0, 1, 0, 34, 0));
405
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
406
+ assert.equal(
407
+ formatDateRangeFriendly(start, end, 'America/Chicago', { baseDate }),
408
+ 'yesterday, 6:34pm to Wed, Jan\u00a03, 4am (CST)',
409
+ );
410
+ });
411
+
412
+ it('should handle two different dates in CDT without the timezone', () => {
413
+ const baseDate = new Date(Date.UTC(2018, 0, 1, 12, 34, 0));
414
+ const start = new Date(Date.UTC(2018, 0, 1, 0, 34, 0));
415
+ const end = new Date(Date.UTC(2018, 0, 3, 10, 0, 0));
416
+ assert.equal(
417
+ formatDateRangeFriendly(start, end, 'America/Chicago', {
418
+ baseDate,
419
+ includeTz: false,
420
+ }),
421
+ 'yesterday, 6:34pm to Wed, Jan\u00a03, 4am',
422
+ );
423
+ });
424
+ });
77
425
  });