从日期列表中获取日期范围列表

本文关键字:列表 取日期 范围 获取 日期 | 更新日期: 2023-09-27 18:14:27

我希望从日期列表中获得日期范围列表(带天)。

可能有或可能没有连续的日期,但在周范围内可能存在一致的间隔(即所有星期一,星期三和星期四或所有星期一和星期日,它可以是一周中的1至7天的任何组合)

示例1 -跨越两个月的日期列表,这些日期都是星期一,星期三或星期五

ID  Date        Day
31  2016-02-01  Monday
31  2016-02-03  Wednesday
31  2016-02-05  Friday
31  2016-02-08  Monday
31  2016-02-10  Wednesday
31  2016-02-12  Friday
31  2016-02-15  Monday
31  2016-02-17  Wednesday
31  2016-02-19  Friday
31  2016-02-22  Monday
31  2016-02-24  Wednesday
31  2016-02-26  Friday
31  2016-02-29  Monday
31  2016-03-02  Wednesday
31  2016-03-04  Friday
31  2016-03-07  Monday
31  2016-03-09  Wednesday
31  2016-03-11  Friday

目标-确定所有日期遵循一个模式-所有日期落在同一天,没有间隔

所需输出

ID                       31 
FROMDATE                 01/02/2016
TODATE                   11/03/2016
OPERATINGDAY_MONDAY      TRUE
OPERATINGDAY_TUESDAY     FALSE
OPERATINGDAY_WEDNESDAY   TRUE
OPERATINGDAY_THURSDAY    FALSE
OPERATINGDAY_FRIDAY      TRUE
OPERATINGDAY_SATURDAY    FALSE
OPERATINGDAY_SUNDAY      FALSE

示例2 -与上面相同,但中间有一个间隙(不是星期五19日)-分为2个日期范围

ID  Date        Day
31  2016-02-01  Monday
31  2016-02-03  Wednesday
31  2016-02-05  Friday
31  2016-02-08  Monday
31  2016-02-10  Wednesday
31  2016-02-12  Friday
31  2016-02-15  Monday
31  2016-02-17  Wednesday
31  2016-02-22  Monday
31  2016-02-24  Wednesday
31  2016-02-26  Friday
31  2016-02-29  Monday
31  2016-03-02  Wednesday
31  2016-03-04  Friday
31  2016-03-07  Monday
31  2016-03-09  Wednesday
31  2016-03-11  Friday

期望的输出是一个像这样的对象

ID                       31 
FROMDATE                 01/02/2016
TODATE                   17/02/2016
OPERATINGDAY_MONDAY      TRUE
OPERATINGDAY_TUESDAY     FALSE
OPERATINGDAY_WEDNESDAY   TRUE
OPERATINGDAY_THURSDAY    FALSE
OPERATINGDAY_FRIDAY      TRUE
OPERATINGDAY_SATURDAY    FALSE
OPERATINGDAY_SUNDAY      FALSE
ID                       31 
FROMDATE                 22/02/2016
TODATE                   11/03/2016
OPERATINGDAY_MONDAY      TRUE
OPERATINGDAY_TUESDAY     FALSE
OPERATINGDAY_WEDNESDAY   TRUE
OPERATINGDAY_THURSDAY    FALSE
OPERATINGDAY_FRIDAY      TRUE
OPERATINGDAY_SATURDAY    FALSE
OPERATINGDAY_SUNDAY      FALSE

示例3 -与示例1相同,但中间有一个新的日期(星期二16日)

ID  Date        Day
31  2016-02-01  Monday
31  2016-02-03  Wednesday
31  2016-02-05  Friday
31  2016-02-08  Monday
31  2016-02-10  Wednesday
31  2016-02-12  Friday
31  2016-02-15  Monday
31  2016-02-16  Tuesday
31  2016-02-17  Wednesday
31  2016-02-22  Monday
31  2016-02-24  Wednesday
31  2016-02-26  Friday
31  2016-02-29  Monday
31  2016-03-02  Wednesday
31  2016-03-04  Friday
31  2016-03-07  Monday
31  2016-03-09  Wednesday
31  2016-03-11  Friday

期望的输出是一个像这样的对象

ID                       31 
FROMDATE                 01/02/2016
TODATE                   15/02/2016
OPERATINGDAY_MONDAY      TRUE
OPERATINGDAY_TUESDAY     FALSE
OPERATINGDAY_WEDNESDAY   TRUE
OPERATINGDAY_THURSDAY    FALSE
OPERATINGDAY_FRIDAY      TRUE
OPERATINGDAY_SATURDAY    FALSE
OPERATINGDAY_SUNDAY      FALSE
ID                       31 
FROMDATE                 16/02/2016
TODATE                   16/02/2016
OPERATINGDAY_MONDAY      FALSE
OPERATINGDAY_TUESDAY     TRUE
OPERATINGDAY_WEDNESDAY   FALSE
OPERATINGDAY_THURSDAY    FALSE
OPERATINGDAY_FRIDAY      FALSE
OPERATINGDAY_SATURDAY    FALSE
OPERATINGDAY_SUNDAY      FALSE
ID                       31 
FROMDATE                 17/02/2016
TODATE                   11/03/2016
OPERATINGDAY_MONDAY      TRUE
OPERATINGDAY_TUESDAY     FALSE
OPERATINGDAY_WEDNESDAY   TRUE
OPERATINGDAY_THURSDAY    FALSE
OPERATINGDAY_FRIDAY      TRUE
OPERATINGDAY_SATURDAY    FALSE
OPERATINGDAY_SUNDAY      FALSE

如果能指明正确的进攻方向就太好了。最好是linq .

最终目标是以一致的方式显示数据

Update:这是我目前使用的代码。我正在处理连续的日子和非连续的日子,但我不确定在哪里甚至开始与遵循一定模式的日期。毫无疑问,我对连续几天的处理都错了。

foreach (var o in option.OptionPrices)
                {
                    var dateList = o.Dates.Select(d => d.Date).OrderBy(d => d.Date);
                    maxDate = (from d in dateList select d.Date).Max();
                    minDate = (from d in dateList select d.Date).Min();
                    if ((maxDate - minDate).Days + 1 == dateList.Count()) // runs everyday specified.
                    {
                        dateRange.Start = minDate;
                        dateRange.End = maxDate;
                        dateRange.OptionPriceid = o.OptionPriceId;
                        dateRange.OptionPriceName = o.Name;                        
                        dateRange.DayNames.Add("Monday");
                        dateRange.DayNames.Add("Tuesday");
                        dateRange.DayNames.Add("Wednesday");
                        dateRange.DayNames.Add("Thursday");
                        dateRange.DayNames.Add("Friday");
                        dateRange.DayNames.Add("Saturday");
                        dateRange.DayNames.Add("Sunday");
                        Pricing pricing = new Pricing
                        {
                            OptionId = option.OptionId,
                            OptionName = option.Name,
                            OptionPriceName = dateRange.OptionPriceName,
                            Fromdate = dateRange.Start.ToShortDateString(),
                            Todate = dateRange.End.ToShortDateString(),
                            AdultPrice = o.AdultPrice,
                            ChildPrice = o.ChildPrice,
                            InfantPrice = o.InfantPrice,
                            Operatingday_Monday = dateRange.DayNames.Contains("Monday") ? "x" : "-",
                            Operatingday_Tuesday = dateRange.DayNames.Contains("Tuesday") ? "x" : "-",
                            Operatingday_Wednesday = dateRange.DayNames.Contains("Wednesday") ? "x" : "-",
                            Operatingday_Thursday = dateRange.DayNames.Contains("Thursday") ? "x" : "-",
                            Operatingday_Friday = dateRange.DayNames.Contains("Friday") ? "x" : "-",
                            Operatingday_Saturday = dateRange.DayNames.Contains("Saturday") ? "x" : "-",
                            Operatingday_Sunday = dateRange.DayNames.Contains("Sunday") ? "x" : "-"
                        };
                        pricingModel.Add(pricing);
                        dateRange = new DateRange { DayNames = new List<string>() };                        
                        continue;
                    }
    // if we get to here we have non consecutive  dates 
                    foreach (var optionPriceDate in o.Dates.Select(d=>d.Date).OrderBy(d=>d.Date))
                    {                                                
                        currentDate = optionPriceDate;
                        if (dateRange.Start == DateTime.MinValue) // new range
                        {
                            dateRange.Start = currentDate; 
                            dateRange.OptionPriceid = o.OptionPriceId;
                            dateRange.OptionPriceName = o.Name;
                            if (!dateRange.DayNames.Contains(currentDate.DayOfWeek.ToString()))
                            {
                                dateRange.DayNames.Add(currentDate.DayOfWeek.ToString());
                            }                            
                            maxDate  = (from d in o.Dates select d.Date).Max(); 
                        }
                        if (currentDate == maxDate && (maxDate-lastDate).Days == 1 ) //last consecative day
                        {
                            dateRange.End = currentDate;
                            if (!dateRange.DayNames.Contains(currentDate.DayOfWeek.ToString()))
                            {
                                dateRange.DayNames.Add(currentDate.DayOfWeek.ToString());
                            }                     
                            Pricing pricing = new Pricing
                            {
                                OptionId = option.OptionId,
                                OptionName = option.Name,
                                OptionPriceName = dateRange.OptionPriceName,
                                Fromdate = dateRange.Start.ToShortDateString(),
                                Todate = dateRange.End.ToShortDateString(),
                                AdultPrice = o.AdultPrice,
                                ChildPrice = o.ChildPrice,
                                InfantPrice = o.InfantPrice,
                                Operatingday_Monday = dateRange.DayNames.Contains("Monday") ? "x" : "-",
                                Operatingday_Tuesday = dateRange.DayNames.Contains("Tuesday") ? "x" : "-",
                                Operatingday_Wednesday = dateRange.DayNames.Contains("Wednesday") ? "x" : "-",
                                Operatingday_Thursday = dateRange.DayNames.Contains("Thursday") ? "x" : "-",
                                Operatingday_Friday = dateRange.DayNames.Contains("Friday") ? "x" : "-",
                                Operatingday_Saturday = dateRange.DayNames.Contains("Saturday") ? "x" : "-",
                                Operatingday_Sunday = dateRange.DayNames.Contains("Sunday") ? "x" : "-"
                            };
                            pricingModel.Add(pricing);
                            // END of Price band - Rset everything
                            dateRange = new DateRange
                            {
                                Start = new DateTime(),
                                End = new DateTime(),
                                DayNames = new List<string>()
                            };
                            lastDate = DateTime.MinValue;
                            continue;
                        }

                        // Check to see if there is a gap
                        if ((currentDate.AddDays(-1) != lastDate) && lastDate != DateTime.MinValue)
                        {
                            dateRange.End = lastDate;
                            Pricing pricing = new Pricing
                            {
                                OptionId = option.OptionId,
                                OptionName = option.Name,
                                OptionPriceName = dateRange.OptionPriceName,
                                Fromdate = dateRange.Start.ToShortDateString(),
                                Todate = dateRange.End.ToShortDateString(),
                                AdultPrice = o.AdultPrice,
                                ChildPrice = o.ChildPrice,
                                InfantPrice = o.InfantPrice,
                                Operatingday_Monday = dateRange.DayNames.Contains("Monday") ? "x" : "-",
                                Operatingday_Tuesday = dateRange.DayNames.Contains("Tuesday") ? "x" : "-",
                                Operatingday_Wednesday = dateRange.DayNames.Contains("Wednesday") ? "x" : "-",
                                Operatingday_Thursday = dateRange.DayNames.Contains("Thursday") ? "x" : "-",
                                Operatingday_Friday = dateRange.DayNames.Contains("Friday") ? "x" : "-",
                                Operatingday_Saturday = dateRange.DayNames.Contains("Saturday") ? "x" : "-",
                                Operatingday_Sunday = dateRange.DayNames.Contains("Sunday") ? "x" : "-"
                            };
                            pricingModel.Add(pricing);                    
                            // Start New dateRange
                            dateRange = new DateRange
                            {
                                Start = currentDate,
                                End = new DateTime(),
                                OptionPriceid = o.OptionPriceId,
                                OptionPriceName = o.Name,
                                DayNames = new List<string>()
                            };
                            dateRange.DayNames.Add(currentDate.DayOfWeek.ToString());
                            lastDate = currentDate;
                            continue;                                                                           
                        }
                        if (!dateRange.DayNames.Contains(currentDate.DayOfWeek.ToString()))
                        {
                            dateRange.DayNames.Add(currentDate.DayOfWeek.ToString());
                        }   
                        lastDate = currentDate;
                    }                                        
                }
                PricingList = pricingModel;

从日期列表中获取日期范围列表

LINQ解决方案不值得追求。我不想维护您最终可能构建的任何lambda汤来提取模式。因此,我有点OOP-y。

这里是周的事情。你似乎正在寻找的模式是基于周的形状(即,哪些天是操作)。然后,具有相同形状的周可以以周期串在一起。

一周由天组成,我们指出哪一天有"工作"(正在工作)。这样可以很容易地看出两个星期是否具有相同的形状。

public class Week
{
    public DateTime StartDate { get { return Days.Keys.FirstOrDefault(); } }
    public DateTime EndDate { get { return Days.Keys.LastOrDefault(); } }
    public Dictionary<DateTime, bool> Days { get; private set; }
    public Week(DateTime startDate)
    {
        if (startDate.DayOfWeek != DayOfWeek.Monday)
        {
            throw  new Exception("Week must start on Monday");
        }
        Days = new Dictionary<DateTime, bool>();
        for (int day = 0; day < 7; day++)
        {
            Days.Add(startDate.AddDays(day), false);
        }
    }
    public int Shape
    {
        get { return Days.Where(d => d.Value).Sum(d => (int)Math.Pow(2, (int)d.Key.DayOfWeek)); }
    }
    public bool AreAlike(Week otherWeek)
    {
        return this.Shape == otherWeek.Shape;
    }
    public void SetWorkDays(List<DateTime> workDays)
    {
        foreach (var workDay in workDays)
        {
            Days[Days.Keys.First(d => d.DayOfWeek == workDay.DayOfWeek)] = true;
        }
    }
    public void SetWorkDay(DayOfWeek dayOfWeek, bool work = true)
    {
        Days[Days.Keys.First(d => d.DayOfWeek == dayOfWeek)] = work;
    }
}

然后可以将周列表转换为包含相同形状的连续周的周期列表

 public class Period
    {
        public List<Week> Weeks { get; private set; }
        public Period(Week week)
        {
            Weeks = new List<Week>(new[]{week});
        }
        public bool AddWeek(Week week)
        {
            if (!Weeks.First().AreAlike(week))
            {
                return false;
            }
            Weeks.Add(week);
            return true;
        }
        public DateTime StartDate 
        {
            get { return Weeks.First().StartDate; }
        }
        public DateTime EndDate
        {
            get { return Weeks.Last().EndDate; }
        }
        public Dictionary<DayOfWeek, bool> Display
        {
            get { return Weeks.First().Days.ToDictionary(d => d.Key.DayOfWeek, d => d.Value); }
        }
    }

这是一个从周列表中生成周期的工厂…

public class PeriodFactory
    {
        public List<Period> GetPeriodsOfLikeWeeks(List<Week> weeks)
        {
            var periods = new List<Period>();
            Period currentPeriod = null;
            foreach (var week in weeks)
            {
                if (currentPeriod == null)
                {
                    currentPeriod = new Period(week);
                    periods.Add(currentPeriod);
                    continue;
                }
                if (!currentPeriod.AddWeek(week))
                {
                    currentPeriod = new Period(week);
                    periods.Add(currentPeriod);
                }
            }
            return periods;
        }
    }

还有一个WeekFactory,它可以从你的源数据中获取数据。

public class WeekFactory
    {
        public List<Week> BuildWeeksFromWorkDays(List<DateTime> workDays)
        {
            workDays = workDays.OrderBy(w => w).ToList();
            var startDate = workDays.First();
            if (startDate.DayOfWeek == DayOfWeek.Sunday)
            {
                startDate = startDate.AddDays(-6);
            }
            else
            {
                startDate = startDate.AddDays((startDate.DayOfWeek - DayOfWeek.Monday) * -1);
            }
            var weeks = new List<Week>();
            while (startDate <= workDays.Last())
            {
                var week = new Week(startDate);
                week.SetWorkDays( workDays.Where(d => d.Date >= startDate && d.Date < startDate.AddDays(7)).ToList());
                weeks.Add(week);
                startDate = startDate.AddDays(7);
            }
            return weeks;
        }
    }

可能不是您问题的完整答案,因为您可能在后面使用数据库。这么多的调整和这样的将需要得到正确的自己的使用。

但是……我的答案是我用LinqPad写的,只是为了好玩和啤酒;-)(OP没有特别说明Linq2Sql)

小解释。根据一定的日历和周开始算法,将日期按周数分组。然后从每个小组构建的结果来看那一周的情况。

这个例子只显示了部分答案,因为您仍然需要遍历每个结果,并确定是否需要合并在工作日相等的连续记录。

void Main()
{
    var data = new [] { 
        new Record(31, DateTime.Parse("2016-02-01")),
        new Record(31, DateTime.Parse("2016-02-03")),
        new Record(31, DateTime.Parse("2016-02-05")),
        new Record(31, DateTime.Parse("2016-02-08")),
        new Record(31, DateTime.Parse("2016-02-10")),
        new Record(31, DateTime.Parse("2016-02-12")),
        new Record(31, DateTime.Parse("2016-02-15")),
        new Record(31, DateTime.Parse("2016-02-16")),
        new Record(31, DateTime.Parse("2016-02-17")),
        new Record(31, DateTime.Parse("2016-02-22")),
        new Record(31, DateTime.Parse("2016-02-24")),
        new Record(31, DateTime.Parse("2016-02-26")),
        new Record(31, DateTime.Parse("2016-02-29")),
        new Record(31, DateTime.Parse("2016-03-02")),
        new Record(31, DateTime.Parse("2016-03-04")),
        new Record(31, DateTime.Parse("2016-03-07")),
        new Record(31, DateTime.Parse("2016-03-09")),
        new Record(31, DateTime.Parse("2016-03-11"))
    };
    (
        from rec in data
        group rec by new { ID = rec.Id,  WeekNum = new GregorianCalendar().GetWeekOfYear(rec.Date, CalendarWeekRule.FirstDay, DayOfWeek.Monday)} into g
        select new { 
            ID = g.Key.ID, 
            FromDate = g.First().Date, 
            LastDate = g.Last().Date,
            OPERATINGDAY_MONDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Monday) != null),
            OPERATINGDAY_TUESDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Tuesday) != null),
            OPERATINGDAY_WEDNESDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Wednesday) != null),
            OPERATINGDAY_THURSDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Thursday) != null),
            OPERATINGDAY_FRIDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Friday) != null),
            OPERATINGDAY_SATURDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Saturday) != null),
            OPERATINGDAY_SUNDAY = (g.FirstOrDefault(x=>x.Date.DayOfWeek == DayOfWeek.Sunday) != null),
        }
    ).Dump();
}
// Define other methods and classes here
class Record
{
    public int Id {get;set;}
    public DateTime Date {get;set;}
    public string Day {get;set;}
    public Record (int id, DateTime date)
    {
        Id = id;
        Date = date;
    }
}