我的目标是获得一个月的第九个工作日。参数是一个给定月份的日期,也是我试图获取的第九个工作日的日期。如果存在,它将返回月份的第N个工作日,并返回DateTime.MinValue
。就我的目的而言,平日是F-F。
是否有一种更优雅或更有效的方法来实现这个逻辑?我的实现感觉很粗糙,基本上是一个while循环,它可以计算工作日,直到找到想要的日期或月底。
public static DateTime getNthWeekdayOfMonth(DateTime date, int nthWeekday)
{
//Valid inputs are greater than 0 but less than 24
if (nthWeekday > 23 || nthWeekday < 1)
return DateTime.MinValue;
//start with 1st day of month from date param
DateTime currentDay = new DateTime(date.Year, date.Month, 1);
int i = 0;
while(i < nthWeekday && currentDay.Month == date.Month)
{
if (currentDay.DayOfWeek != DayOfWeek.Saturday && currentDay.DayOfWeek != DayOfWeek.Sunday)
{
i++;
if(i == nthWeekday)
return currentDay;
}
currentDay = currentDay.AddDays(1);
}
return DateTime.MinValue;
}
用法
var date1 = getNthWeekdayOfMonth(new DateTime(2015, 8, 11), 22);
//returns DateTime.MinValue
var date2 = getNthWeekdayOfMonth(new DateTime(2015, 8, 11), 21);
//returns 8/31/2015
var date3 = getNthWeekdayOfMonth(new DateTime(2015, 8, 11), 1);
//returns 8/3/2015
发布于 2015-08-11 17:05:52
int i = 0; while(i < nthWeekday && currentDay.Month == date.Month) { if (currentDay.DayOfWeek != DayOfWeek.Saturday && currentDay.DayOfWeek != DayOfWeek.Sunday) { i++; if(i == nthWeekday) return currentDay; } currentDay = currentDay.AddDays(1); }
while循环有点混乱--让我们先清理一下,并且应该有一个早期的continue
语句。
让我告诉你我的意思:
int i = 1;
while(i <= nthWeekday && currentDay.Month == date.Month)
{
bool isWeekendDay = currentDay.DayOfWeek == DayOfWeek.Saturday || currentDay.DayOfWeek == DayOfWeek.Sunday;
if (isWeekendDay)
{
currentDay = currentDay.AddDays(1);
continue;
}
if (i == nthWeekday)
{
return currentDay;
}
currentDay = currentDay.AddDays(1);
i++;
}
这是一个更干净的,并确切地显示了我们的意图。读起来容易多了。
您不应该将if语句嵌套到其他if语句中,如果您不必这样做,它可能会变得非常混乱。
发布于 2015-08-11 17:37:05
我还不清楚一个月的“第九个工作日”会是什么样子。从API的角度来看,特别令人困惑的是,您正在传递一个DateTime
,但是您只使用了它的Year
和Month
部分,而放弃了所有其他部分。
接受一个int
,并验证它的值在1到12之间,将使API更加友好。
/// <summary>
/// Computes the date of the nth workday in specified month of specified year,
/// assuming Monday-Friday work weeks.
/// </summary>
public static DateTime WorkdayOfMonth(int year, int month, int n)
注意,XML和PascalCase
注释澄清了用法和假设。
//Valid inputs are greater than 0 but less than 24 if (nthWeekday > 23 || nthWeekday < 1) return DateTime.MinValue;
我不认为这是个好主意。下面是我验证输入的大致方式:
if (month < 1 || month > 12)
{
throw new ArgumentException("Invalid 'month' parameter.");
}
if (n < 1 || n > 23)
{
throw new ArgumentException("Specified 'n' parameter would be for a date outside the specified 'month'.");
}
无情:如果给您的方法参数不允许它正常工作,那么您不应该返回一个有效的DateTime
返回值。另一种选择可能是返回一个空DateTime?
,但在我看来,如果这个函数被赋予month=13
和n=42
,那么应用程序中显然有一个严重的错误,通过返回一个“神奇”的DateTime.MinValue
,您无法阻止流血。在这种特殊情况下,抛出一个异常是正确的。
发布于 2015-08-11 21:53:58
为了避免手动循环,我会以更声明的方式处理它,因为我发现这很难阅读和修改。这种方法与Day在他的回答中所做的类似,但我的代码首先是在单独的生成器方法中生成日期,而不是生成数字。
需要使用C#生成器(产率)使代码更冗长,并且需要额外的函数,但我认为这是值得的。
public DateTime? GetNthWeekdayOfMonth(int year, int month, int n)
{
if (month < 1 || month > 12)
{
throw new ArgumentException("Invalid 'month' parameter", "month");
}
if (n < 1)
{
throw new ArgumentException("Argument specifying the nth workday must be positive", "n");
}
return GenerateDays(year, month)
.TakeWhile(d => d.Month == month)
.Where(d => d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)
.Skip(n - 1)
.Cast<DateTime?>()
.FirstOrDefault();
}
/// <summary>
/// Generates the infinite sequence of subsequent days beginning with the first day of specified month in the specified year.
/// </summary>
private IEnumerable<DateTime> GenerateDays(int fromYear, int fromMonth)
{
var date = new DateTime(fromYear, fromMonth, 1);
while (true)
{
yield return date;
date = date.AddDays(1);
}
}
备注:
https://codereview.stackexchange.com/questions/100609
复制相似问题