-
Notifications
You must be signed in to change notification settings - Fork 2.3k
fix: Inconsistent/broken behavior in parseDate
#3988
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
692dd5f
bb7177f
ffdf528
59658cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) { | ||
|
@@ -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 */) && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
(!strictParsing || value === formatDate(parsedDate, format, locale)) | ||
) { | ||
return parsedDate; | ||
} | ||
} | ||
|
||
return isValid(parsedDate) && strictParsingValueMatch ? parsedDate : null; | ||
return null; | ||
} | ||
|
||
// ** Date "Reflection" ** | ||
|
@@ -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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding |
||
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, | ||
}); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Edit: based on the commit message, |
||
); | ||
// Use date from `selected` prop when manipulating only time for input value | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I have not tried this myself (I'm not experienced enough to know how), I believe this would fix a bug of mine that I discovered last week. I'm using UTCDate objects with the datepicker (set as
selected
,minDate
, andmaxDate
), but dates entered manually in the input box are not getting parsed as UTCDates, and each iteration of manual date input results in an additional timezone offset to the datetime. I think this is because the original call toparse()
passed in anew Date()
for the reference date todate-fns
'sparse()
instead of the component'sminDate
or some other UTCDate object.My temporary workaround is to use
startOfDay(new UTCDate(newDate)).toISOString()
in theonChange
function.