首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >月中第九个工作日返回

月中第九个工作日返回
EN

Code Review用户
提问于 2015-08-11 16:48:52
回答 5查看 4.2K关注 0票数 8

我的目标是获得一个月的第九个工作日。参数是一个给定月份的日期,也是我试图获取的第九个工作日的日期。如果存在,它将返回月份的第N个工作日,并返回DateTime.MinValue。就我的目的而言,平日是F-F。

是否有一种更优雅或更有效的方法来实现这个逻辑?我的实现感觉很粗糙,基本上是一个while循环,它可以计算工作日,直到找到想要的日期或月底。

代码语言:javascript
运行
复制
    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;
    }

用法

代码语言:javascript
运行
复制
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
EN

回答 5

Code Review用户

回答已采纳

发布于 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语句。

让我告诉你我的意思:

代码语言:javascript
运行
复制
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语句中,如果您不必这样做,它可能会变得非常混乱。

票数 8
EN

Code Review用户

发布于 2015-08-11 17:37:05

我还不清楚一个月的“第九个工作日”会是什么样子。从API的角度来看,特别令人困惑的是,您正在传递一个DateTime,但是您只使用了它的YearMonth部分,而放弃了所有其他部分。

接受一个int,并验证它的值在1到12之间,将使API更加友好。

代码语言:javascript
运行
复制
/// <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;

我不认为这是个好主意。下面是我验证输入的大致方式:

代码语言:javascript
运行
复制
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=13n=42,那么应用程序中显然有一个严重的错误,通过返回一个“神奇”的DateTime.MinValue,您无法阻止流血。在这种特殊情况下,抛出一个异常是正确的。

票数 7
EN

Code Review用户

发布于 2015-08-11 21:53:58

为了避免手动循环,我会以更声明的方式处理它,因为我发现这很难阅读和修改。这种方法与Day在他的回答中所做的类似,但我的代码首先是在单独的生成器方法中生成日期,而不是生成数字。

需要使用C#生成器(产率)使代码更冗长,并且需要额外的函数,但我认为这是值得的。

代码语言:javascript
运行
复制
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);
    }
}

备注:

  • 方法的返回类型更改为DateTime?,因为正如其他人所指出的,null比DateTime.MinValue更有意义。
  • 输入类型从DateTime更改为年份和月份,因为只有这些类型是真正必需的。
  • NodaTime的本地日期类型将更好地表示这里的返回类型。DateTime还包含时间组件和不必要的混乱,这使得代码不那么清晰。
票数 7
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/100609

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档