简体   繁体   English

如何提高IsItAHoliday函数的效率?

[英]How can I make my IsItAHoliday function more efficient?

I have a method that is supposed to return 1 if it is a weekend or one of these holidays: New Years Day, Memorial Day, Independence Day, Labor Day, Thanksgiving Day & Christmas Day, and 0 otherwise. 我有一种方法,如果是周末或以下假期之一,则应该返回1:元旦,阵亡将士纪念日,独立日,劳动节,感恩节和圣诞节,否则返回0。 I have chosen to implement the code using a combination of DateTime.DayOfYear and DateTime.IsLeapYear, but I feel like this is really inefficient, and also, makes it more difficult to do holidays like Memorial Day (final Monday of May!). 我选择使用DateTime.DayOfYear和DateTime.IsLeapYear的组合来实现代码,但是我觉得这确实效率低下,而且也使得像阵亡将士纪念日(5月的最后一个星期一)这样的假期变得更加困难。 How can I achieve my goal efficiently, and without hardcoding the holidays that change dates every year? 如何在不对每年更改日期的假期进行硬编码的情况下有效地实现自己的目标?

Here is my current implementation: 这是我当前的实现:

    private int IsItAHoliday(DateTime time)
    {
        // Assume it is not a weekend
        int isWeekendOrHoliday = 0;

        // TODO: Memorial Day, Labor Day, Thanksgiving
        // Declare holidays
        int christmasDayNonLeapYearIndex = 359;
        int christmasDayLeapYearIndex = 360;
        int newYearsDayIndex = 1;
        int independenceDayNonLeapYearIndex = 185;
        int independenceDayLeapYearIndex = 186;

        // Find out if time falls on a weekend
        if (time.DayOfWeek == DayOfWeek.Saturday || time.DayOfWeek == DayOfWeek.Sunday)
        {
            isWeekendOrHoliday = 1;
        }
        // Find out if time falls on a holiday
        // Leap year
        if (DateTime.IsLeapYear(time.Year))
        {
            if ((time.DayOfYear == christmasDayLeapYearIndex) || (time.DayOfYear == independenceDayLeapYearIndex) || (time.DayOfYear == newYearsDayIndex))
            {
                isWeekendOrHoliday = 1;
            }
        }
        // Non-leap year
        else if (!DateTime.IsLeapYear(time.Year))
        {
            if ((time.DayOfYear == christmasDayNonLeapYearIndex) || (time.DayOfYear == independenceDayNonLeapYearIndex) || (time.DayOfYear == newYearsDayIndex))
            {
                isWeekendOrHoliday = 1;
            }
        }

        return isWeekendOrHoliday;
    }

Common approach is to define set of rules that describes a holiday date: 常见方法是定义描述假期的规则集:

public interface IHoliday
{
  bool isHoliday(DateTime date);
}

Then implement the interfaces for different holiday schemas. 然后为不同的假期模式实现接口。 For example, exact date holiday: 例如,确切的日期假期:

public class ExactDayHoliday : IHoliday
{
  public int Day {get; set;}
  public int Month {get; set;}

  public bool isHoliday(DateTime date)
  {
    return date.Month == month && date.Day == day;
  }
}

Another example of rule: a day of n-th weeks of the month. 规则的另一个示例:每月第n周的某天。

public class DayOfWeekHoliday : IHoliday
{
    public int Nth { get; set; }
    public DayOfWeek DayOfWeek { get; set; }
    public int Month { get; set; }

    public bool isHoliday(DateTime date)
    {
        return date.Month == Month && date.DayOfWeek == DayOfWeek && (date.Day - 1) / 7 == (Nth - 1);
    }
} 

Create list of rules for all holidays. 创建所有假期的规则列表。 For example: 例如:

List<IHoliday> holidays = new List<IHoliday> {new ExactDayHoliday {Month = 12, Day = 25}, new DayOfWeekHoliday {Nth = 1, DayOfWeek = DayOfWeek.Monday, Month = 9}};

And the last step (check for given date): 最后一步(检查给定日期):

bool isHoliday = holidays.Any(rule => rule.IsHoliday(date));

I Suggest you use Enumerations if you will be hard coding every event you need your application to support for example : 我建议您使用枚举,如果您要对需要应用程序支持的每个事件进行硬编码,例如:

    public enum Holidays{
    newYearsDayIndex = 1,
    independenceDayNonLeapYearIndex = 185,
        independenceDayLeapYearIndex = 186,
    christmasDayNonLeapYearIndex = 359,
        christmasDayLeapYearIndex = 360
    }

Then use the value of each as the day index of a holiday and the name to explain why this day is a holiday 然后使用每个的值作为假期的天数索引和名称,以说明为什么今天是假期

    Enum.GetValues(typeof(Holidays)); --> For values which you will use as days Index
    Enum.GetNames(typeof(Holidays)); --> For Names which you will use to describe the picked date

You may also consider separating Leap holidays and non leap holidays each in separate Enumeration with your naming conventions 您也可以考虑使用命名约定分别将Le假期和非leap假期分开枚举

You dont need to check for YEAR in holidays , because they appear on the same dates every year, like say Dec 25, 1 Jan etc. 您无需在假期检查YEAR ,因为它们每年出现在相同的日期,例如12月25日,1月1日等。

I quickly compiled some code: 我迅速编译了一些代码:

public class Holiday
{
    public int Day {get; private set;}
    public int Month {get; private set;}
    public Holiday(int day, int month)
    {
        this.Day = day;
        this.Month = month;
    }

    public bool IsEqual(DateTime dateTime)
    {
        return ((this.Day == dateTime.Day) && (this.Month == dateTime.Month));
    }
}

public static class DateTimeExtensions
{
    private static List<Holiday> holidays = new List<Holiday>();

    public static void RegisterHoliday(Holiday holiday)
    {
        holidays.Add(holiday);
    }

    public static bool IsHoliday(this DateTime dateTime)
    {
        foreach (Holiday holiday in holidays)
        {
            if (holiday.IsEqual(dateTime)) return true;
        }
        return false;
    }

    public static bool IsWeekend(this DateTime dateTime)
    {
        return (dateTime.DayOfWeek == DayOfWeek.Sunday) || (dateTime.DayOfWeek == DayOfWeek.Saturday);
    }
}

Now Add Holidays using the Register method and use the extensions. 现在,使用Register方法添加Holidays并使用扩展名。 DateTimeExtensions.RegisterHoliday(new Holiday(25, 12));

DateTime dateTimeToCheck = new DateTime(2013, 12, 25); return dateTimeToCheck.IsHoliday() || dateTimeToCheck.IsWeekend();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM