最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - isSameOrBefore implementation for date-fns - Stack Overflow

programmeradmin4浏览0评论

As moment is deprecated, I decided to stash moment from my entire project and thinking to use datefns as a replacement. While I was going through the code file, I came across a line which is saying,

moment(date1).isSameOrBefore(date2, year);

I started looking for something that is similar to what that function is doing but unfortunately, date-fns doesn't have anything to perform precision-based comparison (i.e: year, month or date comparison)? Can anyone suggest some workaround with date-fns?

As moment is deprecated, I decided to stash moment from my entire project and thinking to use datefns as a replacement. While I was going through the code file, I came across a line which is saying,

moment(date1).isSameOrBefore(date2, year);

I started looking for something that is similar to what that function is doing but unfortunately, date-fns doesn't have anything to perform precision-based comparison (i.e: year, month or date comparison)? Can anyone suggest some workaround with date-fns?

Share Improve this question asked Jul 9, 2021 at 9:03 Ashish BairwaAshish Bairwa 7751 gold badge7 silver badges21 bronze badges
Add a comment  | 

6 Answers 6

Reset to default 7

You could use differenceInYears:

const date1 = new Date(2021, 6, 20);;
const date2 = new Date(2021, 7, 2);

function isSameOrBefore(date1, date2) {
  return dateFns.differenceInYears(date1, date2) <= 0;
}

console.log(isSameOrBefore(date1, date2));

console.log(isSameOrBefore(date1, new Date('2022-06-20')));

console.log(isSameOrBefore(date1, new Date('2019-06-20')));
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.28.5/date_fns.min.js"></script>

Using startOfSOMETHING() you can check if a date is before or same using the minute, hour, day, month ecc to compare they.

const dateBefore = dateFns.startOfHour(new Date(1988, 9, 26, 05, 35));
const dateSame = dateFns.startOfHour(new Date(1988, 9, 26, 11, 55));
const dateAfter = dateFns.startOfHour(new Date(1988, 9, 26, 16, 50));

const limit = dateFns.startOfHour(new Date(1988, 9, 26, 11, 55));

// dateBefore < limit => is before
if (dateFns.isBefore(dateBefore, limit) || dateFns.isEqual(dateBefore, limit)) console.log(dateFns.format(dateBefore), 'is before');
else console.log('is not before');

// dateSame === limit => is same
if (dateFns.isBefore(dateSame, limit) || dateFns.isEqual(dateSame, limit)) console.log(dateFns.format(dateSame), 'is same');
else console.log('is not same');

// dateAfter > limit =>  is after
if (dateFns.isBefore(dateAfter, limit) || dateFns.isEqual(dateAfter, limit)) console.log('you mustnt see that message ');
else console.log(dateFns.format(dateAfter), 'is after');
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.28.5/date_fns.min.js"></script>

In my opinion this library is awful, i prefer day.js that is very similar to moment.js or elaborate the date with new Date() of Javascritp.

You should be able to create a drop-in replacement, as long as you test against the relevant moment function.

We can look for the relevant startOfXXX procedure to compare dates when the unit is specified, and also throw an error if it is missing:

function isSameOrBefore(date1, date2, unit = '') {
    if (unit) {
        const procName = `startOf${unit[0].toUpperCase()}${unit.slice(1)}`;
        if (!dateFns[procName]) { 
            throw new Error(`isSameOrBefore: Unsupported unit: ${unit}`);
        }
        date1 = dateFns[procName](date1);
        date2 = dateFns[procName](date2);
    }
    return dateFns.isBefore(date1, date2) || dateFns.isEqual(date1, date2);
}

// Test against various inputs
const dts = ['2010-10-20 01:00', '2010-10-20 00:00', '2010-10-20 00:59:00', '2010-10-01', '2010-09-01', '2009-09-01'];
let units = ['year', 'month', 'day', 'hour', 'minute'];
let dt1 = '2010-10-20 01:00'
let allTests = [];
for(let dt2 of dts) {
    for(let unit of units) {
        // Ensure we get the same answer as moment().isSameOrBefore
        const testPassed = isSameOrBefore(dt1, dt2, unit) === moment(dt1).isSameOrBefore(dt2, unit)
        allTests.push(testPassed);
        console.log(`isSameOrBefore(${dt1}, ${dt2}, ${unit}):`, isSameOrBefore(dt1, dt2, unit));
        console.log(`isSameOrBefore(${dt1}, ${dt2}, ${unit}): Test passed:`, testPassed ? "TRUE": "FALSE")
    }
}
console.log("All tests passed:", allTests.every(res => res) ? "TRUE": "FALSE")
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js" integrity="sha512-F+u8eWHrfY8Xw9BLzZ8rG/0wIvs0y+JyRJrXjp3VjtFPylAEEGwKbua5Ip/oiVhaTDaDs4eU2Xtsxjs/9ag2bQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Use getYear to get the "year" part of both dates first, then compare the two dates.

Something like:

const date1 = new Date(2021, 6, 20);
const date2 = new Date(2021, 7, 2);
const date3 = new Date(2020, 1, 15);
console.log(dateFns.getYear(date1) <= dateFns.getYear(date2));
console.log(dateFns.getYear(date1) <= dateFns.getYear(date3));
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.28.5/date_fns.min.js"></script>

import { isBefore, isEqual } from 'date-fns';

isSameOrBefore(date1: Date, date2: Date, property?: string) {
  switch (property) {
    case 'full':
      return isBefore(date1, date2) || isEqual(date1, date2);
    case 'year':
      return date1.getFullYear() <= date2.getFullYear();
    case 'month':
      return (
        isBefore(date1.getFullYear(), date2.getFullYear()) ||
        (isEqual(date1.getFullYear(), date2.getFullYear()) &&
          date1.getMonth() <= date2.getMonth())
      );
    case 'date':
      return (
        isBefore(date1.getFullYear(), date2.getFullYear()) ||
        (isEqual(date1.getFullYear(), date2.getFullYear()) &&
          date1.getMonth() < date2.getMonth()) ||
        (isEqual(date1.getFullYear(), date2.getFullYear()) &&
          isEqual(date1.getMonth(), date2.getMonth()) &&
          date1.getDate() <= date2.getDate())
      );
    default:
      return compareDesc(date1, date2);
  }
}

You can add more implementation for day, moment ....

Let me post an answer too. It doesn't require you to import entire date-fns

import { endOfDay, endOfWeek, endOfMonth, endOfYear } from 'date-fns';

export function isSameOrBefore(date1, date2, unit) {
    let method;
    switch (unit) {
        case 'day':
            method = endOfDay;
            break;
        case 'week':
            method = endOfWeek;
            break;
        case 'month':
            method = endOfMonth;
            break;
        case 'year':
            method = endOfYear;
            break;
        default:
            break;
    }
    const startTimestamp = method ? method(date1): date1;
    return dateFns.isBefore(startTimestamp, date2) || dateFns.isEqual(startTimestamp, date2);
}
发布评论

评论列表(0)

  1. 暂无评论