找到失踪的月份

时间:2011-01-14 12:47:33

标签: c# datetime

我有自己的方式这样做,但我不相信它是最好的,在 C#

给定List<DateTime>DateTime startDateDateTime endDate。如何在List<DateTime>startDate之间的每个返回新的endDate 包含在原始{{1}中包含List<DateTime>startDate

日期不保证是月份的开头,可以是月内的任何日期。

endDatestartDate可能跨越多年。

返回的列表应包含每个月缺失的第一天。

谢谢,我希望这是有道理的。

9 个答案:

答案 0 :(得分:3)

嗯,假设不同年份的同一个月被认为是不同的:

    private List<DateTime> GetUnincludedMonths(DateTime startDate, DateTime endDate,
                                               IEnumerable<DateTime> dates)
    {
        var allMonths = new HashSet<Tuple<int, int>>(); //month, year
        DateTime date = startDate;
        while (date <= endDate)
        {
            allMonths.Add(Tuple.Create(date.Month, date.Year));
            date = date.AddMonths(1);
        }
        allMonths.Add(Tuple.Create(endDate.Month, endDate.Year));

        allMonths.ExceptWith(dates.Select(dt => Tuple.Create(dt.Month, dt.Year)));
        return allMonths.Select(t => new DateTime(t.Item2, t.Item1, 1)).ToList();
    }

答案 1 :(得分:3)

var list = new List<DateTime>
    {
        new DateTime(1231223423433132),
        new DateTime(13223123132),
        new DateTime(12333123132),
        new DateTime(123345123132),
        DateTime.Now,
        new DateTime(5634534553)
    };

var allYearMonthes = list.Select(o => 
                             Eumerable.Range(1, 12)
                                 .Select(q => new { o.Year, Month = q }))
                          .SelectMany(o => o);

var enumerable = allYearMonthes.Except(list.Select(o => new { o.Year, o.Month }));

var dateTimes = enumerable.Select(o => new DateTime(o.Year, o.Month, 1));

修改 对于那些对可能完全解决方案感兴趣的人:

DateTime StartDate = DateTime.Now, EndDate = DateTime.Now.AddYears(5).AddMonths(2);
var allYearMonthes = Enumerable.Range(StartDate.Year, EndDate.Year - StartDate.Year -1)
                               .Select(o => Enumerable.Range(1, 12)
                               .Select(q => new { Year = o, Month = q }))
                               .SelectMany(o => o);

var enumerable = allYearMonthes.Except(list.Select(o => new { o.Year, o.Month }));
var dateTimes = enumerable.Select(o => new DateTime(o.Year, o.Month, 1));

答案 2 :(得分:2)

这就是我要做的事情:

static IEnumerable<DateTime> GetMissingMonths(IEnumerable<DateTime> currentDates, DateTime startDate, DateTime endDate)
{
    var yearMonths = new HashSet<Tuple<int, int>>(currentDates.Select(d => Tuple.Create(d.Year, d.Month)));
    DateTime current = new DateTime(startDate.Year, startDate.Month, 1);
    if (current < startDate)
        current = current.AddMonths(1);
    while (current <= endDate)
    {
        if (!yearMonths.Contains(Tuple.Create(current.Year, current.Month)))
        {
            yield return current;
        }
        current = current.AddMonths(1);
    }
}

编辑:如果你不能使用Tuple,你可以使用匿名类型,用helper方法创建HashSet:

static IEnumerable<DateTime> GetMissingMonths(IEnumerable<DateTime> currentDates, DateTime startDate, DateTime endDate)
{
    var yearMonths = MakeHashSet(currentDates.Select(d => new { d.Year, d.Month }));
    DateTime current = new DateTime(startDate.Year, startDate.Month, 1);
    if (current < startDate)
        current = current.AddMonths(1);
    while (current <= endDate)
    {
        if (!yearMonths.Contains(new { current.Year, current.Month }))
        {
            yield return current;
        }
        current = current.AddMonths(1);
    }
}

static HashSet<T> MakeHashSet<T>(IEnumerable<T> source)
{
    return new HashSet<T>(source);
}

当T是匿名类型时,MakeHashSet方法允许您使用类型推断来创建HashSet<T>

答案 3 :(得分:1)

LINQPad - 工作解决方案:

void Main()
{
    var dates = new List<DateTime>
    {
        new DateTime(2011, 1, 1),
        new DateTime(2011, 3, 5),
        new DateTime(2011, 7, 28),
    };
    var startDate = new DateTime(2011, 1, 1);
    var endDate = new DateTime(2012, 12, 31);
    var existingMonths =
        (from dt in dates
         select dt.Year * 12 + dt.Month - 1).Distinct().ToArray();
    var missingMonths =
        from ym in Enumerable.Range(
            startDate.Year * 12 + startDate.Month - 1,
            (endDate.Year * 12 + endDate.Month) - (startDate.Year * 12 + startDate.Month) + 1)
        where !existingMonths.Contains(ym)
        select new DateTime(ym / 12, ym % 12 + 1, 1);
    missingMonths.Dump();
}

答案 4 :(得分:1)

public IEnumerable<DateTime> GetMissingMonths(
  DateTime startDate,
  DateTime endDate,
  IEnumerable<DateTime> source)
{
  IEnumerable<DateTime> sourceMonths =
    source.Select(x => new DateTime(x.Year, x.Month, 1))
          .ToList()
          .Distinct();
  return MonthsBetweenInclusive(startDate, endDate).Except(sourceMonths);
}

public IEnumerable<DateTime> MonthsBetweenInclusive(
  DateTime startDate,
  DateTime endDate)
{
  DateTime currentMonth = new DateTime(startDate.Year, startDate.Month, 1);
  DateTime endMonth = new DateTime(endDate.Year, endDate.Month, 1);

  while(currentMonth <= endMonth)
  {
    yield return currentMonth;
    currentMonth = currentMonth.AddMonths(1);
  }
}

答案 5 :(得分:0)

static void Main(string[] args)
        {
            var days = (new string[] { "3/23/2000", "7/3/2004", "1/3/2004", "3/1/2011" })
                        .Select(a => Convert.ToDateTime(a));

            days = days.Select(a => a.AddDays(1 - (a.Day))).Distinct();
            days = days.OrderBy(a => a);

            var missingMonths = GetMissingMonths(days).ToList();
        }

        private static IEnumerable<DateTime> GetMissingMonths(IEnumerable<DateTime> days)
        {
            DateTime previous = days.First();
            foreach (var current in days.Skip(1))
            {
                int months = (current.Month - previous.Month) + 
                                    12 * (current.Year - previous.Year);
                for (int i = 1; i < months; i++)
                {
                    yield return previous.AddMonths(i);
                }
                previous = current;
            }
        }

答案 6 :(得分:0)

感谢Jani +1的想法。这是一行代码:)

void Main()
 {

 var list = new List<DateTime>
 {
  new DateTime(2005, 10, 11),
  new DateTime(2009, 3, 4),
  new DateTime(2010, 5, 8),
  new DateTime(2010, 8, 10),
  DateTime.Now,
  new DateTime(2010, 4, 8)
 };

        var result= Enumerable.Range(list.Min (l => l.Year), list.Max (l => l.Year) - list.Min (l => l.Year)).
             SelectMany (e => Enumerable.Range(1, 12).Select (en => new DateTime(e, en, 1))).
             Except(list.Select(o => new DateTime(o.Year, o.Month, 1))).
             Where (o => o.Date > list.Min (l => l.Date) && o.Date < list.Max (l => new DateTime(l.Year, l.Month, 1)));

    }

答案 7 :(得分:0)

我会戴上帽子,因为它很有趣。而且我没有看到有人把DateTime放在一个常规for循环中,这是我永远不会做的,所以再次......很有趣。

IEnumerable<DateTime> FindMissingMonths(DateTime startDate, DateTime endDate, IEnumerable<DateTime> inputs)
{
    var allMonths = new List<DateTime>();
    for (DateTime d = startDate; d < endDate; d = d.AddMonths(1))
    {
        allMonths.Add(new DateTime(d.Year, d.Month, 1));
    }
    var usedMonths = (from d in inputs
                        select new DateTime(d.Year, d.Month, 1)).Distinct();
    return allMonths.Except(usedMonths);
}

修复了一个错误,经过测试,有效。

答案 8 :(得分:-1)

    public IList<DateTime> GetMissingMonths(IList<DateTime> currentList, DateTime startDate, DateTime endDate)
    {
        // Create a list for the missing months
        IList<DateTime> missingList = new List<DateTime>();

        // Select a startdate
        DateTime testingDate = startDate;

        // Begin by the month of startDate and ends with the month of endDate
        // month of startDate and endDate included
        while(testingDate <= endDate)
        {
            if (currentList.Count(m => m.Month == testingDate.Month && m.Year == testingDate.Year) == 0)
            {
                missingList.Add(new DateTime(testingDate.Year, testingDate.Month, 1));
            }
            testingDate = testingDate.AddMonths(1);
        }
        return missingList;
    }