从两个日期获取工作日范围
Get weekday range from two dates
我在 SQL 中有一个 UDF table 函数,其功能如下
select * from dbo.GetWeekdayRange(convert(datetime, '11/03/2015', 103), convert(datetime, '31/03/2015', 103))
输出:
WeekStartDate WeekEndDate
-------------------------------------------------
2015-03-11 00:00:00.000 2015-03-15 00:00:00.000
2015-03-16 00:00:00.000 2015-03-22 00:00:00.000
2015-03-23 00:00:00.000 2015-03-29 00:00:00.000
2015-03-30 00:00:00.000 2015-03-31 00:00:00.000
C#中有这样的函数吗?我也尝试过使用 LINQ,但未能成功。我尝试搜索它,但我没有找到它们。
这可以很容易地在 C# 中复制,我相信有一个更有效的解决方案,但这个有效:
public static IEnumerable<DateRange> GetWeekdayRange(DateTime startDate, DateTime endDate, DayOfWeek weekEndsOn = DayOfWeek.Sunday)
{
var currStartDate = startDate;
var currDate = startDate;
while(currDate<endDate)
{
while(currDate.DayOfWeek != weekEndsOn && currDate<endDate)
{
currDate = currDate.AddDays(1);
}
yield return new DateRange{ WeekStartDate = currStartDate,WeekEndDate = currDate};
currStartDate = currDate.AddDays(1);
currDate = currStartDate;
}
}
public struct DateRange
{
public DateTime WeekStartDate{get;set;}
public DateTime WeekEndDate{get;set;}
}
测试代码
var start = new DateTime(2015,3,11);
var end = new DateTime(2015,3,31);
var range = GetWeekdayRange(start,end);
foreach(var val in range)
{
Console.WriteLine("{0:yyyy-MM-dd} - {1:yyyy-MM-dd}",val.WeekStartDate,val.WeekEndDate);
}
输出:
2015-03-11 - 2015-03-15
2015-03-16 - 2015-03-22
2015-03-23 - 2015-03-29
2015-03-30 - 2015-03-31
实例:http://rextester.com/DGSX37215
如果你真的想要一个更像 LINQ 的解决方案,你可以这样做——我发现它更难阅读和理解正在发生的事情,但它提供了相同的输出。它使用日历将日期列表分组为周,然后从组
中选择 Min
和 Max
public static IEnumerable<DateRange> GetWeekdayRange(DateTime startDate, DateTime endDate, DayOfWeek weekStartsOn = DayOfWeek.Monday)
{
var diff = endDate.Subtract(startDate).Days;
var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
var range = Enumerable.Range(0,diff+1).Select(v => startDate.AddDays(v))
.Select(d => new {Date=d, WeekNumber=cal.GetWeekOfYear(d, System.Globalization.CalendarWeekRule.FirstDay, weekStartsOn) })
.GroupBy(g => g.WeekNumber);
return range.Select(g => new DateRange{WeekStartDate=g.Min(v => v.Date), WeekEndDate= g.Max(v => v.Date)});
}
我在 SQL 中有一个 UDF table 函数,其功能如下
select * from dbo.GetWeekdayRange(convert(datetime, '11/03/2015', 103), convert(datetime, '31/03/2015', 103))
输出:
WeekStartDate WeekEndDate
-------------------------------------------------
2015-03-11 00:00:00.000 2015-03-15 00:00:00.000
2015-03-16 00:00:00.000 2015-03-22 00:00:00.000
2015-03-23 00:00:00.000 2015-03-29 00:00:00.000
2015-03-30 00:00:00.000 2015-03-31 00:00:00.000
C#中有这样的函数吗?我也尝试过使用 LINQ,但未能成功。我尝试搜索它,但我没有找到它们。
这可以很容易地在 C# 中复制,我相信有一个更有效的解决方案,但这个有效:
public static IEnumerable<DateRange> GetWeekdayRange(DateTime startDate, DateTime endDate, DayOfWeek weekEndsOn = DayOfWeek.Sunday)
{
var currStartDate = startDate;
var currDate = startDate;
while(currDate<endDate)
{
while(currDate.DayOfWeek != weekEndsOn && currDate<endDate)
{
currDate = currDate.AddDays(1);
}
yield return new DateRange{ WeekStartDate = currStartDate,WeekEndDate = currDate};
currStartDate = currDate.AddDays(1);
currDate = currStartDate;
}
}
public struct DateRange
{
public DateTime WeekStartDate{get;set;}
public DateTime WeekEndDate{get;set;}
}
测试代码
var start = new DateTime(2015,3,11);
var end = new DateTime(2015,3,31);
var range = GetWeekdayRange(start,end);
foreach(var val in range)
{
Console.WriteLine("{0:yyyy-MM-dd} - {1:yyyy-MM-dd}",val.WeekStartDate,val.WeekEndDate);
}
输出:
2015-03-11 - 2015-03-15
2015-03-16 - 2015-03-22
2015-03-23 - 2015-03-29
2015-03-30 - 2015-03-31
实例:http://rextester.com/DGSX37215
如果你真的想要一个更像 LINQ 的解决方案,你可以这样做——我发现它更难阅读和理解正在发生的事情,但它提供了相同的输出。它使用日历将日期列表分组为周,然后从组
中选择Min
和 Max
public static IEnumerable<DateRange> GetWeekdayRange(DateTime startDate, DateTime endDate, DayOfWeek weekStartsOn = DayOfWeek.Monday)
{
var diff = endDate.Subtract(startDate).Days;
var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
var range = Enumerable.Range(0,diff+1).Select(v => startDate.AddDays(v))
.Select(d => new {Date=d, WeekNumber=cal.GetWeekOfYear(d, System.Globalization.CalendarWeekRule.FirstDay, weekStartsOn) })
.GroupBy(g => g.WeekNumber);
return range.Select(g => new DateRange{WeekStartDate=g.Min(v => v.Date), WeekEndDate= g.Max(v => v.Date)});
}