C# 找出日期范围之间的差距
我需要你的帮助。我正试图找出如何找到EndDate和下一个StartDate之间的差距。如果存在间隙,我需要返回间隙所在的值。你能帮帮我吗 我有一张有开始日期和结束日期的清单。 例如:C# 找出日期范围之间的差距,c#,.net,linq,datetime,C#,.net,Linq,Datetime,我需要你的帮助。我正试图找出如何找到EndDate和下一个StartDate之间的差距。如果存在间隙,我需要返回间隙所在的值。你能帮帮我吗 我有一张有开始日期和结束日期的清单。 例如: 开始日期:2021年1月2日结束日期:2021年10月2日 开始日期:2021年11月2日结束日期:2021年15月2日 开始日期:2021年2月20日结束日期:2021年2月25日 1和2之间没有间隙。介于2(Enddate)和3(Stardate)之间是一个差距,需要返回如下结果:在2021年2月16日和20
static void Main(string[] args)
{
List<DateRanges> DateRanges = new List<DateRanges>();
DateRanges.Add(new DateRanges() { StartDate = new DateTime(2021, 01, 01), EndDate = new DateTime(2021, 01, 31) });
DateRanges.Add(new DateRanges() { StartDate = new DateTime(2021, 02, 10), EndDate = new DateTime(2021, 02, 25) });
var missing = DateRangeEnumerable.GetDates(DateRanges);
var ranges = missing.GetRanges();
}
public class DateRanges
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
//public DateRanges(DateTime Start, DateTime End)
//{
// StartDate = Start;
// EndDate = End;
//}
}
public static class DateRangeEnumerable
{
public static IEnumerable<DateTime> GetDates(this IEnumerable<DateRanges> source)
{
var sortedSource = source.OrderBy(r => r.StartDate);
foreach (var range in sortedSource)
{
var d = range.StartDate;
while (d < range.EndDate)
{
yield return d;
d = d.AddDays(1);
}
}
}
public static IEnumerable<DateRanges> GetRanges(this IEnumerable<DateTime> source)
{
var sortedSource = source.OrderBy(d => d);
var enumerator = sortedSource.GetEnumerator();
if (!enumerator.MoveNext())
yield break;
DateTime from = enumerator.Current;
DateTime prev = from;
while (true)
{
while (true)
{
if (enumerator.MoveNext())
{
if (enumerator.Current == prev.AddDays(1))
prev = enumerator.Current;
else
break;
}
else
{
yield return new DateRanges() { StartDate = from, EndDate = prev.AddDays(1) };
yield break;
}
}
yield return new DateRanges() { StartDate = from, EndDate = prev.AddDays(1) };
from = enumerator.Current;
prev = enumerator.Current;
}
}
}
static void Main(字符串[]args)
{
列表日期范围=新列表();
Add(new DateRanges(){StartDate=new DateTime(2021,01,01),EndDate=new DateTime(2021,01,31)});
Add(new DateRanges(){StartDate=new DateTime(2021,02,10),EndDate=new DateTime(2021,02,25)});
var missing=DateRangeEnumerable.GetDates(DateRanges);
var ranges=缺少.GetRanges();
}
公共类日期范围
{
公共日期时间起始日期{get;set;}
公共日期时间结束日期{get;set;}
//公共日期范围(日期时间开始、日期时间结束)
//{
//开始日期=开始;
//结束日期=结束;
//}
}
公共静态类DateRangeEnumerable
{
公共静态IEnumerable GetDates(此IEnumerable源)
{
var sortedSource=source.OrderBy(r=>r.StartDate);
foreach(分拣源中的var范围)
{
var d=范围.StartDate;
而(dd);
var枚举器=sortedSource.GetEnumerator();
如果(!enumerator.MoveNext())
屈服断裂;
DateTime from=枚举数。当前;
DateTime prev=起始日期;
while(true)
{
while(true)
{
if(枚举数.MoveNext())
{
if(enumerator.Current==prev.AddDays(1))
prev=枚举数。当前值;
其他的
打破
}
其他的
{
返回新的DateRanges(){StartDate=from,EndDate=prev.AddDays(1)};
屈服断裂;
}
}
返回新的DateRanges(){StartDate=from,EndDate=prev.AddDays(1)};
from=枚举数。当前;
prev=枚举数。当前值;
}
}
}
使用链表怎么样?
代码:
Exmaple
var dateRanges = new List<DateRanges>
{
new() {StartDate = new DateTime(2021, 2, 01), EndDate = new DateTime(2021, 2, 10)},
new() {StartDate = new DateTime(2021, 02, 11), EndDate = new DateTime(2021, 02, 15)},
new() {StartDate = new DateTime(2021, 02, 20), EndDate = new DateTime(2021, 02, 25)}
};
var end = dateRanges.First().EndDate;
foreach (var range in dateRanges.Skip(1))
{
if(end.AddDays(1) < range.StartDate )
Console.WriteLine($"{end.AddDays(1):d} - {range.StartDate.AddDays(-1):d}");
end = range.EndDate;
}
免责声明:它不包含错误检查、排序、代码中没有暗示的内容,并且假设日期没有时间值。它只是复制了您的描述那么,您可以像这样列举差距:
private static IEnumerable<DateRanges> Gaps(IEnumerable<DateRanges> dates) {
var source = dates
.OrderBy(range => range.StartDate);
DateTime last = DateTime.MinValue;
bool first = true;
foreach (var range in source) {
if (!first && range.StartDate.AddDays(1) > last)
yield return new DateRanges() {
StartDate = last.AddDays(1),
EndDate = range.StartDate.AddDays(-1))
};
// In case of overlapping periods we have to pick the latest date
last = first || range.EndDate > last
? range.EndDate
: last;
first = false;
}
}
我喜欢使用返回后续项对的通用扩展方法:
public static IEnumerable<(T Previous, T Next)> PreviousAndNext<T>(this IEnumerable<T> self)
{
using (var iter = self.GetEnumerator())
{
if (!iter.MoveNext())
yield break;
var previous = iter.Current;
while (iter.MoveNext())
{
var next = iter.Current;
yield return (previous, next);
previous = next;
}
}
}
公共静态IEnumerable Previous和Next(此IEnumerable self)
{
使用(var iter=self.GetEnumerator())
{
如果(!iter.MoveNext())
屈服断裂;
var-previous=iter.电流;
while(iter.MoveNext())
{
var next=iter.电流;
收益率回报率(上一个、下一个);
上一个=下一个;
}
}
}
这允许非常紧凑的linq查询
DateRanges.PreviousAndNext()
.Where(p => p.Previous.EndDate.AddDays(1) < p.Next.StartDate)
.Select(p => (p.Previous.EndDate, p.Next.StartDate));
DateRanges.PreviousAndNext()
.Where(p=>p.Previous.EndDate.AddDays(1)(p.Previous.EndDate,p.Next.StartDate));
为什么要将其转换为日期?我将遍历这些范围,记住上一个结束日期,并将其与当前开始日期进行比较。如果其不相等,则创建一个新的“缺失范围”,从上一个结束日期+1开始,到当前开始日期-1结束。如果要对范围进行排序,请使用自定义比较器,使用OrderBy
或列表进行排序。排序
,不要扩展范围。这样做会丢失范围信息嗨,谢谢。但是这行“收益率回报(last.AddDays(1),range.StartDate.AddDays(-1));”不起作用。因为它试图返回日期时间而不是日期范围。@Ronak:谢谢!我已经编辑了添加的应答构造函数调用。
private static IEnumerable<DateRanges> Gaps(IEnumerable<DateRanges> dates) {
var source = dates
.OrderBy(range => range.StartDate);
DateTime last = DateTime.MinValue;
bool first = true;
foreach (var range in source) {
if (!first && range.StartDate.AddDays(1) > last)
yield return new DateRanges() {
StartDate = last.AddDays(1),
EndDate = range.StartDate.AddDays(-1))
};
// In case of overlapping periods we have to pick the latest date
last = first || range.EndDate > last
? range.EndDate
: last;
first = false;
}
}
foreach (var gap in Gaps(dateRanges))
Console.WriteLine($"Gap found between {gap.StartDate} and {gap.EndDate}");
public static IEnumerable<(T Previous, T Next)> PreviousAndNext<T>(this IEnumerable<T> self)
{
using (var iter = self.GetEnumerator())
{
if (!iter.MoveNext())
yield break;
var previous = iter.Current;
while (iter.MoveNext())
{
var next = iter.Current;
yield return (previous, next);
previous = next;
}
}
}
DateRanges.PreviousAndNext()
.Where(p => p.Previous.EndDate.AddDays(1) < p.Next.StartDate)
.Select(p => (p.Previous.EndDate, p.Next.StartDate));