我有自己的方式这样做,但我不相信它是最好的,在 C#
给定List<DateTime>
,DateTime startDate
和DateTime endDate
。如何在List<DateTime>
和startDate
之间的每个月返回新的endDate
包含在原始{{1}中包含List<DateTime>
和startDate
。
日期不保证是月份的开头,可以是月内的任何日期。
endDate
和startDate
可能跨越多年。
返回的列表应包含每个月缺失的第一天。
谢谢,我希望这是有道理的。
答案 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;
}