fix dst in time converter

This commit is contained in:
sbriat 2023-09-27 14:15:33 +02:00
parent 1a881572c2
commit 0661c72ed7
11 changed files with 149 additions and 321 deletions

View File

@ -30,4 +30,4 @@ SEATS_REQUESTED=1
STRICT_FREQUENCY=false
# default timezone
DEFAULT_TIMEZONE=Europe/Paris
TIMEZONE=Europe/Paris

View File

@ -5,5 +5,5 @@ export type DefaultParams = {
SEATS_REQUESTED: number;
DEPARTURE_TIME_MARGIN: number;
STRICT: boolean;
DEFAULT_TIMEZONE: string;
TIMEZONE: string;
};

View File

@ -15,6 +15,6 @@ export class DefaultParamsProvider implements DefaultParamsProviderPort {
this._configService.get('DEPARTURE_TIME_MARGIN'),
),
STRICT: this._configService.get('STRICT_FREQUENCY') == 'true',
DEFAULT_TIMEZONE: this._configService.get('DEFAULT_TIMEZONE'),
TIMEZONE: this._configService.get('DEFAULT_TIMEZONE'),
});
}

View File

@ -23,7 +23,7 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
private readonly timezoneFinder: TimezoneFinderPort,
@Inject(TIME_CONVERTER) private readonly timeConverter: TimeConverterPort,
) {
this._defaultTimezone = defaultParamsProvider.getParams().DEFAULT_TIMEZONE;
this._defaultTimezone = defaultParamsProvider.getParams().TIMEZONE;
}
/**
@ -79,7 +79,7 @@ export class InputDateTimeTransformer implements DateTimeTransformerPort {
this._defaultTimezone,
)[0],
);
return new Date(this.fromDate(geoFromDate, frequency)).getDay();
return new Date(this.fromDate(geoFromDate, frequency)).getUTCDay();
};
/**

View File

@ -66,7 +66,7 @@ export class OutputDateTimeTransformer implements DateTimeTransformerPort {
geoFromDate.coordinates.lat,
)[0],
);
return new Date(this.fromDate(geoFromDate, frequency)).getDay();
return new Date(this.fromDate(geoFromDate, frequency)).getUTCDay();
};
/**

View File

@ -6,91 +6,52 @@ import { TimeConverterPort } from '../core/application/ports/time-converter.port
export class TimeConverter implements TimeConverterPort {
private readonly UNIX_EPOCH = '1970-01-01';
localStringTimeToUtcStringTime = (time: string, timezone: string): string => {
try {
if (!time || !timezone) throw new Error();
return new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone(timezone))
.convert(TimeZone.zone('UTC'))
.format('HH:mm');
} catch (e) {
return undefined;
}
};
localStringTimeToUtcStringTime = (time: string, timezone: string): string =>
new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone(timezone))
.convert(TimeZone.zone('UTC'))
.format('HH:mm');
utcStringTimeToLocalStringTime = (time: string, timezone: string): string => {
try {
if (!time || !timezone) throw new Error();
return new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone))
.format('HH:mm');
} catch (e) {
return undefined;
}
};
utcStringTimeToLocalStringTime = (time: string, timezone: string): string =>
new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone))
.format('HH:mm');
localStringDateTimeToUtcDate = (
date: string,
time: string,
timezone: string,
dst = true,
): Date => {
try {
if (!date || !time || !timezone) throw new Error();
return new Date(
new DateTime(
`${date}T${time}`,
TimeZone.zone(timezone, dst),
).toIsoString(),
);
} catch (e) {
return undefined;
}
};
dst = false,
): Date =>
new Date(
new DateTime(
`${date}T${time}`,
TimeZone.zone(timezone, dst),
).toIsoString(),
);
utcStringDateTimeToLocalIsoString = (
date: string,
time: string,
timezone: string,
dst?: boolean,
): string => {
try {
if (!date || !time || !timezone) throw new Error();
return new DateTime(`${date}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone, dst))
.toIsoString();
} catch (e) {
return undefined;
}
};
dst = false,
): string =>
new DateTime(`${date}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone, dst))
.toIsoString();
utcUnixEpochDayFromTime = (time: string, timezone: string): number => {
try {
if (!time || !timezone) throw new Error();
return new Date(
new DateTime(
`${this.UNIX_EPOCH}T${time}`,
TimeZone.zone(timezone, false),
)
.convert(TimeZone.zone('UTC'))
.toIsoString()
.split('T')[0],
).getDay();
} catch (e) {
return undefined;
}
};
utcUnixEpochDayFromTime = (time: string, timezone: string): number =>
new Date(
new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone(timezone, false))
.convert(TimeZone.zone('UTC'))
.toIsoString()
.split('T')[0],
).getUTCDay();
localUnixEpochDayFromTime = (time: string, timezone: string): number => {
try {
if (!time || !timezone) throw new Error();
return new Date(
new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone))
.toIsoString()
.split('T')[0],
).getDay();
} catch (e) {
return undefined;
}
};
localUnixEpochDayFromTime = (time: string, timezone: string): number =>
new Date(
new DateTime(`${this.UNIX_EPOCH}T${time}`, TimeZone.zone('UTC'))
.convert(TimeZone.zone(timezone))
.toIsoString()
.split('T')[0],
).getUTCDay();
}

View File

@ -71,7 +71,7 @@ const mockDefaultParamsProvider: DefaultParamsProviderPort = {
PASSENGER: true,
SEATS_REQUESTED: 1,
STRICT: false,
DEFAULT_TIMEZONE: 'Europe/Paris',
TIMEZONE: 'Europe/Paris',
};
},
};

View File

@ -53,6 +53,6 @@ describe('DefaultParamsProvider', () => {
expect(params.DEPARTURE_TIME_MARGIN).toBe(900);
expect(params.PASSENGER).toBeTruthy();
expect(params.DRIVER).toBeFalsy();
expect(params.DEFAULT_TIMEZONE).toBe('Europe/Paris');
expect(params.TIMEZONE).toBe('Europe/Paris');
});
});

View File

@ -19,7 +19,7 @@ const mockDefaultParamsProvider: DefaultParamsProviderPort = {
PASSENGER: true,
SEATS_REQUESTED: 1,
STRICT: false,
DEFAULT_TIMEZONE: 'Europe/Paris',
TIMEZONE: 'Europe/Paris',
};
},
};

View File

@ -19,7 +19,7 @@ const mockDefaultParamsProvider: DefaultParamsProviderPort = {
PASSENGER: true,
SEATS_REQUESTED: 1,
STRICT: false,
DEFAULT_TIMEZONE: 'Europe/Paris',
TIMEZONE: 'Europe/Paris',
};
},
};

View File

@ -16,41 +16,12 @@ describe('Time Converter', () => {
);
expect(utcDatetime).toBe('07:00');
});
it('should return undefined if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisTime = '28:00';
const utcDatetime = timeConverter.localStringTimeToUtcStringTime(
parisTime,
'Europe/Paris',
);
expect(utcDatetime).toBeUndefined();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisTime = undefined;
const utcDatetime = timeConverter.localStringTimeToUtcStringTime(
parisTime,
'Europe/Paris',
);
expect(utcDatetime).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
it('should throw an error if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const fooBarTime = '08:00';
const utcDatetime = timeConverter.localStringTimeToUtcStringTime(
fooBarTime,
'Foo/Bar',
);
expect(utcDatetime).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const fooBarTime = '08:00';
const utcDatetime = timeConverter.localStringTimeToUtcStringTime(
fooBarTime,
undefined,
);
expect(utcDatetime).toBeUndefined();
expect(() => {
timeConverter.localStringTimeToUtcStringTime(fooBarTime, 'Foo/Bar');
}).toThrow();
});
});
@ -64,46 +35,24 @@ describe('Time Converter', () => {
);
expect(parisTime).toBe('08:00');
});
it('should return undefined if time is invalid', () => {
it('should throw an error if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '27:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
expect(() => {
timeConverter.utcStringTimeToLocalStringTime(utcTime, 'Europe/Paris');
}).toThrow();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = undefined;
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
it('should throw an error if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '07:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
'Foo/Bar',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcTime = '07:00';
const parisTime = timeConverter.utcStringTimeToLocalStringTime(
utcTime,
undefined,
);
expect(parisTime).toBeUndefined();
expect(() => {
timeConverter.utcStringTimeToLocalStringTime(utcTime, 'Foo/Bar');
}).toThrow();
});
});
describe('localStringDateTimeToUtcDate', () => {
it('should convert a summer paris date and time to a utc date', () => {
it('should convert a summer paris date and time to a utc date with dst', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-22';
const parisTime = '12:00';
@ -111,10 +60,11 @@ describe('Time Converter', () => {
parisDate,
parisTime,
'Europe/Paris',
true,
);
expect(utcDate.toISOString()).toBe('2023-06-22T10:00:00.000Z');
});
it('should convert a winter paris date and time to a utc date', () => {
it('should convert a winter paris date and time to a utc date with dst', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-02-02';
const parisTime = '12:00';
@ -122,6 +72,7 @@ describe('Time Converter', () => {
parisDate,
parisTime,
'Europe/Paris',
true,
);
expect(utcDate.toISOString()).toBe('2023-02-02T11:00:00.000Z');
});
@ -133,7 +84,6 @@ describe('Time Converter', () => {
parisDate,
parisTime,
'Europe/Paris',
false,
);
expect(utcDate.toISOString()).toBe('2023-06-22T11:00:00.000Z');
});
@ -159,75 +109,69 @@ describe('Time Converter', () => {
);
expect(utcDate.toISOString()).toBe('2023-02-03T01:00:00.000Z');
});
it('should return undefined if date is invalid', () => {
it('should throw an error if date is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-32';
const parisTime = '08:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
expect(utcDate).toBeUndefined();
expect(() => {
timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
}).toThrow();
});
it('should return undefined if date is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = undefined;
const parisTime = '08:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
expect(utcDate).toBeUndefined();
});
it('should return undefined if time is invalid', () => {
it('should throw an error if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-22';
const parisTime = '28:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
expect(utcDate).toBeUndefined();
expect(() => {
timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
}).toThrow();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-22';
const parisTime = undefined;
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Europe/Paris',
);
expect(utcDate).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
it('should throw an error if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-22';
const parisTime = '12:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Foo/Bar',
);
expect(utcDate).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const parisDate = '2023-06-22';
const parisTime = '12:00';
const utcDate = timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
undefined,
);
expect(utcDate).toBeUndefined();
expect(() => {
timeConverter.localStringDateTimeToUtcDate(
parisDate,
parisTime,
'Foo/Bar',
);
}).toThrow();
});
});
describe('utcStringDateTimeToLocalIsoString', () => {
it('should convert a utc string date and time to a summer paris date isostring with dst', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
true,
);
expect(localIsoString).toBe('2023-06-22T12:00:00.000+02:00');
});
it('should convert a utc string date and time to a winter paris date isostring with dst', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-02-02';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
true,
);
expect(localIsoString).toBe('2023-02-02T11:00:00.000+01:00');
});
it('should convert a utc string date and time to a summer paris date isostring', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
@ -237,29 +181,6 @@ describe('Time Converter', () => {
utcTime,
'Europe/Paris',
);
expect(localIsoString).toBe('2023-06-22T12:00:00.000+02:00');
});
it('should convert a utc string date and time to a winter paris date isostring', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-02-02';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(localIsoString).toBe('2023-02-02T11:00:00.000+01:00');
});
it('should convert a utc string date and time to a summer paris date isostring without dst', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '10:00';
const localIsoString = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
false,
);
expect(localIsoString).toBe('2023-06-22T11:00:00.000+01:00');
});
it('should convert a utc date to a tonga date isostring', () => {
@ -284,71 +205,41 @@ describe('Time Converter', () => {
);
expect(localIsoString).toBe('2023-02-02T15:00:00.000-10:00');
});
it('should return undefined if date is invalid', () => {
it('should throw an error if date is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-32';
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
expect(() => {
timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
}).toThrow();
});
it('should return undefined if date is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = undefined;
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if time is invalid', () => {
it('should throw an error if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '27:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
expect(() => {
timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
}).toThrow();
});
it('should return undefined if time is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = undefined;
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Europe/Paris',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
it('should throw an error if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Foo/Bar',
);
expect(parisTime).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
const utcDate = '2023-06-22';
const utcTime = '07:00';
const parisTime = timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
undefined,
);
expect(parisTime).toBeUndefined();
expect(() => {
timeConverter.utcStringDateTimeToLocalIsoString(
utcDate,
utcTime,
'Foo/Bar',
);
}).toThrow();
});
});
@ -371,29 +262,17 @@ describe('Time Converter', () => {
timeConverter.utcUnixEpochDayFromTime('16:00', 'Pacific/Tahiti'),
).toBe(5);
});
it('should return undefined if time is invalid', () => {
it('should throw an error if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.utcUnixEpochDayFromTime('28:00', 'Europe/Paris'),
).toBeUndefined();
expect(() => {
timeConverter.utcUnixEpochDayFromTime('28:00', 'Europe/Paris');
}).toThrow();
});
it('should return undefined if time is undefined', () => {
it('should throw an error if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.utcUnixEpochDayFromTime(undefined, 'Europe/Paris'),
).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.utcUnixEpochDayFromTime('12:00', 'Foo/Bar'),
).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.utcUnixEpochDayFromTime('12:00', undefined),
).toBeUndefined();
expect(() => {
timeConverter.utcUnixEpochDayFromTime('12:00', 'Foo/Bar');
}).toThrow();
});
});
@ -416,29 +295,17 @@ describe('Time Converter', () => {
timeConverter.localUnixEpochDayFromTime('05:00', 'Pacific/Tahiti'),
).toBe(3);
});
it('should return undefined if time is invalid', () => {
it('should throw an error if time is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('28:00', 'Europe/Paris'),
).toBeUndefined();
expect(() => {
timeConverter.localUnixEpochDayFromTime('28:00', 'Europe/Paris');
}).toThrow();
});
it('should return undefined if time is undefined', () => {
it('should throw an error if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime(undefined, 'Europe/Paris'),
).toBeUndefined();
});
it('should return undefined if timezone is invalid', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('12:00', 'Foo/Bar'),
).toBeUndefined();
});
it('should return undefined if timezone is undefined', () => {
const timeConverter: TimeConverter = new TimeConverter();
expect(
timeConverter.localUnixEpochDayFromTime('12:00', undefined),
).toBeUndefined();
expect(() => {
timeConverter.localUnixEpochDayFromTime('12:00', 'Foo/Bar');
}).toThrow();
});
});
});