1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-20 14:54:15 +01:00

(bug) invalid event date in negative TZ

This commit is contained in:
Sylvain 2023-01-13 12:15:48 +01:00
parent f2a21e444f
commit 921b5eab2f
5 changed files with 88 additions and 12 deletions

View File

@ -3,6 +3,7 @@
- Add more context data to sentry reports
- Improved SSO testing
- Fix a bug: unable to run task fix_invoice_item when some invoice items are associated with errors
- Fix a bug: invalid event date reported when the timezone in before UTC
- [TODO DEPLOY] `rails fablab:fix:invoice_items_in_error` THEN `rails fablab:fix_invoice_items` THEN `rails db:migrate`
## v5.6.5 2023 January 9

View File

@ -1,6 +1,6 @@
import moment, { unitOfTime } from 'moment';
import { IFablab } from '../models/fablab';
import { TDateISO, TDateISODate, THours, TMinutes } from '../typings/date-iso';
import { TDateISO, TDateISODate, TDateISOShortTime } from '../typings/date-iso';
declare let Fablab: IFablab;
@ -17,7 +17,15 @@ export default class FormatLib {
*/
static isDateISO = (value: string): boolean => {
if (typeof value !== 'string') return false;
return !!value?.match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\d\d\d/);
return !!value?.match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d/);
};
/**
* Check if the provided variable is string representing a short date, according to ISO 8601 (e.g. 2023-01-12)
*/
static isShortDateISO = (value: string): boolean => {
if (typeof value !== 'string') return false;
return !!value.match(/^\d\d\d\d-\d\d-\d\d$/);
};
/**
@ -32,7 +40,36 @@ export default class FormatLib {
* Return the formatted localized date for the given date
*/
static date = (date: Date|TDateISO|TDateISODate): string => {
return Intl.DateTimeFormat().format(moment(date).toDate());
let tempDate: Date;
if (FormatLib.isShortDateISO(date as string) || FormatLib.isDateISO(date as string)) {
tempDate = FormatLib.parseISOdate(date as TDateISO);
} else {
tempDate = moment(date).toDate();
}
return Intl.DateTimeFormat(Fablab.intl_locale).format(tempDate);
};
/**
* Parse the provided datetime or date string (as ISO8601 format) and return the equivalent Date object
*/
private static parseISOdate = (date: TDateISO|TDateISODate, res: Date = new Date()): Date => {
const isoDateMatch = (date as string)?.match(/^(\d\d\d\d)-(\d\d)-(\d\d)/);
res.setFullYear(parseInt(isoDateMatch[1], 10));
res.setMonth(parseInt(isoDateMatch[2], 10) - 1);
res.setDate(parseInt(isoDateMatch[3], 10));
return res;
};
/**
* Parse the provided datetime or time string (as ISO8601 format) and return the equivalent Date object
*/
private static parseISOtime = (date: TDateISO|TDateISOShortTime, res: Date = new Date()): Date => {
const isoTimeMatch = (date as string)?.match(/(^|T)(\d\d):(\d\d)/);
res.setHours(parseInt(isoTimeMatch[2], 10));
res.setMinutes(parseInt(isoTimeMatch[3], 10));
return res;
};
/**
@ -45,13 +82,10 @@ export default class FormatLib {
/**
* Return the formatted localized time for the given date
*/
static time = (date: Date|TDateISO|`${THours}:${TMinutes}`): string => {
static time = (date: Date|TDateISO|TDateISOShortTime): string => {
let tempDate: Date;
if (FormatLib.isShortTimeISO(date as string)) {
const isoTimeMatch = (date as string)?.match(/^(\d\d):(\d\d)$/);
tempDate = new Date();
tempDate.setHours(parseInt(isoTimeMatch[1], 10));
tempDate.setMinutes(parseInt(isoTimeMatch[2], 10));
if (FormatLib.isShortTimeISO(date as string) || FormatLib.isDateISO(date as string)) {
tempDate = FormatLib.parseISOtime(date as TDateISOShortTime);
} else {
tempDate = moment(date).toDate();
}

View File

@ -1,4 +1,4 @@
// from https://gist.github.com/MrChocolatine/367fb2a35d02f6175cc8ccb3d3a20054
// inspired from https://gist.github.com/MrChocolatine/367fb2a35d02f6175cc8ccb3d3a20054
type TYear = `${number}${number}${number}${number}`;
type TMonth = `${number}${number}`;
@ -13,10 +13,15 @@ type TMilliseconds = `${number}${number}${number}`;
*/
type TDateISODate = `${TYear}-${TMonth}-${TDay}`;
/**
* Represent a string like `14:42`
*/
type TDateISOShortTime = `${THours}:${TMinutes}`;
/**
* Represent a string like `14:42:34.678`
*/
type TDateISOTime = `${THours}:${TMinutes}:${TSeconds}`|`${THours}:${TMinutes}:${TSeconds}.${TMilliseconds}`;
type TDateISOTime = `${TDateISOShortTime}:${TSeconds}`|`${TDateISOShortTime}:${TSeconds}.${TMilliseconds}`;
/**
* Represent a timezone like `+0100`

View File

@ -0,0 +1,36 @@
import FormatLib from 'lib/format';
import { IFablab } from 'models/fablab';
declare const Fablab: IFablab;
describe('FormatLib', () => {
test('format a date', () => {
Fablab.intl_locale = 'fr-FR';
const str = FormatLib.date(new Date('2023-01-12T12:00:00+0100'));
expect(str).toBe('12/01/2023');
});
test('format an iso8601 short date', () => {
Fablab.intl_locale = 'fr-FR';
const str = FormatLib.date('2023-01-12');
expect(str).toBe('12/01/2023');
});
test('format an iso8601 date', () => {
Fablab.intl_locale = 'fr-CA';
const str = FormatLib.date('2023-01-12T23:59:14-0500');
expect(str).toBe('2023-01-12');
});
test('format a time', () => {
Fablab.intl_locale = 'fr-FR';
const str = FormatLib.time(new Date('2023-01-12T23:59:14+0100'));
expect(str).toBe('23:59');
});
test('format an iso8601 short time', () => {
Fablab.intl_locale = 'fr-FR';
const str = FormatLib.time('23:59');
expect(str).toBe('23:59');
});
test('format an iso8601 time', () => {
Fablab.intl_locale = 'fr-CA';
const str = FormatLib.time('2023-01-12T23:59:14-0500');
expect(str).toBe('23 h 59');
});
});

View File

@ -2,7 +2,7 @@
"references": [
{ "path": "../../" }
],
"include": ["components/**/*", "__fixtures__/**/*", "__lib__/**/*"],
"include": ["components/**/*", "lib/**/*", "__fixtures__/**/*", "__lib__/**/*"],
"compilerOptions": {
"jsx": "react-jsx",
"target": "ES2015",