C# 计算重叠日期中的夜数
我在想一个合乎逻辑的方法来解决这个问题时遇到了一个问题。 我有一个日期范围列表,例如:C# 计算重叠日期中的夜数,c#,date,logic,C#,Date,Logic,我在想一个合乎逻辑的方法来解决这个问题时遇到了一个问题。 我有一个日期范围列表,例如: 01/01/15 - 11/01/15 02/01/15 - 04/01/15 09/01/15 - 13/01/15 18/01/15 - 20/01/15 var vRanges = new List<Range> { new Range("01/01/15", "11/01/15"), new Range
01/01/15 - 11/01/15
02/01/15 - 04/01/15
09/01/15 - 13/01/15
18/01/15 - 20/01/15
var vRanges = new List<Range>
{
new Range("01/01/15", "11/01/15"),
new Range("02/01/15", "04/01/15"),
new Range("09/01/15", "13/01/15"),
new Range("18/01/15", "20/01/15"),
};
var v = ComputeNights(vRanges);
我需要做的是计算出所有这些日期范围内的总夜数
因此,对于本例,总计应为14晚:
01/01/15 - 11/01/15 // 10 nights
02/01/15 - 04/01/15 // Ignored as nights are covered in 1-11
09/01/15 - 13/01/15 // 2 nights as 11th and 12th nights haven't been covered
18/01/15 - 20/01/15 // 2 nights
我可以使用min-max dates轻松计算出总的夜晚数,但这忽略了丢失的日期(示例中为14-17),这是我无法计算的
有没有办法找到总天数来帮助解决这个问题?类似的方法应该可以:
internal class Range
{
internal DateTime From, To;
public Range(string aFrom, string aTo)
{
From = DateTime.ParseExact(aFrom, "dd/mm/yy", CultureInfo.InvariantCulture);
To = DateTime.ParseExact(aTo, "dd/mm/yy", CultureInfo.InvariantCulture);
}
}
public static int ComputeNights(IEnumerable<Range> ranges)
{
var vSet = new HashSet<DateTime>();
foreach (var range in ranges)
for (var i = range.From; i < range.To; i = i.AddDays(1)) vSet.Add(i)
return vSet.Count;
}
内部类范围
{
内部日期时间从,到;
公共范围(字符串aFrom、字符串aTo)
{
From=DateTime.ParseExact(aFrom,“dd/mm/yy”,CultureInfo.InvariantCulture);
To=DateTime.ParseExact(aTo,“dd/mm/yy”,CultureInfo.InvariantCulture);
}
}
公共静态整数计算权限(IEnumerable ranges)
{
var vSet=new HashSet();
foreach(范围中的var范围)
对于(var i=范围从;i<范围到;i=i.AddDays(1))vSet.Add(i)
返回vSet.Count;
}
运行示例的代码如下:
01/01/15 - 11/01/15
02/01/15 - 04/01/15
09/01/15 - 13/01/15
18/01/15 - 20/01/15
var vRanges = new List<Range>
{
new Range("01/01/15", "11/01/15"),
new Range("02/01/15", "04/01/15"),
new Range("09/01/15", "13/01/15"),
new Range("18/01/15", "20/01/15"),
};
var v = ComputeNights(vRanges);
var vRanges=新列表
{
新范围(“2015年1月1日”、“2015年11月1日”),
新系列(“2015年1月2日”、“2015年1月4日”),
新系列(“09/01/15”、“13/01/15”),
新系列(“2015年1月18日”、“2015年1月20日”),
};
var v=计算亮度(vRanges);
v的计算结果为14类似的结果应该可以:
internal class Range
{
internal DateTime From, To;
public Range(string aFrom, string aTo)
{
From = DateTime.ParseExact(aFrom, "dd/mm/yy", CultureInfo.InvariantCulture);
To = DateTime.ParseExact(aTo, "dd/mm/yy", CultureInfo.InvariantCulture);
}
}
public static int ComputeNights(IEnumerable<Range> ranges)
{
var vSet = new HashSet<DateTime>();
foreach (var range in ranges)
for (var i = range.From; i < range.To; i = i.AddDays(1)) vSet.Add(i)
return vSet.Count;
}
内部类范围
{
内部日期时间从,到;
公共范围(字符串aFrom、字符串aTo)
{
From=DateTime.ParseExact(aFrom,“dd/mm/yy”,CultureInfo.InvariantCulture);
To=DateTime.ParseExact(aTo,“dd/mm/yy”,CultureInfo.InvariantCulture);
}
}
公共静态整数计算权限(IEnumerable ranges)
{
var vSet=new HashSet();
foreach(范围中的var范围)
对于(var i=范围从;i<范围到;i=i.AddDays(1))vSet.Add(i)
返回vSet.Count;
}
运行示例的代码如下:
01/01/15 - 11/01/15
02/01/15 - 04/01/15
09/01/15 - 13/01/15
18/01/15 - 20/01/15
var vRanges = new List<Range>
{
new Range("01/01/15", "11/01/15"),
new Range("02/01/15", "04/01/15"),
new Range("09/01/15", "13/01/15"),
new Range("18/01/15", "20/01/15"),
};
var v = ComputeNights(vRanges);
var vRanges=新列表
{
新范围(“2015年1月1日”、“2015年11月1日”),
新系列(“2015年1月2日”、“2015年1月4日”),
新系列(“09/01/15”、“13/01/15”),
新系列(“2015年1月18日”、“2015年1月20日”),
};
var v=计算亮度(vRanges);
v计算为14,你可以这样计算:
var laterDateTime = Convert.ToDateTime("11/01/15 ");
var earlierDateTime = Convert.ToDateTime("01/01/15");
TimeSpan dates = laterDateTime - earlierDateTime;
int nights = dates.Days - 1;
你可以把你所有的转换成DateTime。
然后可以使用-运算符减去这两个日期时间。
您的结果将是一种类型的struct TimeSpan
TimeSpan是一个天属性。从中减去1,你就得到了夜晚
两天之间等于一晚三天之间是两晚
4天之间是3夜
我相信你可以做剩下的。你可以这样计算:
var laterDateTime = Convert.ToDateTime("11/01/15 ");
var earlierDateTime = Convert.ToDateTime("01/01/15");
TimeSpan dates = laterDateTime - earlierDateTime;
int nights = dates.Days - 1;
你可以把你所有的转换成DateTime。
然后可以使用-运算符减去这两个日期时间。
您的结果将是一种类型的struct TimeSpan
TimeSpan是一个天属性。从中减去1,你就得到了夜晚
两天之间等于一晚三天之间是两晚
4天之间是3夜
我相信您可以完成剩下的工作。这里有一种使用哈希集的方法:
public static int CountDays(IEnumerable<TimeRange> periods)
{
var usedDays = new HashSet<DateTime>();
foreach (var period in periods)
for (var day = period.Start; day < period.End; day += TimeSpan.FromDays(1))
usedDays.Add(day);
return usedDays.Count;
}
注意:对于较大的日期范围,这不是很有效!如果要考虑大的日期范围,将重叠范围合并为单个范围的方法会更好。
[编辑]修复了使用半开区间而不是闭合区间的代码。这里有一种使用哈希集的方法:
public static int CountDays(IEnumerable<TimeRange> periods)
{
var usedDays = new HashSet<DateTime>();
foreach (var period in periods)
for (var day = period.Start; day < period.End; day += TimeSpan.FromDays(1))
usedDays.Add(day);
return usedDays.Count;
}
注意:对于较大的日期范围,这不是很有效!如果要考虑大的日期范围,将重叠范围合并为单个范围的方法会更好。
[编辑]修复了使用半开放时间间隔而不是封闭时间间隔的代码。假设在1月1日和1月3日之间有两个晚上,这应该有效。如果您已经有了
DateTime
值而不是字符串,则可以去掉解析位。基本上,我使用DateTime.Subtract()
来计算两个日期之间的天数(即夜数)
namespace DateTest1
{
using System;
using System.Collections.Generic;
using System.Globalization;
class Program
{
static void Main(string[] args)
{
var intervals = new List<Tuple<string, string>>
{
new Tuple<string, string>("01/01/15", "11/01/15"),
new Tuple<string, string>("02/01/15", "04/01/15"),
new Tuple<string, string>("09/01/15", "13/01/15"),
new Tuple<string, string>("18/01/15", "20/01/15")
};
var totalNights = 0;
foreach (var interval in intervals)
{
var dateFrom = DateTime.ParseExact(interval.Item1, "dd/MM/yy", CultureInfo.InvariantCulture);
var dateTo = DateTime.ParseExact(interval.Item2, "dd/MM/yy", CultureInfo.InvariantCulture);
var nights = dateTo.Subtract(dateFrom).Days;
Console.WriteLine("{0} - {1}: {2} nights", interval.Item1, interval.Item2, nights);
totalNights += nights;
}
Console.WriteLine("Total nights: {0}", totalNights);
}
}
}
假设在1月1日和1月3日之间有两个晚上,这应该有效。如果您已经有了
DateTime
值而不是字符串,则可以去掉解析位。基本上,我使用DateTime.Subtract()
来计算两个日期之间的天数(即夜数)
namespace DateTest1
{
using System;
using System.Collections.Generic;
using System.Globalization;
class Program
{
static void Main(string[] args)
{
var intervals = new List<Tuple<string, string>>
{
new Tuple<string, string>("01/01/15", "11/01/15"),
new Tuple<string, string>("02/01/15", "04/01/15"),
new Tuple<string, string>("09/01/15", "13/01/15"),
new Tuple<string, string>("18/01/15", "20/01/15")
};
var totalNights = 0;
foreach (var interval in intervals)
{
var dateFrom = DateTime.ParseExact(interval.Item1, "dd/MM/yy", CultureInfo.InvariantCulture);
var dateTo = DateTime.ParseExact(interval.Item2, "dd/MM/yy", CultureInfo.InvariantCulture);
var nights = dateTo.Subtract(dateFrom).Days;
Console.WriteLine("{0} - {1}: {2} nights", interval.Item1, interval.Item2, nights);
totalNights += nights;
}
Console.WriteLine("Total nights: {0}", totalNights);
}
}
}
为了防止您没有足够的答案,这里还有一个使用Linq和
Aggregate
。返回14晚
List<Tuple<DateTime, DateTime>> dates = new List<Tuple<DateTime, DateTime>>
{
Tuple.Create(new DateTime(2015, 1,1), new DateTime(2015, 1,11)),
Tuple.Create(new DateTime(2015, 1,2), new DateTime(2015, 1,4)),
Tuple.Create(new DateTime(2015, 1,9), new DateTime(2015, 1,13)),
Tuple.Create(new DateTime(2015, 1,18), new DateTime(2015, 1,20))
};
var availableDates =
dates.Aggregate<Tuple<DateTime, DateTime>,
IEnumerable<DateTime>,
IEnumerable<DateTime>>
(new List<DateTime>(),
(allDates, nextRange) => allDates.Concat(Enumerable.Range(0, (nextRange.Item2 - nextRange.Item1).Days)
.Select(e => nextRange.Item1.AddDays(e))),
allDates => allDates);
var numDays =
availableDates.Aggregate<DateTime,
Tuple<DateTime, int>,
int>
(Tuple.Create(DateTime.MinValue, 0),
(acc, nextDate) =>
{
int daysSoFar = acc.Item2;
if ((nextDate - acc.Item1).Days == 1)
{
daysSoFar++;
}
return Tuple.Create(nextDate, daysSoFar);
},
acc => acc.Item2);
列表日期=新列表
{
创建(新日期时间(2015,1,1),新日期时间(2015,1,11)),
创建(新日期时间(2015,1,2),新日期时间(2015,1,4)),
创建(新日期时间(2015,1,9),新日期时间(2015,1,13)),
创建(新日期时间(2015,1,18),新日期时间(2015,1,20))
};
var availableDates=
日期.合计
(新列表(),
(allDates,nextRange)=>allDates.Concat(Enumerable.Range(0,(nextRange.Item2-nextRange.Item1).Days)
.Select(e=>nextRange.Item1.AddDays(e)),
allDates=>allDates);
变量numDays=
可用数据。聚合
(Tuple.Create(DateTime.MinValue,0),
(附件,下一日期)=>
{
int daysSoFar=附件项目2;
如果((下一个日期-附件项1).Days==1)
{