Skip to content

Commit

Permalink
Merge 59658cd into 716c0cb
Browse files Browse the repository at this point in the history
  • Loading branch information
maranomynet authored Apr 6, 2023
2 parents 716c0cb + 59658cd commit 422bbbc
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 70 deletions.
77 changes: 16 additions & 61 deletions src/date_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ import longFormatters from "date-fns/esm/_lib/format/longFormatters";

export const DEFAULT_YEAR_ITEM_NUMBER = 12;

// This RegExp catches symbols escaped by quotes, and also
// sequences of symbols P, p, and the combinations like `PPPPPPPppppp`
var longFormattingTokensRegExp = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g;

// ** Date Constructors **

export function newDate(value) {
Expand All @@ -76,59 +72,24 @@ export function newDate(value) {
return isValid(d) ? d : null;
}

export function parseDate(value, dateFormat, locale, strictParsing, minDate) {
let parsedDate = null;
let localeObject =
export function parseDate(value, dateFormat, locale, strictParsing, refDate) {
const localeObject =
getLocaleObject(locale) || getLocaleObject(getDefaultLocale());
let strictParsingValueMatch = true;
if (Array.isArray(dateFormat)) {
dateFormat.forEach((df) => {
let tryParseDate = parse(value, df, new Date(), {
locale: localeObject,
});
if (strictParsing) {
strictParsingValueMatch =
isValid(tryParseDate, minDate) &&
value === formatDate(tryParseDate, df, locale);
}
if (isValid(tryParseDate, minDate) && strictParsingValueMatch) {
parsedDate = tryParseDate;
}
});
return parsedDate;
}

parsedDate = parse(value, dateFormat, new Date(), { locale: localeObject });

if (strictParsing) {
strictParsingValueMatch =
isValid(parsedDate) &&
value === formatDate(parsedDate, dateFormat, locale);
} else if (!isValid(parsedDate)) {
dateFormat = dateFormat
.match(longFormattingTokensRegExp)
.map(function (substring) {
var firstCharacter = substring[0];
if (firstCharacter === "p" || firstCharacter === "P") {
var longFormatter = longFormatters[firstCharacter];
return localeObject
? longFormatter(substring, localeObject.formatLong)
: firstCharacter;
}
return substring;
})
.join("");

if (value.length > 0) {
parsedDate = parse(value, dateFormat.slice(0, value.length), new Date());
}
const formats = Array.isArray(dateFormat) ? dateFormat : [dateFormat];
refDate = refDate || newDate();

if (!isValid(parsedDate)) {
parsedDate = new Date(value);
for (let i = 0, len = formats.length; i < len; i++) {
const format = formats[i];
const parsedDate = parse(value, format, refDate, { locale: localeObject });
if (
isValid(parsedDate /* , minDate */) &&
(!strictParsing || value === formatDate(parsedDate, format, locale))
) {
return parsedDate;
}
}

return isValid(parsedDate) && strictParsingValueMatch ? parsedDate : null;
return null;
}

// ** Date "Reflection" **
Expand All @@ -146,21 +107,15 @@ export function formatDate(date, formatStr, locale) {
if (locale === "en") {
return format(date, formatStr, { awareOfUnicodeTokens: true });
}
let localeObj = getLocaleObject(locale);
const localeObj =
getLocaleObject(locale) || getLocaleObject(getDefaultLocale()) || null;
if (locale && !localeObj) {
console.warn(
`A locale object was not found for the provided string ["${locale}"].`
);
}
if (
!localeObj &&
!!getDefaultLocale() &&
!!getLocaleObject(getDefaultLocale())
) {
localeObj = getLocaleObject(getDefaultLocale());
}
return format(date, formatStr, {
locale: localeObj ? localeObj : null,
locale: localeObj,
awareOfUnicodeTokens: true,
});
}
Expand Down
1 change: 1 addition & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ export default class DatePicker extends React.Component {
this.props.dateFormat,
this.props.locale,
this.props.strictParsing,
this.props.selected,
this.props.minDate
);
// Use date from `selected` prop when manipulating only time for input value
Expand Down
61 changes: 59 additions & 2 deletions test/date_utils_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -896,11 +896,45 @@ describe("date_utils", function () {

it("should parse date that matches one of the formats", () => {
const value = "01/15/2019";
const dateFormat = ["MM/dd/yyyy", "yyyy-MM-dd"];
const dateFormat = ["yyyy-MM-dd", "MM/dd/yyyy"];

expect(parseDate(value, dateFormat, null, true)).to.not.be.null;
});

it("should prefer the first matching format in array (strict)", () => {
const value = "01/06/2019";
const valueLax = "1/6/2019";
const dateFormat = ["MM/dd/yyyy", "dd/MM/yyyy"];

const expected = new Date(2019, 0, 6);

assert(
isEqual(parseDate(value, dateFormat, null, true), expected),
"Value with exact format"
);
expect(
parseDate(valueLax, dateFormat, null, true),
"Value with lax format"
).to.be.null;
});

it("should prefer the first matching format in array", () => {
const value = "01/06/2019";
const valueLax = "1/6/2019";
const dateFormat = ["MM/dd/yyyy", "dd/MM/yyyy"];

const expected = new Date(2019, 0, 6);

assert(
isEqual(parseDate(value, dateFormat, null, false), expected),
"Value with exact format"
);
assert(
isEqual(parseDate(valueLax, dateFormat, null, false), expected),
"Value with lax format"
);
});

it("should not parse date that does not match the format", () => {
const value = "01/15/20";
const dateFormat = "MM/dd/yyyy";
Expand All @@ -916,7 +950,7 @@ describe("date_utils", function () {
});

it("should parse date without strict parsing", () => {
const value = "01/15/20";
const value = "1/2/2020";
const dateFormat = "MM/dd/yyyy";

expect(parseDate(value, dateFormat, null, false)).to.not.be.null;
Expand All @@ -932,6 +966,29 @@ describe("date_utils", function () {
assert(isEqual(actual, expected));
});

it("should parse date based on locale w/o strict", () => {
const valuePt = "26. fev 1995";
const valueEn = "26. feb 1995";

const locale = "pt-BR";
const dateFormat = "d. MMM yyyy";

const expected = new Date(1995, 1, 26);

assert(
isEqual(parseDate(valuePt, dateFormat, locale, false), expected),
"valuePT with pt-BR"
);
assert(
isEqual(parseDate(valueEn, dateFormat, null, false), expected),
"valueEn with default (en-US)"
);
expect(
parseDate(valueEn, dateFormat, locale, false),
"valueEn with (pt-BR)"
).to.be.null;
});

it("should not parse date based on locale without a given locale", () => {
const value = "26/05/1995";
const dateFormat = "P";
Expand Down
14 changes: 7 additions & 7 deletions test/datepicker_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -507,9 +507,9 @@ describe("DatePicker", () => {
/>
);

var input = ReactDOM.findDOMNode(datePicker.input);
input.value = utils.newDate("2014-01-02");
TestUtils.Simulate.change(input);
TestUtils.Simulate.change(datePicker.input, {
target: { value: "01/02/2014" },
});

expect(utils.getHours(date)).to.equal(10);
expect(utils.getMinutes(date)).to.equal(11);
Expand Down Expand Up @@ -880,7 +880,7 @@ describe("DatePicker", () => {
datePicker = TestUtils.renderIntoDocument(
<DatePicker
selected={new Date("1993-07-02")}
minDate={new Date("1800/01/01")}
minDate={new Date("1800-01-01")}
open
/>
);
Expand All @@ -889,11 +889,11 @@ describe("DatePicker", () => {
it("should auto update calendar when the updated date text is after props.minDate", () => {
TestUtils.Simulate.change(datePicker.input, {
target: {
value: "1801/01/01",
value: "01/01/1801",
},
});

expect(datePicker.input.value).to.equal("1801/01/01");
expect(datePicker.input.value).to.equal("01/01/1801");
expect(
datePicker.calendar.componentNode.querySelector(
".react-datepicker__current-month"
Expand Down Expand Up @@ -965,7 +965,7 @@ describe("DatePicker", () => {
it("should update the selected date on manual input", () => {
var data = getOnInputKeyDownStuff();
TestUtils.Simulate.change(data.nodeInput, {
target: { value: "02/02/2017" },
target: { value: "2017-02-02" },
});
TestUtils.Simulate.keyDown(data.nodeInput, getKey("Enter"));
data.copyM = utils.newDate("2017-02-02");
Expand Down

0 comments on commit 422bbbc

Please sign in to comment.