• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / 67f39f48-4879-4d7a-955d-13ff891730cc

10 Apr 2025 03:28AM UTC coverage: 90.237% (+0.001%) from 90.236%
67f39f48-4879-4d7a-955d-13ff891730cc

push

circleci

xinglu01
fix(util): handle set default locale

5598 of 6865 branches covered (81.54%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

9 existing lines in 1 file now uncovered.

13358 of 14142 relevant lines covered (94.46%)

992.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.31
/src/util/date/tiny-date.ts
1
import { TZDate } from '@date-fns/tz';
2
import { FirstWeekContainsDate, Locale, setHours, setMinutes, setSeconds } from 'date-fns';
3
import { ThyLocaleType } from 'ngx-tethys/i18n';
4
import { SafeAny } from 'ngx-tethys/types';
5
import {
6
    addDays,
15✔
7
    addHours,
14✔
8
    addMinutes,
14✔
9
    addMonths,
10
    addQuarters,
1✔
11
    addSeconds,
12
    addWeeks,
1✔
13
    addYears,
14
    differenceInCalendarDays,
1✔
15
    differenceInCalendarMonths,
1✔
16
    differenceInCalendarQuarters,
1✔
17
    differenceInCalendarYears,
18
    differenceInDays,
44,209✔
19
    differenceInHours,
44,209✔
20
    differenceInMinutes,
41,532✔
21
    differenceInSeconds,
41,122✔
22
    differenceInWeeks,
23
    endOfDay,
410✔
24
    endOfISOWeek,
409✔
25
    endOfMonth,
26
    endOfQuarter,
1!
27
    endOfWeek,
1✔
28
    endOfYear,
29
    format,
30
    fromUnixTime,
31
    getDateFnsLocale,
2,677✔
32
    getDaysInMonth,
33
    getQuarter,
34
    getUnixTime,
35
    getWeek,
55✔
36
    isSameDay,
55✔
37
    isSameHour,
55✔
38
    isSameMinute,
39
    isSameMonth,
UNCOV
40
    isSameQuarter,
×
41
    isSameSecond,
42
    isSameYear,
43
    isToday,
1!
44
    isTomorrow,
45
    isValid,
UNCOV
46
    isWeekend,
×
47
    setDay,
48
    setDefaultOptions,
49
    setMonth,
41,122!
50
    setQuarter,
51
    setYear,
52
    startOfDay,
41✔
53
    startOfISOWeek,
54
    startOfMonth,
55
    startOfQuarter,
172✔
56
    startOfWeek,
57
    startOfYear,
58
    subDays,
59
    subWeeks
1,222✔
60
} from './functions';
61

62
export type TinyDateCompareGrain = 'decade' | 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second';
22,359✔
63

64
export type WeekDayIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6;
65

7,102✔
66
export type TinyDateType = TinyDate | Date | null;
67

68
export function sortRangeValue(rangeValue: TinyDate[]): TinyDate[] {
174✔
69
    if (Array.isArray(rangeValue)) {
70
        const [start, end] = rangeValue;
71
        return start && end && start.isAfterSecond(end) ? [end, start] : [start, end];
755✔
72
    }
73
    return rangeValue;
74
}
33✔
75

76
export const DEFAULT_TIMEZONE = 'Asia/Shanghai';
2✔
77

2✔
78
export class TinyDate implements Record<string, any> {
79
    nativeDate: Date;
80

3✔
81
    private useTimeZone: string;
82

83
    private static locale: string = ThyLocaleType.zhHans;
66✔
84

85
    protected static dateFnsLocale: Locale = getDateFnsLocale(TinyDate.locale);
86

62✔
87
    protected static defaultTimeZone: string = DEFAULT_TIMEZONE;
88

89
    constructor(date?: Date | string | number, zone?: string) {
62✔
90
        this.useTimeZone = zone || TinyDate.defaultTimeZone;
91
        if (date) {
92
            if (date instanceof Date) {
1✔
93
                this.nativeDate = TinyDate.utcToZonedTime(date, this.useTimeZone);
94
            } else if (typeof date === 'string' || typeof date === 'number') {
95
                this.nativeDate = new TZDate(date as SafeAny, this.useTimeZone);
1✔
96
            } else if (typeof ngDevMode === 'undefined' || ngDevMode) {
97
                throw new Error(
98
                    `The input date type is not supported expect Date | string | number | { date: number; with_time: 0 | 1}, actual ${JSON.stringify(
1✔
99
                        date
100
                    )}`
101
                );
102
            }
1✔
103
        } else {
1✔
104
            this.nativeDate = new TZDate(Date.now(), this.useTimeZone);
1✔
105
        }
106
    }
107

102✔
108
    static setDefaultLocale(locale: string) {
102✔
109
        TinyDate.locale = locale;
102✔
110
        TinyDate.dateFnsLocale = getDateFnsLocale(locale);
111
        return setDefaultOptions({ locale: TinyDate.dateFnsLocale });
112
    }
660✔
113

114
    static getDefaultLocale(): { locale: string; dateFnsLocale: Locale } {
115
        return { locale: TinyDate.locale, dateFnsLocale: TinyDate.dateFnsLocale };
1,256✔
116
    }
117

118
    static setDefaultTimeZone(zone: string) {
172✔
119
        TinyDate.defaultTimeZone = zone ?? DEFAULT_TIMEZONE;
120
    }
121

1✔
122
    static getDefaultTimeZone(): string {
123
        return TinyDate.defaultTimeZone;
124
    }
32✔
125

126
    static utcToZonedTime(value: Date | number, timeZone?: string): Date {
127
        return TZDate.tz(timeZone || TinyDate.defaultTimeZone, value as any);
32✔
128
    }
129

130
    static createDateInTimeZone(
32✔
131
        year: number,
132
        month: number,
133
        day: number,
134
        hours: number,
398✔
135
        minutes: number,
136
        seconds: number,
137
        timeZone?: string
450✔
138
    ): Date {
139
        return new TZDate(year, month, day, hours, minutes, seconds, timeZone || TinyDate.defaultTimeZone);
140
    }
650✔
141

142
    static fromUnixTime(unixTime: number, timeZone?: string): TinyDate {
143
        return new TinyDate(fromUnixTime(unixTime), timeZone || TinyDate.defaultTimeZone);
1✔
144
    }
145

146
    // get
28,987✔
147
    getTime(): number {
148
        return this.nativeDate.getTime();
149
    }
1✔
150

151
    getDate(): number {
152
        return this.nativeDate.getDate();
2✔
153
    }
154

155
    getYear(): number {
1✔
156
        return this.nativeDate.getFullYear();
157
    }
158

×
159
    getQuarter(): number {
160
        return getQuarter(this.nativeDate);
55,148✔
161
    }
162

2✔
163
    getMonth(): number {
2✔
164
        return this.nativeDate.getMonth();
165
    }
799✔
166

799✔
167
    getFullYear(): number {
168
        return this.nativeDate.getFullYear();
1,425✔
169
    }
1,425✔
170

171
    getWeek(options: { locale?: Locale; weekStartsOn?: WeekDayIndex } = { weekStartsOn: 1 }): number {
441✔
172
        return getWeek(this.nativeDate, options);
441✔
173
    }
174

52,474✔
175
    getDay(): number {
52,474✔
176
        return this.nativeDate.getDay();
177
    }
2✔
178

2✔
179
    getHours(): number {
180
        return this.nativeDate.getHours();
2✔
181
    }
2✔
182

183
    getMinutes(): number {
2✔
184
        return this.nativeDate.getMinutes();
2✔
185
    }
186

1✔
187
    getSeconds(): number {
1✔
188
        return this.nativeDate.getSeconds();
189
    }
55,148✔
190

191
    getMilliseconds(): number {
192
        return this.nativeDate.getMilliseconds();
787✔
193
    }
194

195
    getDaysInMonth() {
1,363✔
196
        return getDaysInMonth(this.nativeDate);
197
    }
198

441✔
199
    getDaysInQuarter() {
200
        return differenceInCalendarDays(this.endOfQuarter().addSeconds(1).nativeDate, this.startOfQuarter().nativeDate);
201
    }
52,473✔
202

203
    // set
204
    setDate(amount: number): TinyDate {
1✔
205
        const date = new Date(this.nativeDate);
206
        date.setDate(amount);
207
        return new TinyDate(date, this.useTimeZone);
1✔
208
    }
209

210
    setHms(hour: number, minute: number, second: number): TinyDate {
1✔
211
        const date = new Date(this.nativeDate);
212
        date.setHours(hour, minute, second);
213
        return new TinyDate(date, this.useTimeZone);
214
    }
127✔
215

216
    setYear(year: number): TinyDate {
217
        return new TinyDate(setYear(this.nativeDate, year), this.useTimeZone);
64✔
218
    }
219

220
    setMonth(month: number): TinyDate {
22,279✔
221
        return new TinyDate(setMonth(this.nativeDate, month), this.useTimeZone);
222
    }
223

1✔
224
    setQuarter(quarter: number): TinyDate {
225
        return new TinyDate(setQuarter(this.nativeDate, quarter), this.useTimeZone);
226
    }
7,151✔
227

228
    setDay(day: number, options?: { weekStartsOn: WeekDayIndex }): TinyDate {
229
        return new TinyDate(setDay(this.nativeDate, day, options), this.useTimeZone);
1✔
230
    }
231

232
    setHours(hours: number): TinyDate {
1✔
233
        return new TinyDate(setHours(this.nativeDate, hours), this.useTimeZone);
234
    }
235

1✔
236
    setMinutes(minutes: number): TinyDate {
237
        return new TinyDate(setMinutes(this.nativeDate, minutes), this.useTimeZone);
238
    }
2✔
239

240
    setSeconds(seconds: number): TinyDate {
UNCOV
241
        return new TinyDate(setSeconds(this.nativeDate, seconds), this.useTimeZone);
×
242
    }
243

244
    // add
22,135✔
245
    addYears(amount: number): TinyDate {
246
        return new TinyDate(addYears(this.nativeDate, amount), this.useTimeZone);
247
    }
1✔
248

249
    addQuarters(amount: number): TinyDate {
250
        return new TinyDate(addQuarters(this.nativeDate, amount), this.useTimeZone);
2✔
251
    }
252

253
    addMonths(amount: number): TinyDate {
1✔
254
        return new TinyDate(addMonths(this.nativeDate, amount), this.useTimeZone);
255
    }
256

1✔
257
    addWeeks(amount: number): TinyDate {
258
        return new TinyDate(addWeeks(this.nativeDate, amount), this.useTimeZone);
259
    }
15✔
260

261
    addDays(amount: number): TinyDate {
262
        return new TinyDate(addDays(this.nativeDate, amount), this.useTimeZone);
263
    }
2✔
264
    addHours(amount: number): TinyDate {
265
        return new TinyDate(addHours(this.nativeDate, amount), this.useTimeZone);
266
    }
44,270✔
267

268
    addSeconds(amount: number): TinyDate {
269
        return new TinyDate(addSeconds(this.nativeDate, amount), this.useTimeZone);
2✔
270
    }
271

272
    addMinutes(amount: number): TinyDate {
2✔
273
        return new TinyDate(addMinutes(this.nativeDate, amount), this.useTimeZone);
274
    }
275

276
    // isSame
379✔
277

278
    isSame(date: TinyDateType, grain: TinyDateCompareGrain = 'day'): boolean {
279
        let fn;
206✔
280
        switch (grain) {
281
            case 'decade':
282
                fn = (pre: Date, next: Date) => Math.abs(pre.getFullYear() - next.getFullYear()) < 11;
236✔
283
                break;
284
            case 'year':
285
                fn = isSameYear;
32✔
286
                break;
287
            case 'month':
288
                fn = isSameMonth;
2,376✔
289
                break;
290
            case 'quarter':
291
                fn = isSameQuarter;
113✔
292
                break;
293
            case 'day':
294
                fn = isSameDay;
151✔
295
                break;
296
            case 'hour':
297
                fn = isSameHour;
180✔
298
                break;
299
            case 'minute':
300
                fn = isSameMinute;
33✔
301
                break;
302
            case 'second':
303
                fn = isSameSecond;
2,126✔
304
                break;
305
            default:
306
                fn = isSameDay;
307
                break;
402✔
308
        }
309
        return fn(this.nativeDate, this.toNativeDate(date));
310
    }
1,055✔
311

312
    isSameYear(date: TinyDateType): boolean {
313
        return this.isSame(date, 'year');
147✔
314
    }
315

316
    isSameMonth(date: TinyDateType): boolean {
213✔
317
        return this.isSame(date, 'month');
318
    }
29,625!
319

51,782✔
320
    isSameQuarter(date: TinyDateType): boolean {
2✔
321
        return this.isSame(date, 'quarter');
322
    }
323

51,780!
324
    isSameDay(date: TinyDateType): boolean {
325
        return this.isSame(date, 'day');
127✔
326
    }
127✔
327

328
    isSameHour(date: TinyDateType): boolean {
64✔
329
        return this.isSame(date, 'hour');
64✔
330
    }
331

44,414✔
332
    isSameMinute(date: TinyDateType): boolean {
44,414✔
333
        return this.isSame(date, 'minute');
334
    }
7,153✔
335

7,153✔
336
    isSameSecond(date: TinyDateType): boolean {
337
        return this.isSame(date, 'second');
2✔
338
    }
2✔
339

340
    // isBefore and isAfter
2✔
341
    isBeforeYear(date: TinyDateType): boolean {
2✔
342
        return this.compare(date, 'year');
343
    }
2✔
344

2✔
345
    isBeforeQuarter(date: TinyDate): boolean {
346
        return this.compare(date, 'quarter');
16✔
347
    }
16✔
348

349
    isBeforeMonth(date: TinyDateType): boolean {
×
UNCOV
350
        return this.compare(date, 'month');
×
351
    }
352

51,780✔
353
    isBeforeWeek(date: TinyDateType): boolean {
354
        return this.compare(date, 'week');
355
    }
106,928✔
356

357
    isBeforeDay(date: TinyDateType): boolean {
UNCOV
358
        return this.compare(date, 'day');
×
359
    }
360

UNCOV
361
    isBeforeHour(date: TinyDateType): boolean {
×
362
        return this.compare(date, 'hour');
363
    }
UNCOV
364

×
365
    isBeforeMinute(date: TinyDateType): boolean {
366
        return this.compare(date, 'minute');
UNCOV
367
    }
×
368

369
    isBeforeSecond(date: TinyDateType): boolean {
UNCOV
370
        return this.compare(date, 'second');
×
371
    }
372

373
    isAfterYear(date: TinyDateType): boolean {
6✔
374
        return this.compare(date, 'year', false);
375
    }
376

377
    isAfterQuarter(date: TinyDate): boolean {
378
        return this.compare(date, 'quarter', false);
379
    }
380

381
    isAfterMonth(date: TinyDateType): boolean {
382
        return this.compare(date, 'month', false);
383
    }
384

385
    isAfterWeek(date: TinyDateType): boolean {
386
        return this.compare(date, 'week', false);
387
    }
388

389
    isAfterDay(date: TinyDateType): boolean {
390
        return this.compare(date, 'day', false);
391
    }
392

393
    isAfterHour(date: TinyDateType): boolean {
394
        return this.compare(date, 'hour', false);
395
    }
396

397
    isAfterMinute(date: TinyDateType): boolean {
398
        return this.compare(date, 'minute', false);
399
    }
400

401
    isAfterSecond(date: TinyDateType): boolean {
402
        return this.compare(date, 'second', false);
403
    }
404

405
    // is
406
    isWeekend(): boolean {
407
        return isWeekend(this.nativeDate);
408
    }
409

410
    isToday(): boolean {
411
        return isToday(this.nativeDate);
412
    }
413

414
    isTomorrow(): boolean {
415
        return isTomorrow(this.nativeDate);
416
    }
417

418
    isValid(): boolean {
419
        return isValid(this.nativeDate);
420
    }
421

422
    // startOf and endOf
423
    startOfYear(): TinyDate {
424
        return new TinyDate(startOfYear(this.nativeDate), this.useTimeZone);
425
    }
426

427
    startOfQuarter(): TinyDate {
428
        return new TinyDate(startOfQuarter(this.nativeDate), this.useTimeZone);
429
    }
430

431
    startOfMonth(): TinyDate {
432
        return new TinyDate(startOfMonth(this.nativeDate), this.useTimeZone);
433
    }
434

435
    startOfWeek(options?: { locale?: Locale; weekStartsOn?: WeekDayIndex }): TinyDate {
436
        return new TinyDate(startOfWeek(this.nativeDate, options), this.useTimeZone);
437
    }
438

439
    startOfDay(): TinyDate {
440
        return new TinyDate(startOfDay(this.nativeDate), this.useTimeZone);
441
    }
442

443
    endOfYear(): TinyDate {
444
        return new TinyDate(endOfYear(this.nativeDate), this.useTimeZone);
445
    }
446

447
    endOfQuarter(): TinyDate {
448
        return new TinyDate(endOfQuarter(this.nativeDate), this.useTimeZone);
449
    }
450

451
    endOfMonth(): TinyDate {
452
        return new TinyDate(endOfMonth(this.nativeDate), this.useTimeZone);
453
    }
454

455
    endOfWeek(options?: { locale?: Locale; weekStartsOn?: WeekDayIndex }): TinyDate {
456
        return new TinyDate(endOfWeek(this.nativeDate, options), this.useTimeZone);
457
    }
458

459
    endOfDay(): TinyDate {
460
        return new TinyDate(endOfDay(this.nativeDate), this.useTimeZone);
461
    }
462

463
    // other
464
    format(
465
        mat: string,
466
        options?: {
467
            locale?: Locale;
468
            weekStartsOn?: WeekDayIndex;
469
            firstWeekContainsDate?: FirstWeekContainsDate;
470
            useAdditionalWeekYearTokens?: boolean;
471
            useAdditionalDayOfYearTokens?: boolean;
472
        }
473
    ) {
474
        return format(this.nativeDate, mat, options);
475
    }
476

477
    calendarStart(options?: { weekStartsOn: WeekDayIndex | undefined }): TinyDate {
478
        return new TinyDate(startOfWeek(startOfMonth(this.nativeDate), options), this.useTimeZone);
479
    }
480

481
    clone(): TinyDate {
482
        return new TinyDate(new Date(this.nativeDate), this.useTimeZone);
483
    }
484

485
    getUnixTime(): number {
486
        return getUnixTime(this.nativeDate);
487
    }
488

489
    compare(date: TinyDateType, grain: TinyDateCompareGrain = 'day', isBefore: boolean = true): boolean {
490
        if (date === null) {
491
            return false;
492
        }
493
        let fn;
494
        switch (grain) {
495
            case 'year':
496
                fn = differenceInCalendarYears;
497
                break;
498
            case 'quarter':
499
                fn = differenceInCalendarQuarters;
500
                break;
501
            case 'month':
502
                fn = differenceInCalendarMonths;
503
                break;
504
            case 'day':
505
                fn = differenceInCalendarDays;
506
                break;
507
            case 'week':
508
                fn = differenceInWeeks;
509
                break;
510
            case 'hour':
511
                fn = differenceInHours;
512
                break;
513
            case 'minute':
514
                fn = differenceInMinutes;
515
                break;
516
            case 'second':
517
                fn = differenceInSeconds;
518
                break;
519
            default:
520
                fn = differenceInCalendarDays;
521
                break;
522
        }
523
        return isBefore ? fn(this.nativeDate, this.toNativeDate(date)) < 0 : fn(this.nativeDate, this.toNativeDate(date)) > 0;
524
    }
525

526
    private toNativeDate(date: any): Date {
527
        return date instanceof TinyDate ? date.nativeDate : date;
528
    }
529

530
    startOfISOWeek(): TinyDate {
531
        return new TinyDate(startOfISOWeek(this.nativeDate), this.useTimeZone);
532
    }
533

534
    endOfISOWeek(): TinyDate {
535
        return new TinyDate(endOfISOWeek(this.nativeDate), this.useTimeZone);
536
    }
537

538
    differenceInDays(date: Date): number {
539
        return differenceInDays(this.nativeDate, date);
540
    }
541

542
    differenceInHours(date: Date): number {
543
        return differenceInHours(this.nativeDate, date);
544
    }
545

546
    subWeeks(amount: number): TinyDate {
547
        return new TinyDate(subWeeks(this.nativeDate, amount), this.useTimeZone);
548
    }
549

550
    subDays(amount: number): TinyDate {
551
        return new TinyDate(subDays(this.nativeDate, amount), this.useTimeZone);
552
    }
553
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc