首页 > 解决方案 > 在momentjs中每5天查找连续日期

问题描述

我有一个日历,用户必须在其中标记日期 4 次。假设用户每天都可以标记并返回以下对象:

{
 date: '2018-01-10',
 dots: [{
         color: 'blue',
         key: 'markOne'
        }, 
        {
         color: 'red',
         key: 'markTwo'
        },
        {
         color: 'black',
         key: 'markThree'
        }, 
        {
         color: 'yellow',
         key: 'markFour'
        }
       ] 
},
{
 date: '2018-02-10',
 dots: [{
         color: 'blue',
         key: 'markOne'
        }, 
        {
         color: 'red',
         key: 'markTwo'
        },
        {
         color: 'black',
         key: 'markThree'
        }, 
        {
         color: 'yellow',
         key: 'markFour'
        }
       ]
},
{
 date: '2018-03-10',
 dots: [{
         color: 'blue',
         key: 'markOne'
        }, 
        {
         color: 'blue',
         key: 'markTwo'
        },
        {
         color: 'black',
         key: 'markThree'
        }, 
        null
       ]
},
{...day4},
{...day5 and so on}

date仅当连续 5 天且仅当dots没有null对象时,我才需要向用户显示本地通知。

因此,让我们假设用户在标记所有 4 个点2018-01-10时开始标记(所有 4 个点),直到2018-05-10那时应该显示本地通知(这是我已经实现的另一个逻辑)。

如果日期是连续的,但dots数组至少有一个,null那么它不应该发送通知。

日期应每 5 天细分一次,因此5,10,15,20,25,30每个月都应显示不同的通知:

const notificationsEveryFiveDays = [
 {day5: 'day 5 notification'},
 {day10: 'day 10 notification'},
 {day15: 'day15 notification'},
 {day20: 'day20 notification'},
 {day25: 'day25 notification'},
 {day30: 'day 30 notification'}
];

到目前为止,我已经设法获取所有日期并操作对象键以返回按日期排序的数组。

export const MarkedDates = () => {
  MyStorage.getItem('markedDates').then((items) => {
    if (items) {
        let dates = _.map(items, (val, id) => {
            return {...val, date: id};
        });
        let sortedDates = _.sortBy(dates, 'date');
        console.log(sortedDates);
    }
});

};

我正在尝试使用moment-range,但我不知道如何检查所有内容dates是否连续dots且不包含null. 这是一个很难解决的问题!

标签: javascriptdatemomentjs

解决方案


我假设您使用的是日期格式 YYYY-DD-MM。(以前没见过那个)

我的方法是首先对列表进行排序并删除任何带有空点的内容,因为它们无论如何都不算​​连续天。之后,我们从最短的一天开始,遍历列表并检查自上次条目以来是否已经过去了一天。当连续 5 天时,将连续天的列表添加到连续数组中。

const dates = [
{
 date: '2018-02-10',
 dots: [{color: 'yellow', key: 'markFour' } ]
},
{
 date: '2018-01-10',
 dots: [ { color: 'yellow', key: 'markFour' } ] 
},
{
 date: '2018-03-10',
 dots: [{ color: 'black', key: 'markThree' }]
},
{
  date: '2018-04-10',
  dots: [{color: "blue", key: 'markOne'}]
},
{
  date: '2018-05-10',
  dots: [{color: "blue", key: 'markOne'}]
}]

// if there is a null then do nothing. Let get that check out of the way first
const dotsHasNull = dates.filter(pair => (pair.dots.filter(dot => dot == null) ).length).length != 0


const sortedDates = dates.map(pair => { 
  // convert date to moment date to use the diff function later
  return {date: moment(pair.date, "YYYY-DD-MM"), dots: pair.dots} 
})
.filter( (pair) => {
	// filter out all days that contain null dots 
	// this is done to handle a case where days 1-7 are consecutive but day 1 contain a null dot, which would discard the entire range 
	// we want it to create a range from 2-7 instead.
	return pair.dots.filter(dot => dot == null).length == 0
	// Maybe you want it to discard the entire range if the range contains a dot, then move this check to after we have found the ranges.
})
.sort((a,b) => a.date.valueOf() - b.date.valueOf() ) // there are probably more efficient sorting methods:)


var consecutivePairs = [];

var currentConsecutive = [];

sortedDates.forEach(pair => {
  if (currentConsecutive.length == 0) {
    currentConsecutive.push(pair)
    return
  }
  const lastConsecutivePair = currentConsecutive[currentConsecutive.length -1];
  // as long as only one day has passed then keep adding to the list
  if (pair.date.diff(lastConsecutivePair.date, 'days') == 1) {
	  currentConsecutive.push(pair)
  } else {
	  // start with an array containing the current pair because otherwise we might skip some days
	  currentConsecutive = [pair];
  }
  if (currentConsecutive.length == 5) {
	  // when we have a range that is atleast 5 days long that add it to 
	consecutivePairs.push(currentConsecutive)
  }
})

consecutivePairs.forEach(consecutive => {
	// sounds like you have some specific requirements for the the notification
	// so you probably have to replace this

	// find every 5 days
	const mark = consecutive.length - (consecutive.length % 5)
	console.log("consecutive days notifications: ", "day " + mark + " notification");
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.js"></script>

希望这能解决你的问题。


推荐阅读