日期范围内的天数,不包括周末和其他日期,以C#表示
本文关键字:日期 其他 表示 不包括 范围内 周末 | 更新日期: 2023-09-27 18:00:52
我有一个C#方法,如下所示:
public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, String excludeDates)
{
}
它应该计算startDate和endDate之间的天数,但也可以选择排除周末和其他日期(以逗号分隔的日期字符串形式传入(。
我完全不知道如何解决这个问题。我的直觉是从startDate到endDate循环,并进行一些字符串比较,但据我所知,C#不允许以这种方式循环日期——或者至少这不是一种非常优雅的做事方式。
哦,循环浏览日期真的很容易——这根本不是问题:
// I'm assuming you want <= to give an *inclusive* end date...
for (DateTime date = start; date <= end; date = date.AddDays(1))
{
// Do stuff with date
}
您也可以很容易地编写IEnumerable<DateTime>
,并使用foreach
。
如果可能的话,我会尽量避免在这里执行字符串操作——从根本上说,这些日期不是字符串,所以如果你能尽可能地在问题域中工作,这会让事情变得更容易。
当然,可能有比循环更有效的方法,但它们更难正确。如果循环在性能方面还可以,我会坚持下去。
作为我自己的开源项目的一个快速插件,Noda Time有一组更为多样的类型来表示日期和时间——在这种情况下,您将使用LocalDate
。这样你就不必担心如果"开始"的时间晚于"结束"的时间会发生什么。另一方面,Noda time还没有真正结束。。。您需要的比特已经准备好了,应该可以正常工作,但API可能在未来仍然会改变。
编辑:如果确实需要频繁地循环日期,您可能需要类似于以下扩展方法(将其放在顶级非通用静态类中(:
public static IEnumerable<DateTime> To(this DateTime start, DateTime end)
{
Date endDate = end.Date;
for (DateTime date = start.Date; date <= endDate; date = date.AddDays(1))
{
yield return date;
}
}
然后:
foreach (DateTime date in start.To(end))
{
...
}
这里有一个例子,包括排除的日期、周末和循环。不过,我确实将excludeDates字符串更改为List。应该添加一些null检查。
public static int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, List<DateTime> excludeDates)
{
int count = 0;
for (DateTime index = startDate; index < endDate; index = index.AddDays(1))
{
if (excludeWeekends && index.DayOfWeek != DayOfWeek.Sunday && index.DayOfWeek != DayOfWeek.Saturday)
{
bool excluded = false; ;
for (int i = 0; i < excludeDates.Count; i++)
{
if (index.Date.CompareTo(excludeDates[i].Date) == 0)
{
excluded = true;
break;
}
}
if (!excluded)
{
count++;
}
}
}
return count;
}
编辑:我确实想指出,如果你不必经常这样做的话,我会认为这是一种快速而肮脏的方法。如果你经常这样做,并且startDate和endDate之间的距离相当大,那么最好按照其他答案中的一个进行计算。建议这样做是为了获得迭代日期的感觉。
Subsonic糖库有很多助手来处理DateTime操作。
你可以在Subsonic网站上找到完整的列表,源代码在github中。
结合LINQ表达式,
public int GetNoOfLeaveDays(DateTime fromDate, DateTime toDate, Boolean excludeWeekends, List<DateTime> excludeDates)
{
var count = 0;
for (DateTime index = fromDate; index <= toDate; index = index.AddDays(1))
{
if (!excludeWeekends || index.DayOfWeek == DayOfWeek.Saturday || index.DayOfWeek == DayOfWeek.Sunday) continue;
var excluded = excludeDates.Any(t => index.Date.CompareTo(t.Date) == 0);
if (!excluded) count++;
}
return count;
}
下面是我在SQL中使用的不同方法的伪代码:
查找两个日期之间的总天数
减去周末数
如果开始日期是星期日,则删除一天
如果开始日期是星期六,则删除一天
删除你不想要的任何其他日子(请参阅我上面的评论,了解如何在c#中做到这一点(
这可能有效并避免O(n(类型的解决方案:
public int DaysLeft(DateTime startDate, DateTime endDate, Boolean excludeWeekends, String excludeDates)
{
//Work out days in range
int days = (int)endDate.Subtract(startDate).TotalDays + 1;
if (excludeWeekends)
{
//Remove most weekends by removing 2 in 7 days (rounded down)
days -= ((int)Math.Floor((decimal)(days / 7)) * 2);
if (startDate.DayOfWeek == DayOfWeek.Sunday) days -= 1;
if (startDate.DayOfWeek == DayOfWeek.Saturday) days -= 2;
}
return days;
}
不过,它并没有经过详尽的测试。
为了处理排除日期,你可以循环浏览这些日期,并排除它们在开始和结束之间的位置(如果合适的话,也可以不是周末(。这应该是一个比从开始到结束的所有日子更短的循环。
private int workingdays(int month,int year)
{
int daysInMonth = 0;
int days = DateTime.DaysInMonth(year, month);
for (int i = 1; i <= days; i++)
{
DateTime day = new DateTime(year, month, i);
if (day.DayOfWeek != DayOfWeek.Sunday && day.DayOfWeek != DayOfWeek.Saturday)
{
daysInMonth++;
}
}
return daysInMonth;
}