Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 16 additions & 21 deletions core/src/components/datetime/datetime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,15 @@ import {
getPreviousYear,
getStartOfWeek,
} from './utils/manipulation';
import { clampDate, convertToArrayOfNumbers, getPartsFromCalendarDay, parseAmPm, parseDate } from './utils/parse';
import {
clampDate,
convertToArrayOfNumbers,
getPartsFromCalendarDay,
parseAmPm,
parseDate,
parseMaxParts,
parseMinParts,
} from './utils/parse';
import {
getCalendarDayState,
isDayDisabled,
Expand Down Expand Up @@ -784,37 +792,24 @@ export class Datetime implements ComponentInterface {
};

private processMinParts = () => {
if (this.min === undefined) {
const { min, todayParts } = this;
if (min === undefined) {
this.minParts = undefined;
return;
}

const { month, day, year, hour, minute } = parseDate(this.min);

this.minParts = {
month,
day,
year,
hour,
minute,
};
this.minParts = parseMinParts(min, todayParts);
};

private processMaxParts = () => {
if (this.max === undefined) {
const { max, todayParts } = this;

if (max === undefined) {
this.maxParts = undefined;
return;
}

const { month, day, year, hour, minute } = parseDate(this.max);

this.maxParts = {
month,
day,
year,
hour,
minute,
};
this.maxParts = parseMaxParts(max, todayParts);
};

private initializeCalendarListener = () => {
Expand Down
88 changes: 87 additions & 1 deletion core/src/components/datetime/test/parse.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { clampDate, getPartsFromCalendarDay, parseAmPm } from '../utils/parse';
import { clampDate, getPartsFromCalendarDay, parseAmPm, parseMinParts, parseMaxParts } from '../utils/parse';

describe('getPartsFromCalendarDay()', () => {
it('should extract DatetimeParts from a calendar day element', () => {
Expand Down Expand Up @@ -72,3 +72,89 @@ describe('parseAmPm()', () => {
expect(parseAmPm(11)).toEqual('am');
});
});

describe('parseMinParts()', () => {
it('should fill in missing information when not provided', () => {
const today = {
day: 14,
month: 3,
year: 2022,
minute: 4,
hour: 2,
};
expect(parseMinParts('2012', today)).toEqual({
month: 1,
day: 1,
year: 2012,
hour: 0,
minute: 0,
});
});
it('should default to current year when only given HH:mm', () => {
const today = {
day: 14,
month: 3,
year: 2022,
minute: 4,
hour: 2,
};
expect(parseMinParts('04:30', today)).toEqual({
month: 1,
day: 1,
year: 2022,
hour: 4,
minute: 30,
});
});
});

describe('parseMaxParts()', () => {
it('should fill in missing information when not provided', () => {
const today = {
day: 14,
month: 3,
year: 2022,
minute: 4,
hour: 2,
};
expect(parseMaxParts('2012', today)).toEqual({
month: 12,
day: 31,
year: 2012,
hour: 23,
minute: 59,
});
});
it('should default to current year when only given HH:mm', () => {
const today = {
day: 14,
month: 3,
year: 2022,
minute: 4,
hour: 2,
};
expect(parseMaxParts('04:30', today)).toEqual({
month: 12,
day: 31,
year: 2022,
hour: 4,
minute: 30,
});
});
it('should fill in correct day during a leap year', () => {
const today = {
day: 14,
month: 3,
year: 2022,
minute: 4,
hour: 2,
};
expect(parseMaxParts('2012-02', today)).toEqual({
month: 2,
day: 29,
year: 2012,
hour: 23,
minute: 59,
});
});
});
70 changes: 70 additions & 0 deletions core/src/components/datetime/utils/parse.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DatetimeParts } from '../datetime-interface';

import { isAfter, isBefore } from './comparison';
import { getNumDaysInMonth } from './helpers';

const ISO_8601_REGEXP =
// eslint-disable-next-line no-useless-escape
Expand Down Expand Up @@ -138,3 +139,72 @@ export const clampDate = (
export const parseAmPm = (hour: number) => {
return hour >= 12 ? 'pm' : 'am';
};

/**
* Takes a max date string and creates a DatetimeParts
* object, filling in any missing information.
* For example, max="2012" would fill in the missing
* month, day, hour, and minute information.
*/
export const parseMaxParts = (max: string, todayParts: DatetimeParts): DatetimeParts => {
const { month, day, year, hour, minute } = parseDate(max);

/**
* When passing in `max` or `min`, developers
* can pass in any ISO-8601 string. This means
* that not all of the date/time fields are defined.
* For example, passing max="2012" is valid even though
* there is no month, day, hour, or minute data.
* However, all of this data is required when clamping the date
* so that the correct initial value can be selected. As a result,
* we need to fill in any omitted data with the min or max values.
*/

const yearValue = year ?? todayParts.year;
const monthValue = month ?? 12;
return {
month: monthValue,
day: day ?? getNumDaysInMonth(monthValue, yearValue),
/**
* Passing in "HH:mm" is a valid ISO-8601
* string, so we just default to the current year
* in this case.
*/
year: yearValue,
hour: hour ?? 23,
minute: minute ?? 59,
};
};

/**
* Takes a min date string and creates a DatetimeParts
* object, filling in any missing information.
* For example, min="2012" would fill in the missing
* month, day, hour, and minute information.
*/
export const parseMinParts = (min: string, todayParts: DatetimeParts): DatetimeParts => {
const { month, day, year, hour, minute } = parseDate(min);

/**
* When passing in `max` or `min`, developers
* can pass in any ISO-8601 string. This means
* that not all of the date/time fields are defined.
* For example, passing max="2012" is valid even though
* there is no month, day, hour, or minute data.
* However, all of this data is required when clamping the date
* so that the correct initial value can be selected. As a result,
* we need to fill in any omitted data with the min or max values.
*/
return {
month: month ?? 1,
day: day ?? 1,
/**
* Passing in "HH:mm" is a valid ISO-8601
* string, so we just default to the current year
* in this case.
*/
year: year ?? todayParts.year,
hour: hour ?? 0,
minute: minute ?? 0,
};
};