Convert dates to use luxon.js

This commit is contained in:
Kia Lam 2021-07-22 12:12:35 -04:00
parent f6104dd438
commit 304ec80d80
15 changed files with 148 additions and 163 deletions

View File

@ -21,6 +21,7 @@
"has-ansi": "4.0.0",
"html-entities": "2.3.2",
"js-yaml": "^3.13.1",
"luxon": "^2.0.1",
"prop-types": "^15.6.2",
"react": "^16.13.1",
"react-ace": "^9.3.0",
@ -14601,10 +14602,9 @@
}
},
"node_modules/luxon": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz",
"integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==",
"optional": true,
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.1.tgz",
"integrity": "sha512-8Eawf81c9ZlQj62W3eq4mp+C7SAIAnmaS7ZuEAiX503YMcn+0C1JnMQRtfaQj6B5qTZLgHv0F4H5WabBCvi1fw==",
"engines": {
"node": "*"
}
@ -21000,6 +21000,15 @@
"luxon": "^1.21.3"
}
},
"node_modules/rrule/node_modules/luxon": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==",
"optional": true,
"engines": {
"node": "*"
}
},
"node_modules/rst-selector-parser": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz",
@ -38379,10 +38388,9 @@
}
},
"luxon": {
"version": "1.26.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.26.0.tgz",
"integrity": "sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==",
"optional": true
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-2.0.1.tgz",
"integrity": "sha512-8Eawf81c9ZlQj62W3eq4mp+C7SAIAnmaS7ZuEAiX503YMcn+0C1JnMQRtfaQj6B5qTZLgHv0F4H5WabBCvi1fw=="
},
"magic-string": {
"version": "0.25.7",
@ -43724,6 +43732,14 @@
"requires": {
"luxon": "^1.21.3",
"tslib": "^1.10.0"
},
"dependencies": {
"luxon": {
"version": "1.28.0",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==",
"optional": true
}
}
},
"rst-selector-parser": {

View File

@ -21,6 +21,7 @@
"has-ansi": "4.0.0",
"html-entities": "2.3.2",
"js-yaml": "^3.13.1",
"luxon": "^2.0.1",
"prop-types": "^15.6.2",
"react": "^16.13.1",
"react-ace": "^9.3.0",

View File

@ -2,7 +2,6 @@ import React from 'react';
import { node, string } from 'prop-types';
import { t } from '@lingui/macro';
import styled from 'styled-components';
import { formatDateString } from 'util/dates';
import _Detail from './Detail';
const Detail = styled(_Detail)`
@ -10,14 +9,8 @@ const Detail = styled(_Detail)`
`;
function NumberSinceDetail({ label, number, date, dataCy = null }) {
const dateStr = formatDateString(date);
return (
<Detail
label={label}
dataCy={dataCy}
value={t`${number} since ${dateStr}`}
/>
<Detail label={label} dataCy={dataCy} value={t`${number} since ${date}`} />
);
}
NumberSinceDetail.propTypes = {

View File

@ -85,7 +85,7 @@ describe('<ScheduleAdd />', () => {
interval: 1,
name: 'Run once schedule',
startDate: '2020-03-25',
startTime: '10:00:00',
startTime: '10:00 AM',
timezone: 'America/New_York',
});
});
@ -108,7 +108,7 @@ describe('<ScheduleAdd />', () => {
name: 'Run every 10 minutes 10 times',
occurrences: 10,
startDate: '2020-03-25',
startTime: '10:30:00',
startTime: '10:30 AM',
timezone: 'America/New_York',
});
});
@ -127,12 +127,12 @@ describe('<ScheduleAdd />', () => {
description: 'test description',
end: 'onDate',
endDate: '2020-03-26',
endTime: '10:45:00',
endTime: '10:45 AM',
frequency: 'hour',
interval: 1,
name: 'Run every hour until date',
startDate: '2020-03-25',
startTime: '10:45:00',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -154,7 +154,7 @@ describe('<ScheduleAdd />', () => {
interval: 1,
name: 'Run daily',
startDate: '2020-03-25',
startTime: '10:45:00',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -178,7 +178,7 @@ describe('<ScheduleAdd />', () => {
name: 'Run weekly on mon/wed/fri',
occurrences: 1,
startDate: '2020-03-25',
startTime: '10:45:00',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -201,7 +201,7 @@ describe('<ScheduleAdd />', () => {
occurrences: 1,
runOn: 'day',
runOnDayNumber: 1,
startTime: '10:45',
startTime: '10:45 AM',
startDate: '2020-04-01',
timezone: 'America/New_York',
});
@ -221,7 +221,7 @@ describe('<ScheduleAdd />', () => {
description: 'test description',
end: 'never',
endDate: '2020-03-26',
endTime: '11:00:00',
endTime: '11:00 AM',
frequency: 'month',
interval: 1,
name: 'Run monthly on the last Tuesday',
@ -230,7 +230,7 @@ describe('<ScheduleAdd />', () => {
runOnTheDay: 'tuesday',
runOnTheOccurrence: -1,
startDate: '2020-03-31',
startTime: '11:00',
startTime: '11:00 AM',
timezone: 'America/New_York',
});
});
@ -255,7 +255,7 @@ describe('<ScheduleAdd />', () => {
runOnDayMonth: 3,
runOnDayNumber: 1,
startDate: '2020-03-01',
startTime: '00:00',
startTime: '12:00 AM',
timezone: 'America/New_York',
});
});
@ -282,7 +282,7 @@ describe('<ScheduleAdd />', () => {
runOnTheDay: 'friday',
runOnTheMonth: 4,
startDate: '2020-04-10',
startTime: '11:15',
startTime: '11:15 AM',
timezone: 'America/New_York',
});
});
@ -309,7 +309,7 @@ describe('<ScheduleAdd />', () => {
runOnTheDay: 'weekday',
runOnTheMonth: 10,
startDate: '2020-04-10',
startTime: '11:15',
startTime: '11:15 AM',
timezone: 'America/New_York',
});
});
@ -378,7 +378,7 @@ describe('<ScheduleAdd />', () => {
name: 'Schedule',
end: 'never',
endDate: '2021-01-29',
endTime: '14:15:00',
endTime: '2:15 PM',
frequency: 'none',
occurrences: 1,
runOn: 'day',
@ -394,7 +394,7 @@ describe('<ScheduleAdd />', () => {
{ name: 'cred 2', id: 20 },
],
startDate: '2021-01-28',
startTime: '14:15:00',
startTime: '2:15 PM',
timezone: 'America/New_York',
});
});
@ -467,7 +467,7 @@ describe('<ScheduleAdd />', () => {
interval: 1,
name: 'Run once schedule',
startDate: '2020-03-25',
startTime: '10:00:00',
startTime: '10:00 AM',
timezone: 'America/New_York',
});
});

View File

@ -250,15 +250,21 @@ function ScheduleDetail({ hasDaysToKeepField, schedule, surveyConfig }) {
<DetailList gutter="sm">
<Detail label={t`Name`} value={name} />
<Detail label={t`Description`} value={description} />
<Detail label={t`First Run`} value={formatDateString(dtstart)} />
<Detail label={t`Next Run`} value={formatDateString(next_run)} />
<Detail label={t`Last Run`} value={formatDateString(dtend)} />
<Detail
label={t`First Run`}
value={formatDateString(dtstart, timezone)}
/>
<Detail
label={t`Next Run`}
value={formatDateString(next_run, timezone)}
/>
<Detail label={t`Last Run`} value={formatDateString(dtend, timezone)} />
<Detail label={t`Local Time Zone`} value={timezone} />
<Detail label={t`Repeat Frequency`} value={repeatFrequency} />
{hasDaysToKeepField ? (
<Detail label={t`Days of Data to Keep`} value={daysToKeep} />
) : null}
<ScheduleOccurrences preview={preview} />
<ScheduleOccurrences preview={preview} tz={timezone} />
<UserDateDetail
label={t`Created`}
date={created}

View File

@ -13,10 +13,6 @@ import ScheduleEdit from './ScheduleEdit';
jest.mock('../../../api');
let wrapper;
const now = new Date();
const closestQuarterHour = new Date(Math.ceil(now.getTime() / 900000) * 900000);
const tomorrow = new Date(closestQuarterHour);
tomorrow.setDate(tomorrow.getDate() + 1);
const mockSchedule = {
rrule:
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;COUNT=1;FREQ=MINUTELY',
@ -204,7 +200,7 @@ describe('<ScheduleEdit />', () => {
interval: 1,
name: 'Run once schedule',
startDate: '2020-03-25',
startTime: '10:00:00',
startTime: '10:00 AM',
timezone: 'America/New_York',
});
});
@ -228,7 +224,7 @@ describe('<ScheduleEdit />', () => {
name: 'Run every 10 minutes 10 times',
occurrences: 10,
startDate: '2020-03-25',
startTime: '10:30:00',
startTime: '10:30 AM',
timezone: 'America/New_York',
});
});
@ -248,12 +244,12 @@ describe('<ScheduleEdit />', () => {
description: 'test description',
end: 'onDate',
endDate: '2020-03-26',
endTime: '10:45:00',
endTime: '10:45 AM',
frequency: 'hour',
interval: 1,
name: 'Run every hour until date',
startDate: '2020-03-25',
startTime: '10:45:00',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -276,7 +272,7 @@ describe('<ScheduleEdit />', () => {
interval: 1,
name: 'Run daily',
startDate: '2020-03-25',
startTime: '10:45:00',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -299,7 +295,7 @@ describe('<ScheduleEdit />', () => {
name: 'Run weekly on mon/wed/fri',
occurrences: 1,
startDate: '2020-03-25',
startTime: '10:45:00',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -324,7 +320,7 @@ describe('<ScheduleEdit />', () => {
runOn: 'day',
runOnDayNumber: 1,
startDate: '2020-04-01',
startTime: '10:45',
startTime: '10:45 AM',
timezone: 'America/New_York',
});
});
@ -352,7 +348,7 @@ describe('<ScheduleEdit />', () => {
runOnTheDay: 'tuesday',
runOnTheOccurrence: -1,
startDate: '2020-03-31',
startTime: '11:00',
startTime: '11:00 AM',
timezone: 'America/New_York',
});
});
@ -380,7 +376,7 @@ describe('<ScheduleEdit />', () => {
runOn: 'day',
runOnDayMonth: 3,
runOnDayNumber: 1,
startTime: '00:00',
startTime: '12:00 AM',
startDate: '2020-03-01',
timezone: 'America/New_York',
});
@ -408,7 +404,7 @@ describe('<ScheduleEdit />', () => {
runOnTheOccurrence: 2,
runOnTheDay: 'friday',
runOnTheMonth: 4,
startTime: '11:15',
startTime: '11:15 AM',
startDate: '2020-04-10',
timezone: 'America/New_York',
});
@ -437,7 +433,7 @@ describe('<ScheduleEdit />', () => {
runOnTheOccurrence: 1,
runOnTheDay: 'weekday',
runOnTheMonth: 10,
startTime: '11:15',
startTime: '11:15 AM',
startDate: '2020-04-10',
timezone: 'America/New_York',
});
@ -528,7 +524,7 @@ describe('<ScheduleEdit />', () => {
name: mockSchedule.name,
end: 'never',
endDate: '2021-01-29',
endTime: '14:15:00',
endTime: '2:15 PM',
frequency: 'none',
occurrences: 1,
runOn: 'day',
@ -539,7 +535,7 @@ describe('<ScheduleEdit />', () => {
runOnTheOccurrence: 1,
skip_tags: '',
startDate: '2021-01-28',
startTime: '14:15:00',
startTime: '2:15 PM',
timezone: 'America/New_York',
credentials: [
{ id: 3, name: 'Credential 3', kind: 'ssh', url: '' },
@ -630,7 +626,7 @@ describe('<ScheduleEdit />', () => {
name: 'foo',
inventory: 702,
rrule:
'DTSTART;TZID=America/New_York:20200402T184500 RRULE:INTERVAL=1;COUNT=1;FREQ=MINUTELY',
'DTSTART;TZID=America/New_York:20200402T144500 RRULE:INTERVAL=1;COUNT=1;FREQ=MINUTELY',
});
});
@ -732,7 +728,7 @@ describe('<ScheduleEdit />', () => {
interval: 1,
name: 'Run once schedule',
startDate: '2020-03-25',
startTime: '10:00:00',
startTime: '10:00 AM',
timezone: 'America/New_York',
});
});

View File

@ -103,7 +103,7 @@ function ScheduleListItem({
<DetailList stacked>
<Detail
label={t`Next Run`}
value={formatDateString(schedule.next_run)}
value={formatDateString(schedule.next_run, schedule.timezone)}
/>
</DetailList>
)}

View File

@ -1,11 +1,11 @@
import 'styled-components/macro';
import React, { useState } from 'react';
import { shape } from 'prop-types';
import { shape, string } from 'prop-types';
import styled from 'styled-components';
import { t } from '@lingui/macro';
import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core';
import { formatDateString, formatDateStringUTC } from 'util/dates';
import { formatDateString } from 'util/dates';
import { DetailName, DetailValue } from '../../DetailList';
import MultiButtonToggle from '../../MultiButtonToggle';
@ -22,7 +22,7 @@ const OccurrencesLabel = styled.div`
}
`;
function ScheduleOccurrences({ preview = { local: [], utc: [] } }) {
function ScheduleOccurrences({ preview = { local: [], utc: [] }, tz }) {
const [mode, setMode] = useState('local');
if (preview.local.length < 2) {
@ -64,8 +64,8 @@ function ScheduleOccurrences({ preview = { local: [], utc: [] } }) {
{preview[mode].map((dateStr) => (
<div key={dateStr}>
{mode === 'local'
? formatDateString(dateStr)
: formatDateStringUTC(dateStr)}
? formatDateString(dateStr, tz)
: formatDateString(dateStr, 'UTC')}
</div>
))}
</DetailValue>
@ -75,10 +75,12 @@ function ScheduleOccurrences({ preview = { local: [], utc: [] } }) {
ScheduleOccurrences.propTypes = {
preview: shape(),
tz: string,
};
ScheduleOccurrences.defaultProps = {
preview: { local: [], utc: [] },
tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
};
export default ScheduleOccurrences;

View File

@ -1,6 +1,7 @@
import React, { useEffect, useCallback, useState } from 'react';
import { shape, func } from 'prop-types';
import { DateTime } from 'luxon';
import { t } from '@lingui/macro';
import { Formik, useField } from 'formik';
import { RRule } from 'rrule';
@ -190,13 +191,11 @@ function ScheduleForm({
const [isSaveDisabled, setIsSaveDisabled] = useState(false);
let rruleError;
const now = new Date();
const closestQuarterHour = new Date(
Math.ceil(now.getTime() / 900000) * 900000
const now = DateTime.now();
const closestQuarterHour = DateTime.fromMillis(
Math.ceil(now.ts / 900000) * 900000
);
const tomorrow = new Date(closestQuarterHour);
tomorrow.setDate(tomorrow.getDate() + 1);
const tomorrow = closestQuarterHour.plus({ days: 1 });
const isTemplate =
resource.type === 'workflow_job_template' ||
resource.type === 'job_template';
@ -376,9 +375,9 @@ function ScheduleForm({
) {
showPromptButton = true;
}
const [currentDate, time] = dateToInputDateTime(closestQuarterHour);
const [currentDate, time] = dateToInputDateTime(closestQuarterHour.toISO());
const [tomorrowDate] = dateToInputDateTime(tomorrow);
const [tomorrowDate] = dateToInputDateTime(tomorrow.toISO());
const initialValues = {
daysOfWeek: [],
description: schedule.description || '',
@ -448,7 +447,10 @@ function ScheduleForm({
} = RRule.fromString(schedule.rrule.replace(' ', '\n'));
if (dtstart) {
const [startDate, startTime] = dateToInputDateTime(schedule.dtstart);
const [startDate, startTime] = dateToInputDateTime(
schedule.dtstart,
schedule.timezone
);
overriddenValues.startDate = startDate;
overriddenValues.startTime = startTime;
@ -457,7 +459,10 @@ function ScheduleForm({
if (schedule.until) {
overriddenValues.end = 'onDate';
const [endDate, endTime] = dateToInputDateTime(schedule.until);
const [endDate, endTime] = dateToInputDateTime(
schedule.until,
schedule.timezone
);
overriddenValues.endDate = endDate;
overriddenValues.endTime = endTime;
@ -550,7 +555,10 @@ function ScheduleForm({
startDate,
} = values;
if (end === 'onDate' && new Date(startDate) >= new Date(endDate)) {
if (
end === 'onDate' &&
DateTime.fromISO(startDate) >= DateTime.fromISO(endDate)
) {
errors.endDate = t`Please select an end date/time that comes after the start date/time.`;
}

View File

@ -1,5 +1,6 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { DateTime } from 'luxon';
import { dateToInputDateTime } from 'util/dates';
import { SchedulesAPI, JobTemplatesAPI, InventoriesAPI } from 'api';
@ -105,7 +106,7 @@ const nonRRuleValuesMatch = () => {
wrapper.find('DatePicker[aria-label="Start date"]').prop('value')
).toBe('2020-04-02');
expect(wrapper.find('TimePicker[aria-label="Start time"]').prop('time')).toBe(
'6:45 PM'
'2:45 PM'
);
expect(wrapper.find('select#schedule-timezone').prop('value')).toBe(
'America/New_York'
@ -474,11 +475,11 @@ describe('<ScheduleForm />', () => {
});
test('initially renders expected fields and values', () => {
const now = new Date();
const closestQuarterHour = new Date(
Math.ceil(now.getTime() / 900000) * 900000
const now = DateTime.now();
const closestQuarterHour = DateTime.fromMillis(
Math.ceil(now.ts / 900000) * 900000
);
const [date, time] = dateToInputDateTime(closestQuarterHour);
const [date, time] = dateToInputDateTime(closestQuarterHour.toISO());
expect(wrapper.find('ScheduleForm').length).toBe(1);
defaultFieldsVisible();
expect(wrapper.find('FormGroup[label="Run every"]').length).toBe(0);

View File

@ -1,14 +1,12 @@
import { t } from '@lingui/macro';
import { RRule } from 'rrule';
import { DateTime } from 'luxon';
import { getRRuleDayConstants } from 'util/dates';
const parseTime = (time) => {
const [hour, minute, ampm] = time.split(/[: ]/);
const timeHour =
ampm === 'PM' && hour !== '12' ? `${parseInt(hour, 10) + 12}` : `${hour}`;
return [timeHour, minute];
};
const parseTime = (time) => [
DateTime.fromFormat(time, 'h:mm a').hour,
DateTime.fromFormat(time, 'h:mm a').minute,
];
export default function buildRuleObj(values) {
// Dates are formatted like "YYYY-MM-DD"

View File

@ -12,11 +12,7 @@ import RoutedTabs from 'components/RoutedTabs';
import { CardBody, CardActionsRow } from 'components/Card';
import { DetailList, Detail, NumberSinceDetail } from 'components/DetailList';
import { useConfig } from 'contexts/Config';
import {
formatDateString,
formatDateStringUTC,
secondsToDays,
} from 'util/dates';
import { formatDateString, secondsToDays } from 'util/dates';
function SubscriptionDetail() {
const { me = {}, license_info, version } = useConfig();
@ -98,8 +94,9 @@ function SubscriptionDetail() {
label={t`Expires on UTC`}
value={
license_info.license_date &&
formatDateStringUTC(
new Date(license_info.license_date * 1000).toISOString()
formatDateString(
new Date(license_info.license_date * 1000).toISOString(),
'UTC'
)
}
/>

View File

@ -20,7 +20,7 @@ import {
import { ExclamationTriangleIcon } from '@patternfly/react-icons';
import { ConfigAPI } from 'api';
import { formatDateStringUTC } from 'util/dates';
import { formatDateString } from 'util/dates';
import useRequest from 'hooks/useRequest';
import useSelected from 'hooks/useSelected';
import ErrorDetail from 'components/ErrorDetail';
@ -168,8 +168,9 @@ function SubscriptionModal({
{subscription.instance_count}
</Td>
<Td dataLabel={t`Expires`} modifier="nowrap">
{formatDateStringUTC(
new Date(subscription.license_date * 1000).toISOString()
{formatDateString(
new Date(subscription.license_date * 1000).toISOString(),
'UTC'
)}
</Td>
</Tr>

View File

@ -1,62 +1,43 @@
/* eslint-disable import/prefer-default-export */
import { t } from '@lingui/macro';
import { RRule } from 'rrule';
import { getLanguage } from './language';
import { DateTime, Duration } from 'luxon';
const prependZeros = (value) => value.toString().padStart(2, 0);
export function formatDateString(dateString, lang = getLanguage(navigator)) {
if (dateString === null) {
export function formatDateString(dateObj, tz = null) {
if (dateObj === null) {
return null;
}
return new Date(dateString).toLocaleString(lang);
}
export function formatDateStringUTC(dateString, lang = getLanguage(navigator)) {
if (dateString === null) {
return null;
}
return new Date(dateString).toLocaleString(lang, { timeZone: 'UTC' });
return tz !== null
? DateTime.fromISO(dateObj, { zone: tz }).toLocaleString(
DateTime.DATETIME_SHORT_WITH_SECONDS
)
: DateTime.fromISO(dateObj).toLocaleString(
DateTime.DATETIME_SHORT_WITH_SECONDS
);
}
export function secondsToHHMMSS(seconds) {
return new Date(seconds * 1000).toISOString().substr(11, 8);
return Duration.fromObject({ seconds }).toFormat('hh:mm:ss');
}
export function secondsToDays(seconds) {
let duration = Math.floor(parseInt(seconds, 10) / 86400);
if (duration < 0) {
duration = 0;
}
return duration.toString();
return Duration.fromObject({ seconds }).toFormat('d');
}
export function timeOfDay() {
const date = new Date();
const hour = date.getHours();
const minute = prependZeros(date.getMinutes());
const second = prependZeros(date.getSeconds());
const time =
hour > 12
? `${hour - 12}:${minute}:${second} PM`
: `${hour}:${minute}:${second} AM`;
return time;
const dateTime = DateTime.local();
return dateTime.toFormat('hh:mm a');
}
export function dateToInputDateTime(dateObj) {
let date = dateObj;
if (typeof dateObj === 'string') {
date = new Date(dateObj);
export function dateToInputDateTime(dt, tz = null) {
let dateTime;
if (tz) {
dateTime = DateTime.fromISO(dt, { zone: tz });
} else {
dateTime = DateTime.fromISO(dt);
}
const year = date.getFullYear();
const month = prependZeros(date.getMonth() + 1);
const day = prependZeros(date.getDate());
const hour =
date.getHours() > 12 ? parseInt(date.getHours(), 10) - 12 : date.getHours();
const minute = prependZeros(date.getMinutes());
const amPmText = date.getHours() > 11 ? 'PM' : 'AM';
return [`${year}-${month}-${day}`, `${hour}:${minute} ${amPmText}`];
return [dateTime.toFormat('yyyy-LL-dd'), dateTime.toFormat('h:mm a')];
}
export function getRRuleDayConstants(dayString) {

View File

@ -2,7 +2,6 @@ import { RRule } from 'rrule';
import {
dateToInputDateTime,
formatDateString,
formatDateStringUTC,
getRRuleDayConstants,
secondsToDays,
secondsToHHMMSS,
@ -21,35 +20,20 @@ const i18n = {
describe('formatDateString', () => {
test('it returns the expected value', () => {
const lang = 'en-US';
expect(formatDateString(null, lang)).toEqual(null);
expect(formatDateString('', lang)).toEqual('Invalid Date');
expect(formatDateString({}, lang)).toEqual('Invalid Date');
expect(formatDateString(undefined, lang)).toEqual('Invalid Date');
expect(formatDateString('foobar', lang)).toEqual('Invalid Date');
expect(formatDateString('2018-011-31T01:14:52.969227Z', lang)).toEqual(
'Invalid Date'
expect(formatDateString(null)).toEqual(null);
expect(formatDateString('')).toEqual('Invalid DateTime');
expect(formatDateString({})).toEqual('Invalid DateTime');
expect(formatDateString(undefined)).toEqual('Invalid DateTime');
expect(formatDateString('foobar')).toEqual('Invalid DateTime');
expect(formatDateString('2018-011-31T01:14:52.969227Z', undefined)).toEqual(
'Invalid DateTime'
);
expect(formatDateString('2018-01-31T01:14:52.969227Z', lang)).toEqual(
'1/31/2018, 1:14:52 AM'
);
});
});
describe('formatDateStringUTC', () => {
test('it returns the expected value', () => {
const lang = 'en-US';
expect(formatDateStringUTC(null, lang)).toEqual(null);
expect(formatDateStringUTC('', lang)).toEqual('Invalid Date');
expect(formatDateStringUTC({}, lang)).toEqual('Invalid Date');
expect(formatDateStringUTC(undefined, lang)).toEqual('Invalid Date');
expect(formatDateStringUTC('foobar', lang)).toEqual('Invalid Date');
expect(formatDateStringUTC('2018-011-31T01:14:52.969227Z', lang)).toEqual(
'Invalid Date'
);
expect(formatDateStringUTC('2018-01-31T01:14:52.969227Z', lang)).toEqual(
expect(formatDateString('2018-01-31T01:14:52.969227Z')).toEqual(
'1/31/2018, 1:14:52 AM'
);
expect(
formatDateString('2018-01-31T01:14:52.969227Z', 'America/Los_Angeles')
).toEqual('1/30/2018, 5:14:52 PM');
});
});
@ -68,9 +52,10 @@ describe('secondsToHHMMSS', () => {
describe('dateToInputDateTime', () => {
test('it returns the expected value', () => {
expect(
dateToInputDateTime(new Date('2018-01-31T01:14:52.969227Z'))
).toEqual(['2018-01-31', '1:14 AM']);
expect(dateToInputDateTime('2018-01-31T01:14:52.969227Z')).toEqual([
'2018-01-31',
'1:14 AM',
]);
});
});