#javascript #reactjs #iso8601 #daterangepicker
#javascript #reactjs #iso8601 #daterangepicker
Вопрос:
У меня есть два диапазона дат, один из API, а другой из пользовательского ввода. Оба находятся в формате ISO.
диапазон дат из API:
dateStart 2019-04-01T03:04:00Z
dateStop 2019-04-01T03:05:00Z
диапазон дат из пользовательского ввода:
convertedDateFrom 2020-09-15T18:30:00.000Z
convertedDateTo 2020-09-21T18:30:00.000Z
Я хочу преобразовать date range from user input
в date range from API
. Как я могу этого добиться?
EXPECTED: I want to compare the values two date-ranges and depending on that
I will perform certain export functionality.
The user input date-range could
- fall completely within the date-range of the API
- or at least one of the date values could fall or overlap within the
date-range from the API.
должен перекрывать диапазон дат из API.
это мой date range picker handle()
handleDatePickerChange = (setSelectedDayRange) => {
console.log("initializing handleDatePickerChange()");
console.log("setSelectedDayRange", setSelectedDayRange);
// TODO
// convert the dates
let convertedDateFrom = moment(setSelectedDayRange.from).toISOString();
console.log("convertedDateFrom", convertedDateFrom);
let convertedDateTo = moment(setSelectedDayRange.to).toISOString();
console.log("convertedDateTo", convertedDateTo);
// compare dates
// if(convertedDateFrom === )
// check if data exists
this.setState({
selectedDayRange: setSelectedDayRange,
});
};
Комментарии:
1. Каков ваш ожидаемый результат здесь? Это непонятно!
2. @AlwaysHelping ohk. приношу извинения за это. Я обновил описание ожидаемым результатом
Ответ №1:
Чао, ты мог бы использовать функцию isBetween
, предоставляемую moment таким образом:
// interval comes from API
let dateAPIFrom = moment().toISOString();
let dateAPITo = moment().add(2, "days").toISOString();
// user date interval
let convertedDateFrom = moment(setSelectedDayRange.from).toISOString();
let convertedDateTo = moment(setSelectedDayRange.to).toISOString();
if (
moment(convertedDateFrom)
.subtract(1, "month")
.isBetween(dateAPIFrom, dateAPITo) amp;amp;
moment(convertedDateTo)
.subtract(1, "month")
.isBetween(dateAPIFrom, dateAPITo)
) {
//The user input date-range fall completely within the date-range of the API
} else if (
moment(convertedDateFrom)
.subtract(1, "month")
.isBetween(dateAPIFrom, dateAPITo) ||
moment(convertedDateTo)
.subtract(1, "month")
.isBetween(dateAPIFrom, dateAPITo)
) {
//or at least one of the date values could fall or overlap within the date-range from the API.
}
.subtract(1, "month")
потому что moment({day: 19, month: 8, year: 2020}).toISOString()
возвращает всегда month 1
.
Здесь ваш codesandbox изменен.
Комментарии:
1. @Giovani спасибо. по какой-то причине, но условия if, похоже, не выполняются.
2. @NaumanTanwir да, вы правы. Это происходит потому, что
.toIsoString
возвращает всегдаmonth 1
, поэтому вам нужно.subtract(1, "month")
convertedDateFrom
иconvertedDateTo
, и это работает. Я обновил codesandbox. Теперь я обновляю свой ответ. Извините за это 🙂3. @LionelRowe
moment(moment({day: 19, month: 8, year: 2020}).toISOString())
возвращает 9 (мы говорим о моменте, но проблема не в моменте, проблема в выводе react-modern-calendar-datepicker !!!)4. Я обновил свой ответ: это из-за
react-modern-calendar-datepicker
.DatePicker
возвращает объект, подобный{day: 19, month: 8, year: 2020}
и если вы передадите этот объект в moment, moment вернет 19/9/2020, а не 19/8/2020, как ожидалось. Итак, я добавилsubtract(1, "month")
.5. @GiovanniEsposito Я удалил свои комментарии, поскольку они были вызваны моим незнанием
react-modern-calendar-datepicker
. Похоже, что это ошибка в datepicker, а не moment, как вы упомянули.
Ответ №2:
Это обе даты стандарта ISO-8601, которые могут быть легко преобразованы в собственные Date
объекты, которые могут быть преобразованы в количество миллисекунд с эпохи Unix. Вам не нужна какая-либо сложная логика или даже использовать moment
для этого.
/**
* If result is negative, the first date is earlier
* If result is positive, the second date is earlier
* If result is 0, both dates are exactly the same
*/
const compareIsoDates = (isoString1, isoString2) => {
return new Date(isoString1).valueOf() - new Date(isoString2).valueOf()
}
// result is -46106760000, meaning first date is earlier
console.log(compareIsoDates('2019-04-01T03:04:00Z', '2020-09-15T18:30:00.000Z'))
/**
* strictly between (cannot be the same as start or end)
* if you want to allow same as start and end, change to
* >= and <= instead of > and <
*/
const isStrictlyBetween = (targetDate, [startDate, endDate]) => {
return compareIsoDates(targetDate, startDate) > 0
amp;amp; compareIsoDates(targetDate, endDate) < 0
}
// true
console.log(isStrictlyBetween(
'2020-05-01T00:00:00.000Z',
['2020-04-20T18:30:00Z', '2020-05-10T00:00:00Z']
))
// you can also use `compareIsoDates` a sort function to sort an array of
// ISO strings in ascending order (earliest to latest)
console.log([
"1998-02-12T08:18:27.991Z",
"2005-03-19T19:48:59.501Z",
"1997-05-01T14:58:13.848Z",
"2008-08-31T01:30:11.880Z",
"2004-08-05T16:07:55.443Z"
].sort(compareIsoDates))
Ответ №3:
Отличная особенность форматов даты ISO в том, что они сортируются по алфавиту.
Это означает, что пока вы можете преобразовать его в Date
/ moment
/ etc. вы получите точно такие же результаты, как при сравнении их в виде строк.
Вы можете написать, например, compareISODates
функцию Лайонела как:
/**
* If result is negative, the first date is earlier
* If result is positive, the second date is earlier
* If result is 0, both dates are exactly the same
*/
const compareISODates = (isoString1, isoString2) => {
return isoString1.localeCompare(isoString2);
};
Или в качестве другого примера, convertedDateFrom/To
полностью подпадающего под dateStart/End
, вы можете просто проверить, является ли
convertedDateFrom >= dateStart amp;amp; convertedDateTo <= dateEnd
Конечно, если вам нужна более сложная логика, вы должны использовать одну из библиотек дат, упомянутых выше.
Комментарии:
1. При таком подходе вы столкнетесь с проблемами с часовыми поясами, отличными от
Z
(включая часовой пояс00:00
, что означает то же самое, чтоZ
), и при сравнении дат, которые имеют / не имеют дробные доли секунды (как показано в разнице между форматом API и форматом пользовательского ввода в OP). Пример:'2010-10-10T10:10:10.000Z'.localeCompare('2010-10-10T10:10:10Z')
возвращает-1
, но вы хотите0
.