@imihai/angular-datetime-picker 21.0.2 → 22.0.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/.browserslistrc +9 -0
- package/.editorconfig +13 -0
- package/.eslintrc.js +208 -0
- package/.github/workflows/ci_test.yml +35 -0
- package/.prettierrc +2 -0
- package/.travis.yml +16 -0
- package/angular.json +221 -0
- package/e2e/protractor.conf.js +28 -0
- package/e2e/src/app.e2e-spec.ts +14 -0
- package/e2e/src/app.po.ts +11 -0
- package/e2e/tsconfig.e2e.json +13 -0
- package/package.json +77 -33
- package/projects/picker/karma.conf.js +62 -0
- package/projects/picker/ng-package.json +7 -0
- package/projects/picker/package.json +23 -0
- package/projects/picker/src/lib/date-time/adapter/date-time-adapter.class.ts +313 -0
- package/projects/picker/src/lib/date-time/adapter/date-time-format.class.ts +18 -0
- package/projects/picker/src/lib/date-time/adapter/luxon-date-time-adapter.class.ts +307 -0
- package/projects/picker/src/lib/date-time/adapter/luxon-date-time-format.class.ts +11 -0
- package/projects/picker/src/lib/date-time/adapter/luxon-date-time.module.ts +31 -0
- package/projects/picker/src/lib/date-time/adapter/unix-timestamp-adapter/unix-timestamp-date-time-adapter.class.ts +356 -0
- package/projects/picker/src/lib/date-time/adapter/unix-timestamp-adapter/unix-timestamp-date-time-format.class.ts +14 -0
- package/projects/picker/src/lib/date-time/adapter/unix-timestamp-adapter/unix-timestamp-date-time.module.ts +26 -0
- package/projects/picker/src/lib/date-time/calendar-body.component.html +38 -0
- package/projects/picker/src/lib/date-time/calendar-body.component.scss +0 -0
- package/projects/picker/src/lib/date-time/calendar-body.component.spec.ts +120 -0
- package/projects/picker/src/lib/date-time/calendar-body.component.ts +190 -0
- package/projects/picker/src/lib/date-time/calendar-month-view.component.html +47 -0
- package/projects/picker/src/lib/date-time/calendar-month-view.component.scss +16 -0
- package/projects/picker/src/lib/date-time/calendar-month-view.component.spec.ts +394 -0
- package/projects/picker/src/lib/date-time/calendar-month-view.component.ts +705 -0
- package/projects/picker/src/lib/date-time/calendar-multi-year-view.component.html +44 -0
- package/projects/picker/src/lib/date-time/calendar-multi-year-view.component.scss +0 -0
- package/projects/picker/src/lib/date-time/calendar-multi-year-view.component.spec.ts +343 -0
- package/projects/picker/src/lib/date-time/calendar-multi-year-view.component.ts +465 -0
- package/projects/picker/src/lib/date-time/calendar-year-view.component.html +16 -0
- package/projects/picker/src/lib/date-time/calendar-year-view.component.scss +0 -0
- package/projects/picker/src/lib/date-time/calendar-year-view.component.spec.ts +381 -0
- package/projects/picker/src/lib/date-time/calendar-year-view.component.ts +549 -0
- package/projects/picker/src/lib/date-time/calendar.component.html +169 -0
- package/projects/picker/src/lib/date-time/calendar.component.scss +0 -0
- package/projects/picker/src/lib/date-time/calendar.component.spec.ts +592 -0
- package/projects/picker/src/lib/date-time/calendar.component.ts +496 -0
- package/projects/picker/src/lib/date-time/date-time-inline.component.html +1 -0
- package/projects/picker/src/lib/date-time/date-time-inline.component.scss +4 -0
- package/projects/picker/src/lib/date-time/date-time-inline.component.ts +365 -0
- package/projects/picker/src/lib/date-time/date-time-picker-animation-event.ts +4 -0
- package/projects/picker/src/lib/date-time/date-time-picker-container.component.html +126 -0
- package/projects/picker/src/lib/date-time/date-time-picker-container.component.scss +0 -0
- package/projects/picker/src/lib/date-time/date-time-picker-container.component.ts +631 -0
- package/projects/picker/src/lib/date-time/date-time-picker-input.directive.ts +851 -0
- package/projects/picker/src/lib/date-time/date-time-picker-intl.service.ts +76 -0
- package/projects/picker/src/lib/date-time/date-time-picker-trigger.directive.ts +88 -0
- package/projects/picker/src/lib/date-time/date-time-picker.component.html +0 -0
- package/projects/picker/src/lib/date-time/date-time-picker.component.scss +0 -0
- package/projects/picker/src/lib/date-time/date-time-picker.component.spec.ts +2648 -0
- package/projects/picker/src/lib/date-time/date-time-picker.component.ts +731 -0
- package/projects/picker/src/lib/date-time/date-time.class.ts +256 -0
- package/projects/picker/src/lib/date-time/date-time.module.ts +61 -0
- package/projects/picker/src/lib/date-time/numberedFixLen.pipe.ts +28 -0
- package/projects/picker/src/lib/date-time/options-provider.ts +44 -0
- package/projects/picker/src/lib/date-time/timer-box.component.html +79 -0
- package/projects/picker/src/lib/date-time/timer-box.component.scss +0 -0
- package/projects/picker/src/lib/date-time/timer-box.component.ts +175 -0
- package/projects/picker/src/lib/date-time/timer.component.html +58 -0
- package/projects/picker/src/lib/date-time/timer.component.scss +0 -0
- package/projects/picker/src/lib/date-time/timer.component.spec.ts +399 -0
- package/projects/picker/src/lib/date-time/timer.component.ts +371 -0
- package/projects/picker/src/lib/dialog/dialog-config.class.ts +220 -0
- package/projects/picker/src/lib/dialog/dialog-container.component.html +1 -0
- package/projects/picker/src/lib/dialog/dialog-container.component.scss +0 -0
- package/projects/picker/src/lib/dialog/dialog-container.component.ts +231 -0
- package/projects/picker/src/lib/dialog/dialog-ref.class.ts +178 -0
- package/projects/picker/src/lib/dialog/dialog.module.ts +25 -0
- package/projects/picker/src/lib/dialog/dialog.service.ts +353 -0
- package/projects/picker/src/lib/utils/array.utils.ts +12 -0
- package/projects/picker/src/lib/utils/constants.ts +59 -0
- package/projects/picker/src/lib/utils/date.utils.ts +97 -0
- package/projects/picker/src/lib/utils/index.ts +5 -0
- package/projects/picker/src/lib/utils/object.utils.ts +29 -0
- package/projects/picker/src/public_api.ts +56 -0
- package/projects/picker/src/sass/picker.scss +743 -0
- package/projects/picker/src/test-helpers.ts +125 -0
- package/projects/picker/src/test.ts +52 -0
- package/projects/picker/tsconfig.lib.json +19 -0
- package/projects/picker/tsconfig.lib.prod.json +7 -0
- package/projects/picker/tsconfig.spec.json +17 -0
- package/projects/picker/tslint.json +8 -0
- package/src/app/app.component.html +77 -0
- package/src/app/app.component.scss +32 -0
- package/src/app/app.component.spec.ts +16 -0
- package/src/app/app.component.ts +35 -0
- package/src/assets/.gitkeep +0 -0
- package/src/environments/environment.prod.ts +3 -0
- package/src/environments/environment.ts +16 -0
- package/src/favicon.ico +0 -0
- package/src/index.html +14 -0
- package/src/karma.conf.js +31 -0
- package/src/main.ts +16 -0
- package/src/polyfills.ts +53 -0
- package/src/styles.scss +7 -0
- package/src/test.ts +50 -0
- package/src/tsconfig.app.json +16 -0
- package/src/tsconfig.spec.json +18 -0
- package/src/tslint.json +17 -0
- package/tsconfig.base.json +31 -0
- package/tsconfig.json +30 -0
- package/tslint.json +130 -0
- package/assets/style/picker.min.css +0 -1
- package/fesm2022/imihai-angular-datetime-picker.mjs +0 -5845
- package/fesm2022/imihai-angular-datetime-picker.mjs.map +0 -1
- package/imihai-angular-datetime-picker-21.0.2.tgz +0 -0
- package/types/imihai-angular-datetime-picker.d.ts +0 -2193
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* luxon-date-time-adapter.class
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Inject, Injectable, Optional } from '@angular/core';
|
|
6
|
+
import { DateTime, Info, Settings } from 'luxon';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
DateTimeAdapter,
|
|
10
|
+
OWL_DATE_TIME_LOCALE,
|
|
11
|
+
} from './date-time-adapter.class';
|
|
12
|
+
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class LuxonDateTimeAdapter extends DateTimeAdapter<DateTime> {
|
|
15
|
+
public firstMonthOfTheYear = 0;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 0 - Sunday
|
|
19
|
+
* 1 - Monday
|
|
20
|
+
* ...
|
|
21
|
+
* 6 - Saturday
|
|
22
|
+
*/
|
|
23
|
+
public firstDayOfTheWeek = 0;
|
|
24
|
+
|
|
25
|
+
public constructor(
|
|
26
|
+
@Optional()
|
|
27
|
+
@Inject(OWL_DATE_TIME_LOCALE)
|
|
28
|
+
private owlDateTimeLocale: string,
|
|
29
|
+
) {
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
this.setLocale(owlDateTimeLocale || Settings.defaultLocale || 'ru');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public getYear(date: DateTime): number {
|
|
36
|
+
return date.year;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Picker expects month index:
|
|
41
|
+
* 0 - January
|
|
42
|
+
* 11 - December
|
|
43
|
+
*
|
|
44
|
+
* Luxon uses:
|
|
45
|
+
* 1 - January
|
|
46
|
+
* 12 - December
|
|
47
|
+
*/
|
|
48
|
+
public getMonth(date: DateTime): number {
|
|
49
|
+
return date.month - 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Picker expects:
|
|
54
|
+
* 0 - Sunday
|
|
55
|
+
* 6 - Saturday
|
|
56
|
+
*
|
|
57
|
+
* Luxon weekday:
|
|
58
|
+
* 1 - Monday
|
|
59
|
+
* 7 - Sunday
|
|
60
|
+
*/
|
|
61
|
+
public getDay(date: DateTime): number {
|
|
62
|
+
return date.weekday % 7;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public getDate(date: DateTime): number {
|
|
66
|
+
return date.day;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public getHours(date: DateTime): number {
|
|
70
|
+
return date.hour;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public getMinutes(date: DateTime): number {
|
|
74
|
+
return date.minute;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public getSeconds(date: DateTime): number {
|
|
78
|
+
return date.second;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public getTime(date: DateTime): number {
|
|
82
|
+
return date.toMillis();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public getNumDaysInMonth(date: DateTime): number {
|
|
86
|
+
return date.daysInMonth ?? 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public differenceInCalendarDays(dateLeft: DateTime, dateRight: DateTime): number {
|
|
90
|
+
if (this.isValid(dateLeft) && this.isValid(dateRight)) {
|
|
91
|
+
return Math.round(
|
|
92
|
+
dateLeft.startOf('day').diff(dateRight.startOf('day'), 'days').days,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public getYearName(date: DateTime): string {
|
|
100
|
+
return date.setLocale(this.locale).toFormat('yyyy');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public getMonthNames(style: 'long' | 'short' | 'narrow'): string[] {
|
|
104
|
+
return Info.months(style, { locale: this.locale });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] {
|
|
108
|
+
const weekdays = Info.weekdays(style, { locale: this.locale });
|
|
109
|
+
|
|
110
|
+
// Luxon returns Monday..Sunday.
|
|
111
|
+
// Existing picker expects Sunday..Saturday.
|
|
112
|
+
return [
|
|
113
|
+
weekdays[6],
|
|
114
|
+
...weekdays.slice(0, 6),
|
|
115
|
+
];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public getDateNames(): string[] {
|
|
119
|
+
return Array.from({ length: 31 }, (_, index) => `${index + 1}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public toIso8601(date: DateTime): string {
|
|
123
|
+
return date.toISO() ?? '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public isEqual(dateLeft: DateTime, dateRight: DateTime): boolean {
|
|
127
|
+
if (this.isValid(dateLeft) && this.isValid(dateRight)) {
|
|
128
|
+
return dateLeft.toMillis() === dateRight.toMillis();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public isSameDay(dateLeft: DateTime, dateRight: DateTime): boolean {
|
|
135
|
+
if (this.isValid(dateLeft) && this.isValid(dateRight)) {
|
|
136
|
+
return (
|
|
137
|
+
dateLeft.year === dateRight.year &&
|
|
138
|
+
dateLeft.month === dateRight.month &&
|
|
139
|
+
dateLeft.day === dateRight.day
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public isValid(date: DateTime): boolean {
|
|
147
|
+
return DateTime.isDateTime(date) && date.isValid;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public invalid(): DateTime {
|
|
151
|
+
return DateTime.invalid('Invalid date');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public isDateInstance(obj: unknown): boolean {
|
|
155
|
+
return DateTime.isDateTime(obj);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public addCalendarYears(date: DateTime, amount: number): DateTime {
|
|
159
|
+
return date.plus({ years: Number(amount) });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public addCalendarMonths(date: DateTime, amount: number): DateTime {
|
|
163
|
+
return date.plus({ months: Number(amount) });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public addCalendarDays(date: DateTime, amount: number): DateTime {
|
|
167
|
+
return date.plus({ days: Number(amount) });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
public setHours(date: DateTime, amount: number): DateTime {
|
|
171
|
+
return date.set({ hour: amount });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public setMinutes(date: DateTime, amount: number): DateTime {
|
|
175
|
+
return date.set({ minute: amount });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public setSeconds(date: DateTime, amount: number): DateTime {
|
|
179
|
+
return date.set({ second: amount });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public createDate(
|
|
183
|
+
year: number,
|
|
184
|
+
month: number,
|
|
185
|
+
date: number,
|
|
186
|
+
hours = 0,
|
|
187
|
+
minutes = 0,
|
|
188
|
+
seconds = 0,
|
|
189
|
+
): DateTime {
|
|
190
|
+
const result = DateTime.local(
|
|
191
|
+
year,
|
|
192
|
+
month + 1,
|
|
193
|
+
date,
|
|
194
|
+
hours,
|
|
195
|
+
minutes,
|
|
196
|
+
seconds,
|
|
197
|
+
0,
|
|
198
|
+
).setLocale(this.locale);
|
|
199
|
+
|
|
200
|
+
if (!result.isValid) {
|
|
201
|
+
throw Error(
|
|
202
|
+
`LuxonDateTimeAdapter: Invalid date "${date}" for month with index "${month}".`,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public clone(date: DateTime): DateTime {
|
|
210
|
+
return DateTime.fromMillis(date.toMillis(), {
|
|
211
|
+
zone: date.zone,
|
|
212
|
+
locale: date.locale,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
public now(): DateTime {
|
|
217
|
+
return DateTime.local().setLocale(this.locale);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public format(date: DateTime, displayFormat: string): string {
|
|
221
|
+
if (!this.isValid(date)) {
|
|
222
|
+
throw Error('LuxonDateTimeAdapter: Cannot format invalid date.');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return date.setLocale(this.locale).toFormat(displayFormat);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
public parse(value: unknown, parseFormat: string | string[]): DateTime | null {
|
|
229
|
+
if (value == null || value === '') {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (DateTime.isDateTime(value)) {
|
|
234
|
+
return value.isValid ? value.setLocale(this.locale) : this.invalid();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (value instanceof Date) {
|
|
238
|
+
const date = DateTime.fromJSDate(value).setLocale(this.locale);
|
|
239
|
+
|
|
240
|
+
return date.isValid ? date : this.invalid();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (typeof value === 'number') {
|
|
244
|
+
const date = DateTime.fromMillis(value).setLocale(this.locale);
|
|
245
|
+
|
|
246
|
+
return date.isValid ? date : this.invalid();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (typeof value !== 'string') {
|
|
250
|
+
return this.invalid();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const formats = Array.isArray(parseFormat) ? parseFormat : [parseFormat];
|
|
254
|
+
|
|
255
|
+
for (const format of formats) {
|
|
256
|
+
const parsed = DateTime.fromFormat(value, format, {
|
|
257
|
+
locale: this.locale,
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
if (parsed.isValid) {
|
|
261
|
+
return parsed;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const iso = DateTime.fromISO(value, {
|
|
266
|
+
locale: this.locale,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
return iso.isValid ? iso : this.invalid();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
public deserialize(value: unknown): DateTime | null {
|
|
273
|
+
if (value == null || value === '') {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (DateTime.isDateTime(value)) {
|
|
278
|
+
return value.isValid ? value.setLocale(this.locale) : this.invalid();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (value instanceof Date) {
|
|
282
|
+
const date = DateTime.fromJSDate(value).setLocale(this.locale);
|
|
283
|
+
|
|
284
|
+
return date.isValid ? date : this.invalid();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (typeof value === 'number') {
|
|
288
|
+
const date = DateTime.fromMillis(value).setLocale(this.locale);
|
|
289
|
+
|
|
290
|
+
return date.isValid ? date : this.invalid();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (typeof value === 'string') {
|
|
294
|
+
const date = DateTime.fromISO(value, {
|
|
295
|
+
locale: this.locale,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return date.isValid ? date : this.invalid();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return this.invalid();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
public override setLocale(locale: string): void {
|
|
305
|
+
super.setLocale(locale || 'ru');
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OwlDateTimeFormats } from './date-time-format.class';
|
|
2
|
+
|
|
3
|
+
export const OWL_LUXON_DATE_TIME_FORMATS: OwlDateTimeFormats = {
|
|
4
|
+
parseInput: 'dd.MM.yyyy HH:mm',
|
|
5
|
+
fullPickerInput: 'dd.MM.yyyy HH:mm',
|
|
6
|
+
datePickerInput: 'dd.MM.yyyy',
|
|
7
|
+
timePickerInput: 'HH:mm',
|
|
8
|
+
monthYearLabel: 'LLL yyyy',
|
|
9
|
+
dateA11yLabel: 'dd.MM.yyyy',
|
|
10
|
+
monthYearA11yLabel: 'LLLL yyyy',
|
|
11
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* luxon-date-time.module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { NgModule } from '@angular/core';
|
|
6
|
+
|
|
7
|
+
import { DateTimeAdapter } from './date-time-adapter.class';
|
|
8
|
+
import { OWL_DATE_TIME_FORMATS } from './date-time-format.class';
|
|
9
|
+
import { LuxonDateTimeAdapter } from './luxon-date-time-adapter.class';
|
|
10
|
+
import { OWL_LUXON_DATE_TIME_FORMATS } from './luxon-date-time-format.class';
|
|
11
|
+
|
|
12
|
+
@NgModule({
|
|
13
|
+
providers: [
|
|
14
|
+
{
|
|
15
|
+
provide: DateTimeAdapter,
|
|
16
|
+
useClass: LuxonDateTimeAdapter,
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
})
|
|
20
|
+
export class LuxonDateTimeModule {}
|
|
21
|
+
|
|
22
|
+
@NgModule({
|
|
23
|
+
imports: [LuxonDateTimeModule],
|
|
24
|
+
providers: [
|
|
25
|
+
{
|
|
26
|
+
provide: OWL_DATE_TIME_FORMATS,
|
|
27
|
+
useValue: OWL_LUXON_DATE_TIME_FORMATS,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
})
|
|
31
|
+
export class OwlLuxonDateTimeModule {}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* unix-timestamp-date-time-adapter.class
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Inject, Injectable, Optional } from '@angular/core';
|
|
6
|
+
import { DateTime, Info, Settings } from 'luxon';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
DateTimeAdapter,
|
|
10
|
+
OWL_DATE_TIME_LOCALE,
|
|
11
|
+
} from '../date-time-adapter.class';
|
|
12
|
+
|
|
13
|
+
@Injectable()
|
|
14
|
+
export class UnixTimestampDateTimeAdapter extends DateTimeAdapter<number> {
|
|
15
|
+
public firstMonthOfTheYear = 0;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Picker expects:
|
|
19
|
+
* 0 - Sunday
|
|
20
|
+
* 1 - Monday
|
|
21
|
+
* ...
|
|
22
|
+
* 6 - Saturday
|
|
23
|
+
*/
|
|
24
|
+
public firstDayOfTheWeek = 0;
|
|
25
|
+
|
|
26
|
+
public constructor(
|
|
27
|
+
@Optional()
|
|
28
|
+
@Inject(OWL_DATE_TIME_LOCALE)
|
|
29
|
+
private owlDateTimeLocale: string,
|
|
30
|
+
) {
|
|
31
|
+
super();
|
|
32
|
+
|
|
33
|
+
this.setLocale(owlDateTimeLocale || Settings.defaultLocale || 'ru');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public getYear(date: number): number {
|
|
37
|
+
return this.fromTimestamp(date).year;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Picker expects:
|
|
42
|
+
* 0 - January
|
|
43
|
+
* 11 - December
|
|
44
|
+
*
|
|
45
|
+
* Luxon uses:
|
|
46
|
+
* 1 - January
|
|
47
|
+
* 12 - December
|
|
48
|
+
*/
|
|
49
|
+
public getMonth(date: number): number {
|
|
50
|
+
return this.fromTimestamp(date).month - 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Picker expects:
|
|
55
|
+
* 0 - Sunday
|
|
56
|
+
* 6 - Saturday
|
|
57
|
+
*
|
|
58
|
+
* Luxon weekday:
|
|
59
|
+
* 1 - Monday
|
|
60
|
+
* 7 - Sunday
|
|
61
|
+
*/
|
|
62
|
+
public getDay(date: number): number {
|
|
63
|
+
return this.fromTimestamp(date).weekday % 7;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public getDate(date: number): number {
|
|
67
|
+
return this.fromTimestamp(date).day;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public getHours(date: number): number {
|
|
71
|
+
return this.fromTimestamp(date).hour;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public getMinutes(date: number): number {
|
|
75
|
+
return this.fromTimestamp(date).minute;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public getSeconds(date: number): number {
|
|
79
|
+
return this.fromTimestamp(date).second;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public getTime(date: number): number {
|
|
83
|
+
return date;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public getNumDaysInMonth(date: number): number {
|
|
87
|
+
return this.fromTimestamp(date).daysInMonth ?? 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public differenceInCalendarDays(dateLeft: number, dateRight: number): number {
|
|
91
|
+
if (!this.isValid(dateLeft) || !this.isValid(dateRight)) {
|
|
92
|
+
return Number.NaN;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return Math.round(
|
|
96
|
+
this.fromTimestamp(dateLeft)
|
|
97
|
+
.startOf('day')
|
|
98
|
+
.diff(this.fromTimestamp(dateRight).startOf('day'), 'days').days,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public getYearName(date: number): string {
|
|
103
|
+
return this.fromTimestamp(date).toFormat('yyyy');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public getMonthNames(style: 'long' | 'short' | 'narrow'): string[] {
|
|
107
|
+
return Info.months(style, { locale: this.locale });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[] {
|
|
111
|
+
const weekdays = Info.weekdays(style, { locale: this.locale });
|
|
112
|
+
|
|
113
|
+
// Luxon returns Monday..Sunday.
|
|
114
|
+
// Existing picker expects Sunday..Saturday.
|
|
115
|
+
return [
|
|
116
|
+
weekdays[6],
|
|
117
|
+
...weekdays.slice(0, 6),
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public getDateNames(): string[] {
|
|
122
|
+
return Array.from({ length: 31 }, (_, index) => `${index + 1}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public toIso8601(date: number): string {
|
|
126
|
+
return this.fromTimestamp(date).toISO() ?? '';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public isEqual(dateLeft: number, dateRight: number): boolean {
|
|
130
|
+
if (!this.isValid(dateLeft) || !this.isValid(dateRight)) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return dateLeft === dateRight;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public isSameDay(dateLeft: number, dateRight: number): boolean {
|
|
138
|
+
if (!this.isValid(dateLeft) || !this.isValid(dateRight)) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return this.fromTimestamp(dateLeft).hasSame(
|
|
143
|
+
this.fromTimestamp(dateRight),
|
|
144
|
+
'day',
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public isValid(date: number): boolean {
|
|
149
|
+
return typeof date === 'number' && !Number.isNaN(date);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public invalid(): number {
|
|
153
|
+
return NaN;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public isDateInstance(obj: unknown): boolean {
|
|
157
|
+
return typeof obj === 'number';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public addCalendarYears(date: number, amount: number): number {
|
|
161
|
+
return this.fromTimestamp(date)
|
|
162
|
+
.plus({ years: Number(amount) })
|
|
163
|
+
.toMillis();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
public addCalendarMonths(date: number, amount: number): number {
|
|
167
|
+
return this.fromTimestamp(date)
|
|
168
|
+
.plus({ months: Number(amount) })
|
|
169
|
+
.toMillis();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public addCalendarDays(date: number, amount: number): number {
|
|
173
|
+
return this.fromTimestamp(date)
|
|
174
|
+
.plus({ days: Number(amount) })
|
|
175
|
+
.toMillis();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public setHours(date: number, amount: number): number {
|
|
179
|
+
return this.fromTimestamp(date)
|
|
180
|
+
.set({ hour: amount })
|
|
181
|
+
.toMillis();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public setMinutes(date: number, amount: number): number {
|
|
185
|
+
return this.fromTimestamp(date)
|
|
186
|
+
.set({ minute: amount })
|
|
187
|
+
.toMillis();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public setSeconds(date: number, amount: number): number {
|
|
191
|
+
return this.fromTimestamp(date)
|
|
192
|
+
.set({ second: amount })
|
|
193
|
+
.toMillis();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public createDate(
|
|
197
|
+
year: number,
|
|
198
|
+
month: number,
|
|
199
|
+
date: number,
|
|
200
|
+
hours = 0,
|
|
201
|
+
minutes = 0,
|
|
202
|
+
seconds = 0,
|
|
203
|
+
): number {
|
|
204
|
+
const result = DateTime.local(
|
|
205
|
+
year,
|
|
206
|
+
month + 1,
|
|
207
|
+
date,
|
|
208
|
+
hours,
|
|
209
|
+
minutes,
|
|
210
|
+
seconds,
|
|
211
|
+
0,
|
|
212
|
+
).setLocale(this.locale);
|
|
213
|
+
|
|
214
|
+
if (!result.isValid) {
|
|
215
|
+
throw Error(
|
|
216
|
+
`UnixTimestampDateTimeAdapter: Invalid date "${date}" for month with index "${month}".`,
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return result.toMillis();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public clone(date: number): number {
|
|
224
|
+
return date;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
public now(): number {
|
|
228
|
+
return DateTime.local()
|
|
229
|
+
.setLocale(this.locale)
|
|
230
|
+
.toMillis();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Hybrid formatter:
|
|
235
|
+
* - string => Luxon format, e.g. 'dd.MM.yyyy HH:mm'
|
|
236
|
+
* - Intl.DateTimeFormatOptions => old adapter-compatible formatting
|
|
237
|
+
*/
|
|
238
|
+
public format(
|
|
239
|
+
date: number,
|
|
240
|
+
displayFormat: string | Intl.DateTimeFormatOptions,
|
|
241
|
+
): string {
|
|
242
|
+
if (!this.isValid(date)) {
|
|
243
|
+
throw Error('UnixTimestampDateTimeAdapter: Cannot format invalid date.');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const dt = this.fromTimestamp(date);
|
|
247
|
+
|
|
248
|
+
if (typeof displayFormat === 'string') {
|
|
249
|
+
return dt.toFormat(displayFormat);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return this.stripDirectionalityCharacters(
|
|
253
|
+
dt.toJSDate().toLocaleDateString(this.locale, displayFormat),
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
public parse(value: unknown, parseFormat: string | string[] | null): number | null {
|
|
258
|
+
if (value == null || value === '') {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (typeof value === 'number') {
|
|
263
|
+
return this.isValid(value) ? value : this.invalid();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (value instanceof Date) {
|
|
267
|
+
const date = DateTime.fromJSDate(value).setLocale(this.locale);
|
|
268
|
+
|
|
269
|
+
return date.isValid ? date.toMillis() : this.invalid();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (DateTime.isDateTime(value)) {
|
|
273
|
+
return value.isValid
|
|
274
|
+
? value.setLocale(this.locale).toMillis()
|
|
275
|
+
: this.invalid();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (typeof value !== 'string') {
|
|
279
|
+
return this.invalid();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (parseFormat) {
|
|
283
|
+
const formats = Array.isArray(parseFormat) ? parseFormat : [parseFormat];
|
|
284
|
+
|
|
285
|
+
for (const format of formats) {
|
|
286
|
+
if (typeof format !== 'string') {
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const parsed = DateTime.fromFormat(value, format, {
|
|
291
|
+
locale: this.locale,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
if (parsed.isValid) {
|
|
295
|
+
return parsed.toMillis();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const iso = DateTime.fromISO(value, {
|
|
301
|
+
locale: this.locale,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
if (iso.isValid) {
|
|
305
|
+
return iso.toMillis();
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const jsDate = DateTime.fromJSDate(new Date(value)).setLocale(this.locale);
|
|
309
|
+
|
|
310
|
+
return jsDate.isValid ? jsDate.toMillis() : this.invalid();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
public override deserialize(value: unknown): number | null {
|
|
314
|
+
if (value == null || value === '') {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (typeof value === 'number') {
|
|
319
|
+
return this.isValid(value) ? value : this.invalid();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (value instanceof Date) {
|
|
323
|
+
const date = DateTime.fromJSDate(value).setLocale(this.locale);
|
|
324
|
+
|
|
325
|
+
return date.isValid ? date.toMillis() : this.invalid();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (DateTime.isDateTime(value)) {
|
|
329
|
+
return value.isValid
|
|
330
|
+
? value.setLocale(this.locale).toMillis()
|
|
331
|
+
: this.invalid();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (typeof value === 'string') {
|
|
335
|
+
const date = DateTime.fromISO(value, {
|
|
336
|
+
locale: this.locale,
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
return date.isValid ? date.toMillis() : this.invalid();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return this.invalid();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public override setLocale(locale: string): void {
|
|
346
|
+
super.setLocale(locale || 'ru');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private fromTimestamp(timestamp: number): DateTime {
|
|
350
|
+
return DateTime.fromMillis(timestamp).setLocale(this.locale);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private stripDirectionalityCharacters(value: string): string {
|
|
354
|
+
return value.replace(/[\u200e\u200f]/g, '');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* unix-timestamp-date-time-format.class
|
|
3
|
+
*/
|
|
4
|
+
import {OwlDateTimeFormats} from '../date-time-format.class';
|
|
5
|
+
|
|
6
|
+
export const OWL_UNIX_TIMESTAMP_DATE_TIME_FORMATS: OwlDateTimeFormats = {
|
|
7
|
+
parseInput: null,
|
|
8
|
+
fullPickerInput: {year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric'},
|
|
9
|
+
datePickerInput: {year: 'numeric', month: 'numeric', day: 'numeric'},
|
|
10
|
+
timePickerInput: {hour: 'numeric', minute: 'numeric'},
|
|
11
|
+
monthYearLabel: {year: 'numeric', month: 'short'},
|
|
12
|
+
dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
|
|
13
|
+
monthYearA11yLabel: {year: 'numeric', month: 'long'},
|
|
14
|
+
};
|