【问题标题】:Find missing dates for a given range查找给定范围的缺失日期
【发布时间】:2012-07-13 16:26:45
【问题描述】:

我正在尝试为 DateTimes 集合查找两个 DateTime 变量之间缺失的日期。

例如。

Collection
2010-01-01
2010-01-02
2010-01-03
2010-01-05

DateRange
2010-01-01 -> 2010-01-06

会给我一个List<DateTime>

2010-01-04
2010-01-06

我能想到一些是实现这个但没有什么干净和简单的

有什么想法吗?

【问题讨论】:

    标签: c# datetime


    【解决方案1】:

    我可以想出很多方法来实现这一点,例如:

    DateTime[] col = { new DateTime(2010, 1, 1),
                       new DateTime(2010, 1, 2),
                       new DateTime(2010, 1, 3),
                       new DateTime(2010, 1, 5)};
    
    var start = new DateTime(2010, 1, 1);
    var end = new DateTime(2010, 1, 6);
    
    var range = Enumerable.Range(0, (int)(end - start).TotalDays + 1)
                          .Select(i => start.AddDays(i));
    
    var missing = range.Except(col);
    

    您可以将范围内容放入扩展方法中

    public static class extensions
    {
        public static IEnumerable<DateTime> Range(this DateTime startDate, DateTime endDate)
        {
            return Enumerable.Range(0, (int)(endDate - startDate).TotalDays + 1)
                             .Select(i => startDate.AddDays(i));
        }
    }
    

    那就简单了

    DateTime[] col = { new DateTime(2010, 1, 1),
                       new DateTime(2010, 1, 2),
                       new DateTime(2010, 1, 3),
                       new DateTime(2010, 1, 5)};
    
    var start = new DateTime(2010, 1, 1);
    var end = new DateTime(2010, 1, 6);
    var missing = start.Range(end).Except(col);
    

    但也许这不是一个高性能的解决方案:-)

    【讨论】:

    • 这与我的想法相似,只是使用 for 循环来建立我的范围。我只是不喜欢每次都建立一个日期列表的想法,因为我必须安静地做很多。
    • 不应该那么慢,因为 Enumeramble.Range 是惰性评估的 iirc。除了创建日期列表之外,我没有看到任何干净的解决方案,因为 DateTime 类为您完成了所有必要的日期处理逻辑。
    • 放弃了这个解决方案。性能冲击并没有我想象的那么糟糕!
    【解决方案2】:

    具体取决于您要查找的内容以及数据集的大小。一种简单的方法是将日期加载到集合中,然后使用简单的循环。稍后我会在这里添加一个代码示例。

    DateTime currentDate = new DateTime(2010, 1, 1);
    DateTime endDate = new DateTime(2010, 1, 6);
    List<DateTime> existingDates = new List<DateTime>; //You fill with values
    List<DateTime> missingDates = new List<DateTime>;
    
    while(currentDate <= endDate)
    {
        if(existingDates.contains(currentDate))
            missingDates.Add(currentDate);
    
        //Increment date
        currentDate = currentDate.AddDays(1);
    }
    

    使用此示例,您只需要使用正确的值加载“existingDates”,然后“missingDates”列表就会有您的结果

    【讨论】:

    • 在那里使用 .Contains(..) 是一种好方法吗?将整个数组与自身迭代中的一项进行匹配。我没有进行基准测试,但我会选择 Where and Count hits
    【解决方案3】:

    在 .NET 2.0 中:)

        static void Main(string[] args)
        {
            List<DateTime> dates = new List<DateTime>();
            dates.Add(new DateTime(2010, 01, 27));
            dates.Add(new DateTime(2010, 01, 30));
            dates.Add(new DateTime(2010, 01, 31));
            dates.Add(new DateTime(2010, 02, 01));
    
    
            DateTime startDate = new DateTime(2010, 01, 25);
            DateTime endDate = new DateTime(2010, 02, 02);
    
            List<DateTime> missingDates = new List<DateTime>(GetMissingDates(dates, startDate, endDate));
    
        }
    
        private static IEnumerable<DateTime> GetMissingDates(IList<DateTime> dates, DateTime startDate, DateTime endDate)
        {
            TimeSpan _timeStamp = endDate - startDate;
            DateTime _tempDateTime = startDate;
            IList<DateTime> _dateTimeRange = new List<DateTime>();
            IList<DateTime> _missingDates = new List<DateTime>();
    
            for (int i = 0; i <= _timeStamp.Days; i++)
            {
                _dateTimeRange.Add(_tempDateTime);
                _tempDateTime = _tempDateTime.AddDays(1);
            }
    
            foreach (DateTime dt in _dateTimeRange)
            {
                if (!dates.Contains(dt))
                    yield return dt;
            }
        }
    

    【讨论】:

      【解决方案4】:

      惰性求值辅助方法有助于生成要比较的日期列表。可能希望针对大型集合对这种方法进行性能分析。

      void Main()
      {
          var dates = new[] {new DateTime(2000,1,1), new DateTime(2000,1,5)};
          DateHelper.Range(new DateTime(2000,1,1), new DateTime(2000,1,5)).Except(dates).Dump();
      }
      
      // Define other methods and classes here
      public static class DateHelper {
          public static IEnumerable<DateTime> Range(DateTime start, DateTime end) {
              var days = end.Subtract(start).Days;
              var next = start;
              for(var i = 0; i<days; i++) {
                  next = next.AddDays(1);
                  yield return next;
              }
          }
      }
      

      【讨论】:

        【解决方案5】:
        var dates = new List<DateTime>
                        {
                            new DateTime( 2010, 01, 01 ), 
                            new DateTime( 2010, 01, 02 ), 
                            new DateTime( 2010, 01, 03 ), 
                            new DateTime( 2010, 01, 05 )
                        };
        
        var targetDate = new DateTime( 2010, 01, 01 );
        
        var missingDates = new List<DateTime>();
        while ( targetDate <= new DateTime( 2010, 01, 06 ) )
        {
            if ( !dates.Contains( targetDate ) )
                missingDates.Add( targetDate );
        
            targetDate = targetDate.AddDays( 1 );
        }
        
        foreach ( var date in missingDates )
            Debug.WriteLine( date.ToString() );
        

        如果您正在考虑使用 LINQ 来解决这个问题,我认为这是不可能的,除非您还拥有介于最小日期和最大日期之间的所有日期的列表。在 SQL 中,这相当于一个日历表,其中包含给定时间段内的所有日期。

        这是一个 LINQ 解决方案,我在其中创建了上面提到的日历列表,然后查询缺少的日期:

        var dates = new List<DateTime>
                        {
                            new DateTime( 2010, 01, 01 ), 
                            new DateTime( 2010, 01, 02 ), 
                            new DateTime( 2010, 01, 03 ), 
                            new DateTime( 2010, 01, 05 )
                        };
        var calendar = new List<DateTime>();
        var targetDate = new DateTime( 2010, 01, 01 );
        while ( targetDate <= new DateTime( 2010, 01, 06 ) )
        {
            calendar.Add( targetDate );
            targetDate = targetDate.AddDays( 1 );
        }
        
        var missingDates = ( from date in calendar
                      where !dates.Contains( date )
                      select date ).ToList();
        
        foreach ( var date in missingDates )
            Debug.WriteLine( date.ToString() );
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-10-05
          • 2021-08-15
          • 2014-03-29
          • 1970-01-01
          • 2021-09-18
          相关资源
          最近更新 更多