检查日期是否在范围内,忽略年份

时间:2021-03-23 13:04:12

标签: javascript

我想检查日期是否在一个范围内,但我想忽略年份。

例如:

let data = [{dateFrom: '2021-03-01', dateTo: '2021-04-01', nextYear: false},
{dateFrom: '2021-12-01', dateTo: '2022-01-10', nextYear: true}]; // can't be changed

let today = new Date();

let todaysData = data.filter((x) => {
if(x.nextYear) {
  return new Date(x.dateFrom + ' 00:00:00') < today && new Date(x.dateTo + ' 23:59:59') > today
} else {
  return new Date(x.dateFrom + ' 00:00:00') < today && new Date(x.dateTo + ' 23:59:59') > today
}
});

如果今天是在 3 月 1 日到 4 月 1 日之间,则第一个数据样本应该为真。
如果今天是在 12 月 1 日到 1 月 10 日之间,则为第二个。

如果年份相同,这有效,但我希望无论年份如何,这个表达式都是正确的。此外,如果范围中有下一年,则设置“nextYear”标志。 (意味着范围是每年的十二月到一月)

我该怎么做?

3 个答案:

答案 0 :(得分:1)

如果您创建一个日期进行比较会怎样
有点把它们放在同一年

let today = new Date();
let dateToCompare = new Date(''+ today.getYear()+'-'+
x.dateFrom.getMounth()+'-'+ x.dateFrom.getDay());

我认为这不是最好的选择,但可以工作

答案 1 :(得分:1)

您可以通过将 dateFromdateTo 值转换为 ISO 8601 日期字符串,然后将它们传递给 Date 构造函数来过滤数据。您甚至不需要使用 nextYear 标志。

更新如果您想为 true 包含 nextYear 的日期,您可以将它们的年份设置为当前年份,如果 dateFrom超过 dateTo

/**
 * Filters an array of data objects containing date ranges.<p>
 * @param {Object[]} data - an array of objects
 * @param {String} data.dateFrom - data start date
 * @param {String} data.dateTo - data end date
 * @param {Boolean} data.nextYear - if the {@code dateTo} goes into next year
 * @param {Date} [date=new Date()] - target date within data's date range
 * @return a filtered data array
 */
const filterData = (data, date = new Date()) =>
  data.filter(x =>
    ((startDate, endDate) => {
      if (x.nextYear) {
        startDate.setFullYear(date.getFullYear());
        endDate.setFullYear(date.getFullYear());
        if (startDate > endDate) {
          let tmp = startDate;
          startDate = endDate;
          endDate = tmp;
        }
      }
      return date >= startDate && date <= endDate;
    })
    (new Date(`${x.dateFrom}T00:00:00`), new Date(`${x.dateTo}T23:59:59`)))

const data = [
  { dateFrom: '2021-03-01', dateTo: '2021-04-01', nextYear: false },
  { dateFrom: '2021-12-01', dateTo: '2022-01-10', nextYear: true  }
];

console.log(filterData(data));
.as-console-wrapper { top: 0; max-height: 100% !important; }

答案 2 :(得分:1)

在非常仔细地阅读 OP 的验收标准后,一种方法是编写例如一个 getYearLeveledTime 辅助函数,它将每个日期格式字符串值规范化为日期时间数字值。无论传递的日期格式如何,此日期时间的全年基数都调整到 1970 年。仅考虑这种格式的月份和日期。一个额外的标志将时间值增加一整年的定时量。并且为了在任何情况下都保持在保存端,另一个像 getSanitizedTimeRange 这样的小助手会处理正确的范围值优先级。

完成上述设置后,编写过滤函数就容易多了,只需查看某个时间值是否在时间范围内即可。该任务实际上归结为... (time >= timeFrom) && (time <= timeTo) 的返回值。

function getSanitizedTimeRange(a, b) {
  return ((a < b) && [a, b]) || [b, a];
}
function getYearLeveledTime(date, isAddOneYear) {
  date = (date && new Date(date)) || new Date();
  const baseDate = new Date(0);

  baseDate.setDate(date.getDate());
  baseDate.setMonth(date.getMonth());

  if (isAddOneYear) {
    baseDate.setFullYear(baseDate.getFullYear() + 1);
  }
  return baseDate.getTime();
}

function isBoundTimeWithinYearAgnosticRange(dateItem) {
  const [
    timeFrom,
    timeTo,
  ] = getSanitizedTimeRange(
    getYearLeveledTime(dateItem.dateFrom),
    getYearLeveledTime(dateItem.dateTo, dateItem.nextYear)
  );
  const { time } = this; // bound time.

  // whether time is within range or not.
  return (time >= timeFrom) && (time <= timeTo);
}

const data = [
  {dateFrom: '2021-03-01', dateTo: '2021-04-01', nextYear: false},
  {dateFrom: '2021-12-01', dateTo: '2022-01-10', nextYear: true},
];

console.log(
  'filtered, year agnostic, time ranges ...',
  data.filter(isBoundTimeWithinYearAgnosticRange, { time: getYearLeveledTime() })
);

console.log(
  "today's base time ... new Date(getYearLeveledTime()) ...",
  new Date(getYearLeveledTime()),
  `(${ getYearLeveledTime() })`
);
console.log(
  'new Date(getYearLeveledTime("2021-12-01")) ...',
  new Date(getYearLeveledTime("2021-12-01")),
  `(${ getYearLeveledTime("2021-12-01") })`
);
console.log(
  'new Date(getYearLeveledTime("2022-01-10", true)) ...',
  new Date(getYearLeveledTime("2022-01-10", true)),
  `(${ getYearLeveledTime("2022-01-10", true) })`
);
.as-console-wrapper { min-height: 100%!important; top: 0; }