【问题标题】:Get a List of Dates In a Date Range获取日期范围内的日期列表
【发布时间】:2013-03-02 23:34:25
【问题描述】:

假设我有一个 LockedDate 列表。

LockedDate 有一个 DateTime 和一个 IsYearly 布尔值。如果 IsYearly 为真,则不应考虑该年份,因为它可以是任何年份。永远不要考虑时间。

例如:圣诞节,每年 12 月 25 日。

现在我有一个 LockedDate 列表。

没有重复。

现在我需要这个函数:

这个函数会做: 如果 LockedDate 不是每年,并且日、月和年在源的范围内,则添加到返回列表。

如果 LockedDate 是每年一次,并且它的月/日在该范围内,则为该范围内的每一年添加一个新日期。

假设我在 12 月 25 日将 IsYearly 设为 true。我的范围是 2013 年 1 月 22 日至 2015 年 2 月 23 日(含)。需要将 2013 年 12 月 25 日作为新日期并将 2014 年 12 月 25 日作为新日期添加到列表中。

List<Date> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
{


}

谢谢

Dec 25 Yearly -> Dec 25 2013, Dec 25 2014
Dec 2, 2011  NOT Yearly -> Nothing
March 25, 2013 => March 25 2013

【问题讨论】:

  • “我的范围是 2013 年 1 月 22 日到 2013 年 2 月 23 日(含)。我需要将 2013 年 12 月 25 日作为新日期,并将 2014 年 12 月 25 日作为新日期添加到列表中。” - 你能解释一下吗?
  • 您应该至少显示示例数据和预期输出。另外,.NET 中没有Date 而是DateTime,你的意思是这个吗?
  • 是的,我的意思是日期时间,因此我说不应该考虑时间
  • 对不起,我的意思是 2015 年 2 月 22 日
  • -1 你唯一的问题是你还没有写代码。

标签: c# asp.net


【解决方案1】:

如果你有这样的类 LockedDate:

public class LockedDate
{
       public DateTime Date { get; set; }
       public bool IsYearly { get; set; }
       ...
}

您可以使用此代码来获取您需要的日期:

List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
{

       List<DateTime> dt = new List<DateTime>();
       foreach(LockedDate d in source)
       {
             if(!d.IsYearly)
             {
                  if(start<=d.Date && d.Date<=end)
                       dt.Add(d.Date);
             }
             else
             {
                  for(DateTime i = new DateTime(start.Year,d.Date.Month,d.Date.Day);i<=new DateTime(end.Year,d.Date.Month,d.Date.Day);i=i.AddYears(1))
                  {
                        dt.Add(i);
                  }
             }

      }
      return dt;
}

【讨论】:

  • 这行不通,因为i.AddYears(1) 返回了新的DateTime 对象,它没有保存在任何地方。你有一个无限循环!
  • @MarcinJuraszek 你是对的,更新了我的答案,这是一个小错误,我相信你不是这样挑剔的人,因为代码一般都可以。
【解决方案2】:
var notYearly = lockDates.Where(d => !d.IsYearly && (d.Date.Date >= start && d.Date.Date <= end)).Select(d => d.Date);

var years = ((end - start).Days / 365) + 2;
var startYear = start.Year;

var yearly = lockDates.Where(d => d.IsYearly)
                        .SelectMany(d => Enumerable.Range(startYear, years)
                                                    .Select(e => new DateTime(e, d.Date.Month, d.Date.Day))
                                                    .Where(i => i.Date >= start && i.Date <= end));

var allDates = notYearly.Union(yearly)

应该比仅仅遍历开始和结束之间的所有日子并检查(如果该日期正常)更有效。

【讨论】:

    【解决方案3】:

    这可能会给你至少一个想法,它还没有经过测试

    List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
    {
        if (start > end)
            throw new ArgumentException("Start must be before end");
    
        var ts = end - start;
        var dates = Enumerable.Range(0, ts.Days)
            .Select(i => start.AddDays(i))
            .Where(d => source.Any(ld => ld.Date == d
                || (ld.IsYearly && ld.Date.Month == d.Month && ld.Date.Day == d.Day)));
        return dates.ToList();
    }
    

    更新这是带有您的示例数据的演示,它似乎有效:http://ideone.com/3KFi97

    【讨论】:

    • 我认为它可以被称为暴力解决方案:)
    • @MarcinJuraszek:我没有说这是最有效的方法,但它可能是最易读的方法之一。当它真的太慢时,他可以优化它,并且他已经确认这实际上是他想要的。此外,List&lt;LockedDate&gt; 似乎很小。
    • 我并不是说蛮力在任何情况下都不好。只是说可以做得更有效率。
    【解决方案4】:

    这段代码在不使用 Linq 的情况下做你想做的事:

        List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end)
        {
            List<DateTime> result = new List<DateTime>();
    
            foreach (LockedDate lockedDate in source)
            {
                if (!lockedDate.IsYearly && (lockedDate.Date >= start && lockedDate.Date <= end))
                {
                    result.Add(lockedDate.Date);
                }
                else if (lockedDate.IsYearly && (lockedDate.Date >= start && lockedDate.Date <= end))
                {
                    DateTime date = new DateTime(start.Year, lockedDate.Date.Month, lockedDate.Date.Day);
    
                    do
                    {
                        result.Add(date);
                        date = date.AddYears(1);
                    } while (date <= end);
                }
            }
    
            return result;
        }
    

    不明白的部分一定要问清楚,我可以详细解释,不过我觉得还是挺直截了当的。

    此代码假定您的LockedDate 类具有DateTime 对象的属性Date

    【讨论】:

    • 不完全是因为:else if (lockedDate.IsYearly && (lockedDate.Date >= start &&lockedDate.Date
    猜你喜欢
    • 2019-02-23
    • 2014-01-07
    • 1970-01-01
    • 2021-01-25
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多