#javascript
#javascript
Вопрос:
Я думал, что с помощью getTimezoneOffset будут учитываться високосные годы
export const dateToDays = async (date: string): Promise<number | null> => {
if (date === "") return null;
const now: Date = new Date(date);
const start: Date = new Date(now.getFullYear(), 0, 0);
const diff =
now -
start
(start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
const oneDay = 1000 * 60 * 60 * 24;
const day = Math.floor(diff / oneDay);
if (!day) return null;
return Number(day);
};
но когда я запускал тест на 29 февраля 1960 года (не високосный год, в феврале всего 28 дней), я ожидал, что он вернет значение null
test("Test Leap 1961", async () => {
expect(await dateToDays("1961-02-29")).toEqual(null); // 61
});
в феврале 1960 года также нет 30 дней
test("Test Leap 1960", async () => {
expect(await dateToDays("1960-02-30")).toEqual(null); // 60
});
Как я могу гарантировать, что вышеуказанные 2 теста возвращают значение null? или, другими словами, как заставить функцию возвращать значение null, если запрашивается день, которого не существует?
Комментарии:
1. Я не вижу здесь вопроса
2. 1960 год был високосным. Кроме того,
new Date("1960-02-30")
возвращается1960-03-01T00:00:00.000Z
так 1 марта.3. да 1960 год был високосным но в феврале не было 30 дней
4. Но в некоторых реализациях конструктор даты переносится на следующий месяц. Вы можете сверить
getDate()
значение новой даты с прошедшим днем и вернуть null, если они не совпадают.
Ответ №1:
Поскольку проверка выполняется только для 1 <= month <= 12
и 1 <= day <= 31
вам нужно будет проверить, совпадает ли анализируемый месяц now.getMonth() 1
( 1
потому что он показывает статистику 0
) с месяцем, который был передан функции через date
Вы выполняете это с помощью следующей строки:
if (parseInt(date.split('-')[1]) !== now.getMonth() 1) return null;
const dateToDays = function(date) {
if (date === "") return null;
if (isNaN(new Date(date).getDate())) return null;
const now = new Date(date);
const start = new Date(now.getFullYear(), 0, 0);
const diff =
now -
start
(start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
const oneDay = 1000 * 60 * 60 * 24;
const day = Math.floor(diff / oneDay);
if (!day) return null;
// check if month is still the same
// ----------------------------------------------------------------
if (parseInt(date.split('-')[1]) !== now.getMonth() 1) return null;
// ----------------------------------------------------------------
return Number(day);
};
console.log(dateToDays('1960-2-28')); // Ok
console.log(dateToDays('1960-2-29')); // Ok
console.log(dateToDays('1961-2-29')); // Fail
console.log(dateToDays('1960-2-30')); // Fail
console.log(dateToDays('1960-2-31')); // Fail
console.log(dateToDays('1960-4-31')); // Fail
console.log(dateToDays('1960-2-31')); // Fail
console.log(dateToDays('1960-13-1')); // Fail
console.log(dateToDays('Hello :)')); // Fail
Возможно, вы захотите добавить проверку, является ли данная date
строка действительной датой:
if(isNaN(new Date(date).getDate())) return null;
Комментарии:
1.
new Date
не возвращает значение null, оно возвращает объект Date сvalueOf()
NaN илиtoString()
значением ‘Недопустимая дата`2. Добавлен случай, спасибо за предложение @pilchard
3.
date.split('-')
ограничивает формат даты вводаYYYY-MM-DD
4. Действительно @FilipSeman но я оставлю уточнение до OP
Ответ №2:
Обновите первое условие.
if (date === "" || isMonthOwerflow(date)) {
return null;
}
...
Пример new Date("1960-02-x")
, где x может быть 1
31
для каждого месяца. Если день не существует, он будет перетекать в следующий месяц.
Если вы можете использовать библиотеки, то я рекомендую MomentJs
, это в значительной степени отраслевой стандарт для задач, связанных с датой.
console.log(moment().diff(moment('1960-02-28'), 'years')); // ok, 60
console.log(moment().diff(moment('1960-02-29'), 'years')); // ok, 60
console.log(moment().diff(moment('1960-02-30'), 'years')); // NaN
console.log(moment().diff(moment('1961-02-28'), 'years')); // ok, 59
console.log(moment().diff(moment('1961-02-29'), 'years')); // NaN
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
Комментарии:
1.
new Date()
возвращает действительную дату, перенесенную на следующий месяц для любых дней до 31 в Chrome и Node.