Skip to content

Commit

Permalink
Extract date operations to utility functions
Browse files Browse the repository at this point in the history
Drop converting migrationStarted and migrationCompleted to UTC in the
data transformation layer.

Signed-off-by: Radoslaw Szwajkowski <rszwajko@redhat.com>
  • Loading branch information
rszwajko committed Oct 11, 2023
1 parent 483d74c commit 0c27879
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 45 deletions.
21 changes: 9 additions & 12 deletions packages/common/src/components/Filter/DateFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { FormEvent, useState } from 'react';
import { DateTime } from 'luxon';

import { DatePicker, InputGroup, ToolbarFilter } from '@patternfly/react-core';

import { changeFormatToISODate, isValidDate, parseISOtoJSDate, toISODate } from '../../utils';

import { FilterTypeProps } from './types';

/**
Expand All @@ -23,14 +24,10 @@ export const DateFilter = ({
placeholderLabel,
showFilter = true,
}: FilterTypeProps) => {
const validFilters =
selectedFilters
?.map((str) => DateTime.fromISO(str))
?.filter((dt: DateTime) => dt.isValid)
?.map((dt: DateTime) => dt.toISODate()) ?? [];
const validFilters = selectedFilters?.map(changeFormatToISODate)?.filter(Boolean) ?? [];

// internal state - stored as ISO date string (no time)
const [date, setDate] = useState(DateTime.now().toISODate());
const [date, setDate] = useState(toISODate(new Date()));

const clearSingleDate = (option) => {
onFilterUpdate([...validFilters.filter((d) => d !== option)]);
Expand All @@ -40,8 +37,8 @@ export const DateFilter = ({
// require full format "YYYY-MM-DD" although partial date is also accepted
// i.e. YYYY-MM gets parsed as YYYY-MM-01 and results in auto completing the date
// unfortunately due to auto-complete user cannot delete the date char after char
if (value?.length === 10 && DateTime.fromISO(value).isValid) {
const targetDate = DateTime.fromISO(value).toISODate();
if (value?.length === 10 && isValidDate(value)) {
const targetDate = changeFormatToISODate(value);
setDate(targetDate);
onFilterUpdate([...validFilters.filter((d) => d !== targetDate), targetDate]);
}
Expand All @@ -58,9 +55,9 @@ export const DateFilter = ({
>
<InputGroup>
<DatePicker
value={DateTime.fromISO(date).toISODate()}
dateFormat={(date) => DateTime.fromJSDate(date).toISODate()}
dateParse={(str) => DateTime.fromISO(str).toJSDate()}
value={date}
dateFormat={toISODate}
dateParse={parseISOtoJSDate}
onChange={onDateChange}
aria-label={title}
placeholder={placeholderLabel}
Expand Down
6 changes: 2 additions & 4 deletions packages/common/src/components/FilterGroup/matchers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import jsonpath from 'jsonpath';
import { DateTime } from 'luxon';

import { ResourceField } from '../../utils';
import { areSameDayInUTCZero, ResourceField } from '../../utils';
import { DateFilter, EnumFilter, FreetextFilter, GroupedEnumFilter, SwitchFilter } from '../Filter';

import { FilterRenderer, ValueMatcher } from './types';
Expand Down Expand Up @@ -99,8 +98,7 @@ const groupedEnumMatcher = {

const dateMatcher = {
filterType: 'date',
matchValue: (value: string) => (filter: string) =>
DateTime.fromISO(value).toUTC().hasSame(DateTime.fromISO(filter).toUTC(), 'day'),
matchValue: (value: string) => (filter: string) => areSameDayInUTCZero(value, filter),
};

const sliderMatcher = {
Expand Down
81 changes: 81 additions & 0 deletions packages/common/src/utils/__tests__/dates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {
areSameDayInUTCZero,
changeFormatToISODate,
changeTimeZoneToUTCZero,
isValidDate,
parseISOtoJSDate,
toISODate,
} from '../dates';

describe('changeTimeZoneToUTCZero', () => {
test('from UTC+02:00', () => {
expect(changeTimeZoneToUTCZero('2023-10-31T01:30:00.000+02:00')).toBe(
'2023-10-30T23:30:00.000Z',
);
});
test('invalid input', () => {
expect(changeTimeZoneToUTCZero('2023-broken-10-31T01:30:00.000+02:00')).toBe(undefined);
});
});

describe('changeFormatToISODate', () => {
test('from ISO date time with zone', () => {
expect(changeFormatToISODate('2023-10-31T01:30:00.000+02:00')).toBe('2023-10-31');
});
test('invalid input', () => {
expect(changeFormatToISODate('2023-broken-10-31T01:30:00.000+02:00')).toBe(undefined);
});
});

describe('toISODate', () => {
test('unix epoch', () => {
expect(toISODate(new Date(0))).toBe('1970-01-01');
});
test('missing date', () => {
expect(toISODate(undefined)).toBe(undefined);
});
test('invalid date', () => {
expect(toISODate(new Date('foo'))).toBe(undefined);
});
});

describe('isValidDate', () => {
test('2023-10-31T01:30:00.000+02:00', () => {
expect(isValidDate('2023-10-31T01:30:00.000+02:00')).toBeTruthy();
});
test('invalid string', () => {
expect(isValidDate('2023-broken-10-31')).toBeFalsy();
});
test('invalid number of days', () => {
expect(isValidDate('2023-10-60')).toBeFalsy();
});
});

describe('parseISOtoJSDate', () => {
test('2023-10-31T01:30:00.000+02:00', () => {
const date = parseISOtoJSDate('2023-10-31T01:30:00.000+02:00');
expect(date.toUTCString()).toBe('Mon, 30 Oct 2023 23:30:00 GMT');
});
test('invalid input', () => {
expect(parseISOtoJSDate('2023-broken-10-31T01:30:00.000+02:00')).toBe(undefined);
});
});

describe('areSameDayInUTCZero', () => {
test('the same date', () => {
expect(
areSameDayInUTCZero('2023-10-31T01:30:00.000+02:00', '2023-10-29T23:30:00.000-02:00'),
).toBeTruthy();
});
test('the different dates', () => {
expect(
areSameDayInUTCZero('2023-10-31T10:00:00.000+02:00', '2023-10-29T14:00:00.000-02:00'),
).toBeFalsy();
});
test('one date invalid', () => {
expect(areSameDayInUTCZero('2023-10-31T10:00:00.000+02:00', '2023-foo')).toBeFalsy();
});
test('one date missing, one invalid', () => {
expect(areSameDayInUTCZero(undefined, '2023-foo')).toBeFalsy();
});
});
51 changes: 47 additions & 4 deletions packages/common/src/utils/dates.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,55 @@
import { DateTime } from 'luxon';

/**
* Converts a given ISO date string in a known format and timezone to a UTC ISO string.
* Converts a given ISO date time string to UTC+00:00 time zone.
*
* @param {string} isoDateString - The ISO date string in a known format and timezone.
* @returns {string} The equivalent UTC ISO string if date is valid or undefined otherwise.
* @param {string} isoDateString - The ISO date time string
* @returns {string} The equivalent UTC+00:00 date time ISO string if input is valid or undefined otherwise.
*/
export function convertToUTC(isoDateString: string): string | undefined {
export function changeTimeZoneToUTCZero(isoDateString: string): string | undefined {
const date = DateTime.fromISO(isoDateString);
return date.isValid ? date.toUTC().toISO() : undefined;
}

/**
* Converts a given ISO date time string to ISO date string(no time).
*
* @param {string} isoDateString - The ISO date time string
* @returns {string} The equivalent ISO date string if input is valid or undefined otherwise.
*/
export const changeFormatToISODate = (isoDateString: string): string | undefined => {
// preserve the original zone
const date = DateTime.fromISO(isoDateString, { setZone: true, zone: 'utc' });
return date.isValid ? date.toISODate() : undefined;
};

/**
* Prints JS Date instance as ISO date format (no time)
* @param date
* @returns ISO date string if input is valid or undefined otherwise.
*/
export const toISODate = (date: Date): string => {
const dt = DateTime.fromJSDate(date);
return dt.isValid ? dt.toISODate() : undefined;
};

export const isValidDate = (isoDateString: string) => DateTime.fromISO(isoDateString).isValid;

/**
*
* @param isoDateString
* @returns JS Date instance if input is valid or undefined otherwise.
*/
export const parseISOtoJSDate = (isoDateString: string) => {
const date = DateTime.fromISO(isoDateString);
return date.isValid ? date.toJSDate() : undefined;
};

/**
*
* @param a ISO date(time) formatted string
* @param b ISO date(time) formatted string
* @returns true if both dates are on the same day in UTC+00:00
*/
export const areSameDayInUTCZero = (a: string, b: string): boolean =>
DateTime.fromISO(a).toUTC().hasSame(DateTime.fromISO(b).toUTC(), 'day');
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ exports[`Plan rows plantest-01 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -433,7 +433,7 @@ exports[`Plan rows plantest-03 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -644,7 +644,7 @@ exports[`Plan rows plantest-04 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -855,7 +855,7 @@ exports[`Plan rows plantest-05 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -1215,7 +1215,7 @@ exports[`Plan rows plantest-07 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -1381,7 +1381,7 @@ exports[`Plan rows plantest-08 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -1548,7 +1548,7 @@ exports[`Plan rows plantest-09 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -1739,7 +1739,7 @@ exports[`Plan rows plantest-10 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down Expand Up @@ -1950,7 +1950,7 @@ exports[`Plan rows plantest-11 1`] = `
<div
data-test-element-name="Timestamp"
>
2020-10-10T14:04:10.000Z
2020-10-10T14:04:10Z
</div>
</td>
<td
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"status": "PipelineRunning",
"vmCount": 2,
"vmDone": 0,
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -342,7 +342,7 @@
"status": "Finished-Failed",
"vmCount": 4,
"vmDone": 1,
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -641,8 +641,8 @@
"status": "Finished-Succeeded",
"vmCount": 1,
"vmDone": 1,
"migrationCompleted": "2020-10-10T15:58:43.000Z",
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationCompleted": "2020-10-10T15:58:43Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -810,7 +810,7 @@
"status": "Archived",
"vmCount": 2,
"vmDone": 0,
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -1122,7 +1122,7 @@
"status": "Copying",
"vmCount": 3,
"vmDone": 0,
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -1406,7 +1406,7 @@
"status": "Copying-CutoverScheduled",
"vmCount": 3,
"vmDone": 0,
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {
"cutover": "2023-01-18T05:27:28.820Z"
},
Expand Down Expand Up @@ -1692,7 +1692,7 @@
"status": "PipelineRunning",
"vmCount": 3,
"vmDone": 1,
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {
"cutover": "2021-03-16T18:31:30Z"
},
Expand Down Expand Up @@ -1991,8 +1991,8 @@
"status": "Copying-Failed",
"vmCount": 3,
"vmDone": 0,
"migrationCompleted": "2020-10-10T15:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationCompleted": "2020-10-10T15:04:10Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -2168,8 +2168,8 @@
"status": "Finished-Incomplete",
"vmCount": 2,
"vmDone": 1,
"migrationCompleted": "2020-10-10T15:04:10.000Z",
"migrationStarted": "2020-10-10T14:04:10.000Z",
"migrationCompleted": "2020-10-10T15:04:10Z",
"migrationStarted": "2020-10-10T14:04:10Z",
"latestMigration": {},
"object": {
"apiVersion": "forklift.konveyor.io/v1beta1",
Expand Down Expand Up @@ -2346,4 +2346,4 @@
}
}
}
]
]
Loading

0 comments on commit 0c27879

Please sign in to comment.