Skip to content

Commit 12c2e01

Browse files
committed
[WIP] Migrate from moment to Luxon
1 parent a9d89e5 commit 12c2e01

File tree

61 files changed

+522
-571
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+522
-571
lines changed

frontend/src/app/core/config/configuration.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
//++
2828

2929
import { Injectable } from '@angular/core';
30-
import moment from 'moment';
30+
import { Settings } from 'luxon';
3131

3232
import { ConfigurationResource } from 'core-app/features/hal/resources/configuration-resource';
3333
import { ApiV3Service } from 'core-app/core/apiv3/api-v3.service';
@@ -139,7 +139,7 @@ export class ConfigurationService {
139139
if (this.startOfWeekPresent()) {
140140
return this.systemPreference('startOfWeek');
141141
}
142-
return moment.localeData(I18n.locale).firstDayOfWeek();
142+
return Settings.defaultWeekSettings?.firstDay || 0;
143143
}
144144

145145
public get hostName():string {

frontend/src/app/core/datetime/timezone.service.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,13 @@ describe('TimezoneService', () => {
6868
describe('#parseDatetime', () => {
6969
it('is UTC', () => {
7070
const time = timezoneService.parseDatetime(TIME);
71-
expect(time.utcOffset()).toEqual(0);
72-
expect(time.format('HH:mm')).toEqual('09:30');
71+
expect(time.offset).toEqual(0);
72+
expect(time.toFormat('HH:mm')).toEqual('09:30');
7373
});
7474

7575
it('has no time information', () => {
7676
const time = timezoneService.parseDate(DATE);
77-
expect(time.format('HH:mm')).toEqual('00:00');
77+
expect(time.toFormat('HH:mm')).toEqual('00:00');
7878
});
7979
});
8080
});
@@ -87,7 +87,7 @@ describe('TimezoneService', () => {
8787
describe('Non-UTC timezone', () => {
8888
it('is in the given timezone', () => {
8989
const date = timezoneService.parseDatetime(TIME);
90-
expect(date.format('HH:mm')).toEqual('01:30');
90+
expect(date.toFormat('HH:mm')).toEqual('01:30');
9191
});
9292

9393
it('has local time zone', () => {

frontend/src/app/core/datetime/timezone.service.ts

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
import { Injectable } from '@angular/core';
3030
import { ConfigurationService } from 'core-app/core/config/configuration.service';
3131
import { I18nService } from 'core-app/core/i18n/i18n.service';
32-
import moment, { Moment } from 'moment-timezone';
32+
import { DateTime, Duration, DurationUnit, Settings } from 'luxon';
3333
import { outputChronicDuration } from '../../shared/helpers/chronic_duration';
34+
import { toDateTime } from 'core-app/shared/helpers/date-time-helpers';
3435

3536
@Injectable({ providedIn: 'root' })
3637
export class TimezoneService {
@@ -43,21 +44,19 @@ export class TimezoneService {
4344
* Returns the user's configured timezone or guesses it through moment
4445
*/
4546
public userTimezone():string {
46-
return this.configurationService.isTimezoneSet() ? this.configurationService.timezone() : moment.tz.guess();
47+
return this.configurationService.isTimezoneSet() ? this.configurationService.timezone() : Settings.defaultZone.name;
4748
}
4849

4950
/**
5051
* Takes a utc date time string and turns it into
5152
* a local date time moment object.
5253
*/
53-
public parseDatetime(datetime:string, format?:string):Moment {
54-
return moment
55-
.utc(datetime, format)
56-
.tz(this.userTimezone());
54+
public parseDatetime(datetime:string):DateTime {
55+
return DateTime.fromISO(datetime).setZone(this.userTimezone());
5756
}
5857

59-
public parseDate(date:Date|string, format?:string):Moment {
60-
return moment(date, format);
58+
public parseDate(date:DateTime|Date|string):DateTime {
59+
return toDateTime(date);
6160
}
6261

6362
/**
@@ -66,19 +65,18 @@ export class TimezoneService {
6665
* This will effectfully transform the [server] provided datetime object to the user's configured local timezone.
6766
*
6867
* @param {String} datetime in 'YYYY-MM-DDTHH:mm:ssZ' format
69-
* @returns {Moment}
68+
* @returns {DateTime}
7069
*/
71-
public parseISODatetime(datetime:string):Moment {
72-
return this.parseDatetime(datetime, 'YYYY-MM-DDTHH:mm:ssZ');
70+
public parseISODatetime(datetime:string):DateTime {
71+
return this.parseDatetime(datetime);
7372
}
7473

75-
public parseISODate(date:string):Moment {
76-
return this.parseDate(date, 'YYYY-MM-DD');
74+
public parseISODate(date:string):DateTime {
75+
return DateTime.fromISO(date);
7776
}
7877

7978
public formattedDate(date:string, format = this.getDateFormat()):string {
80-
const d = this.parseDate(date);
81-
return d.format(format);
79+
return DateTime.fromISO(date).toLocaleString(format);
8280
}
8381

8482
/**
@@ -87,14 +85,14 @@ export class TimezoneService {
8785
* @param dateString
8886
*/
8987
public daysFromToday(dateString:string):number {
90-
const date = this.parseDate(dateString);
91-
const today = moment().startOf('day');
88+
const dt = DateTime.fromISO(dateString);
89+
const today = DateTime.now().startOf('day');
9290

93-
return date.diff(today, 'days');
91+
return dt.diff(today, 'days').days;
9492
}
9593

96-
public formattedTime(datetimeString:string, format?:string):string {
97-
return this.parseDatetime(datetimeString).format(format || this.getTimeFormat());
94+
public formattedTime(datetimeString:string, format = this.getTimeFormat()):string {
95+
return this.parseDatetime(datetimeString).toLocaleString(format);
9896
}
9997

10098
public formattedDatetime(datetimeString:string):string {
@@ -103,40 +101,40 @@ export class TimezoneService {
103101
}
104102

105103
public formattedRelativeDateTime(datetimeString:string):string {
106-
const d = this.parseDatetime(datetimeString);
107-
return d.fromNow();
104+
const dt = this.parseDatetime(datetimeString);
105+
return dt.toRelative() || '';
108106
}
109107

110-
public formattedDatetimeComponents(datetimeString:string):string[] {
111-
const d = this.parseDatetime(datetimeString);
108+
public formattedDatetimeComponents(datetimeString:string):[string, string] {
109+
const dt = this.parseDatetime(datetimeString);
112110
return [
113-
d.format(this.getDateFormat()),
114-
d.format(this.getTimeFormat()),
111+
dt.toLocaleString(this.getDateFormat()),
112+
dt.toLocaleString(this.getTimeFormat()),
115113
];
116114
}
117115

118116
public toSeconds(durationString:string):number {
119-
return Number(moment.duration(durationString).asSeconds().toFixed(2));
117+
return Number(Duration.fromISO(durationString).seconds.toFixed(2));
120118
}
121119

122120
public toHours(durationString:string):number {
123-
return Number(moment.duration(durationString).asHours().toFixed(2));
121+
return Number(Duration.fromISO(durationString).hours.toFixed(2));
124122
}
125123

126124
public toDays(durationString:string):number {
127-
return Number(moment.duration(durationString).asDays().toFixed(2));
125+
return Number(Duration.fromISO(durationString).days.toFixed(2));
128126
}
129127

130-
public toISODuration(input:string|number, unit:'hours'|'days'):string {
131-
return moment.duration(input, unit).toISOString();
128+
public toISODuration(input:string|number, unit:DurationUnit):string {
129+
return Duration.fromObject({ [unit]: input }).toISO();
132130
}
133131

134132
public utcDateToLocalDate(date:Date):Date {
135133
return new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000);
136134
}
137135

138136
public utcDateToISODateString(date:Date):string {
139-
return moment.utc(date).format('YYYY-MM-DD');
137+
return DateTime.fromJSDate(date).toUTC().toISODate() || '';
140138
}
141139

142140
public utcDatesToISODateStrings(dates:Date[]):string[] {
@@ -170,32 +168,29 @@ export class TimezoneService {
170168
return outputChronicDuration(seconds, opts) || '0h';
171169
}
172170

173-
public formattedISODate(date:any):string {
174-
return this.parseDate(date).format('YYYY-MM-DD');
171+
public formattedISODate(date:DateTime|Date|string):string {
172+
return this.parseDate(date).toISODate() || '';
175173
}
176174

177-
public formattedISODateTime(datetime:any):string {
178-
return datetime.format();
175+
public formattedISODateTime(datetime:DateTime):string {
176+
return datetime.toISO() || '';
179177
}
180178

181-
public isValidISODate(date:any):boolean {
182-
return this.isValid(date, 'YYYY-MM-DD');
179+
public isValidISODate(date:string):boolean {
180+
return DateTime.fromISO(date).isValid;
183181
}
184182

185183
public isValidISODateTime(dateTime:string):boolean {
186-
return this.isValid(dateTime, 'YYYY-MM-DDTHH:mm:ssZ');
184+
return DateTime.fromISO(dateTime).isValid;
187185
}
188186

189-
public isValid(date:string, dateFormat:string):boolean {
190-
const format = dateFormat || this.getDateFormat();
191-
return moment(date, [format], true).isValid();
187+
public getDateFormat():Intl.DateTimeFormatOptions {
188+
//return this.configurationService.dateFormatPresent() ? this.configurationService.dateFormat() :
189+
return DateTime.DATE_SHORT;
192190
}
193191

194-
public getDateFormat():string {
195-
return this.configurationService.dateFormatPresent() ? this.configurationService.dateFormat() : 'L';
196-
}
197-
198-
public getTimeFormat():string {
199-
return this.configurationService.timeFormatPresent() ? this.configurationService.timeFormat() : 'LT';
192+
public getTimeFormat():Intl.DateTimeFormatOptions {
193+
//return this.configurationService.timeFormatPresent() ? this.configurationService.timeFormat() :
194+
return DateTime.TIME_SIMPLE;
200195
}
201196
}

frontend/src/app/core/days/weekday.service.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
Injectable,
3131
Injector,
3232
} from '@angular/core';
33-
import moment, { Moment } from 'moment';
33+
import { DateTime } from 'luxon';
3434
import {
3535
take,
3636
tap,
@@ -57,8 +57,13 @@ export class WeekdayService {
5757
* @param date The iso day number (1-7) or a date instance
5858
* @return {boolean} whether the given iso day is working or not
5959
*/
60-
public isNonWorkingDay(date:Moment|Date|number):boolean {
61-
const isoDayOfWeek = (typeof date === 'number') ? date : moment(date).isoWeekday();
60+
public isNonWorkingDay(date:DateTime|Date|number):boolean {
61+
const isoDayOfWeek = (typeof date === 'number')
62+
? date
63+
: (date instanceof DateTime)
64+
? date.weekday
65+
: DateTime.fromJSDate(date).weekday;
66+
6267
return !!(this.weekdays || []).find((wd) => wd.day === isoDayOfWeek && !wd.working);
6368
}
6469

frontend/src/app/core/setup/init-locale.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
// See COPYRIGHT and LICENSE files for more details.
2727
//++
2828

29-
import moment from 'moment';
29+
import { Settings } from 'luxon';
3030
import { I18n } from 'i18n-js';
3131

3232
export function initializeLocale() {
@@ -43,22 +43,7 @@ export function initializeLocale() {
4343

4444
window.I18n = i18n;
4545

46-
moment.locale(userLocale);
47-
48-
// Remove Postformatting numbers in dates, this will ensure we are always using
49-
// Arabic numbers in dates and durations, regardless of the chosen locale.
50-
// Using moment.locale() ensures locale like "zh-CN" falls back to "zh-cn"
51-
moment.updateLocale(moment.locale(), { postformat: (string:string) => string });
52-
53-
if (!Number.isNaN(firstDayOfWeek) && !Number.isNaN(firstWeekOfYear)) {
54-
// ensure locale like "zh-CN" falls back to "zh-cn"
55-
moment.updateLocale(moment.locale(), {
56-
week: {
57-
dow: firstDayOfWeek,
58-
doy: 7 + firstDayOfWeek - firstWeekOfYear,
59-
},
60-
});
61-
}
46+
Settings.defaultLocale = userLocale;
6247

6348
// Override the default pluralization function to allow
6449
// "other" to be used as a fallback for "one" in languages where one is not set

frontend/src/app/core/setup/init-moment-locales.ts

Lines changed: 0 additions & 88 deletions
This file was deleted.

frontend/src/app/core/setup/init-vendors.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,10 @@ import 'jquery-ujs';
4444
// import 'jquery-ui/ui/widgets/tooltip';
4545
import 'core-vendor/jquery-ui-1.14.1/jquery-ui';
4646

47-
import moment from 'moment';
48-
import './init-moment-locales';
49-
5047
import 'jquery.caret';
5148
// Text highlight for autocompleter
5249
import 'mark.js/dist/jquery.mark.min';
5350

54-
import 'moment-timezone/builds/moment-timezone-with-data.min';
5551
// eslint-disable-next-line import/extensions,import/no-extraneous-dependencies
5652
import '@openproject/primer-view-components/app/assets/javascripts/primer_view_components.js';
5753

@@ -65,5 +61,4 @@ declare global {
6561
}
6662

6763
window._ = lodash;
68-
window.moment = moment;
6964
window.URI = URI;

0 commit comments

Comments
 (0)