简体   繁体   中英

How do I determine the nth day of type for a given date time in c#?

UPDATE 6/1/2013

I developed an extension method that solves this specific problem, and I have posted that code below. I hope it helps someone out.

Background

I have been tasked with adding functionality to an app which will allow setting up recurring meetings (exactly the same way as Outlook does).

So, for example, a user may want to set up a meeting that occurs the first Friday of each month , or the last Monday of each month , or the second weekday of each month, and so on.

Does a standard algorithm for this exist? I have found plenty of partial answers, but nothing that, say, allows for a clean extension method like this:

  /// <summary>
        /// Accepts a date object and finds the next date given an ordinality and type.
        /// </summary>
        /// <param name="ordinality">The ordinality (e.g. "first", "second", "last", etc.)</param>
        /// <param name="dayType">The day type (e.g. "weekday", "Monday", "day", etc)</param>
        /// <returns>A new date object</returns>
 public static DateTime GetNextDateOfType(this DateTime date, string ordinality, string dayType)
 {
 //do stuff
return newDate;
}

I have been working on this in fits and starts, but I keep thinking there must be something already out there.

What I have so far:

     public static DateTime GetNextDateOfType(this DateTime date, string ordinality, string dayType)
        {
            var dateTest = new DateTime(date.Year, date.Month, 1);
            var dateFound = false;
            var ordinal = 1;
            var targetOrdinal = ordinality.ToOrdinal();

            while (!dateFound)
            {
                //Test for type:
                switch (dayType)
                {
                    case "day":
                        if (dateTest >= date)
                        {
                            if (ordinality == "last" && dateTest == dateTest.GetLastDayOfMonth() || dateTest.Day == targetOrdinal)
                            {
                                dateFound = true;
                            }
                        }
                        break;
                    case "weekday":
                        if (dateTest >= date && dateTest.IsWeekDay())
                        {
                            if (targetOrdinal == ordinal)
                            {
                                dateFound = true;
                            }
                            ordinal++;
                        }
                        break;
                    case "weekend day":
                        if (dateTest >= date && !dateTest.IsWeekDay())
                        {
                            dateFound = true;
                        }
                        break;
                    default:
                        if (dateTest >= date && dateTest.DayOfWeek == HelperMethods.GetDayOfWeekFromString(dayType))
                        {
                            dateFound = true;
                        }
                        break;
                }

                dateTest = dateTest.AddDays(1);

            }

            return dateTest;
        }

   public static DateTime GetLastDayOfMonth(this DateTime date)
        {
            return new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
        }

        public static int ToOrdinal(this string ordinal)
        {
            var result = 0;
            switch (ordinal.ToLower())
            {
                case "first":
                    result = 1;
                    break;
                case "second":
                    result = 2;
                    break;
                case "third":
                    result = 3;
                    break;
                case "fourth":
                    result = 4;
                    break;
                case "fifth":
                    result = 5;
                    break;
                default:
                    result = -1;
                    break;
            }
            return result;
        }

        public static bool IsWeekDay(this DateTime date)
        {
            var weekdays = new List<DayOfWeek>
                {
                    DayOfWeek.Monday,
                    DayOfWeek.Tuesday,
                    DayOfWeek.Wednesday,
                    DayOfWeek.Thursday,
                    DayOfWeek.Friday
                };

            return weekdays.Contains(date.DayOfWeek);
        }

        public static List<DateTime> GetWeeks(this DateTime month, DayOfWeek startOfWeek)
        {
            var firstOfMonth = new DateTime(month.Year, month.Month, 1);
            var daysToAdd = ((Int32)startOfWeek - (Int32)month.DayOfWeek) % 7;
            var firstStartOfWeek = firstOfMonth.AddDays(daysToAdd);

            var current = firstStartOfWeek;
            var weeks = new List<DateTime>();
            while (current.Month == month.Month)
            {
                weeks.Add(current);
                current = current.AddDays(7);
            }

            return weeks;
        }

        public static int GetWeekOfMonth(this DateTime date)
        {
            var beginningOfMonth = new DateTime(date.Year, date.Month, 1);

            while (date.Date.AddDays(1).DayOfWeek != CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
                date = date.AddDays(1);

            return (int)Math.Truncate((double)date.Subtract(beginningOfMonth).TotalDays / 7f) + 1;
        }

After struggling with this for a while, here is the solution I came up with. It is an extension method (with other referenced extension methods beneath it). This is not my most elegant code, but it works. I will update the code later if I streamline it in my own environment.

Simple usage example for getting the second *Monday* of a month closest to the passed-in date:

var newDate= someDate.GetNextDateOfType("second", "Monday");

The code:

    public static DateTime GetNextDateOfType(this DateTime date, string ordinality, string dayType)
            {
                var targetOrdinal = ordinality.ToOrdinal();
                var dateTest = (targetOrdinal > -1) ? new DateTime(date.Year, date.Month, 1) : date.GetLastDayOfMonth();
                var dateFound = false;
                var ordinal = 1;
                var ordinalReset = false;

                if (targetOrdinal > -1) //All cases EXCEPT "last"
                {
                    while (!dateFound)
                    {
                        if (dateTest.Month > date.Month && !ordinalReset)
                        {
                            ordinal = 1;
                            ordinalReset = true;
                        }

                        //Test for type:
                        switch (dayType)
                        {
                            case "day":
                                if (dateTest >= date)
                                {
                                    if (dateTest.Day == targetOrdinal)
                                    {
                                        dateFound = true;
                                    }
                                }
                                break;
                            case "weekday":
                                if (dateTest >= date && dateTest.IsWeekDay())
                                {
                                    if (targetOrdinal == ordinal)
                                    {
                                        dateFound = true;
                                    }
                                }

                                if (dateTest.IsWeekDay())
                                {
                                    ordinal++;
                                }

                                break;
                            case "weekend day":
                                if (dateTest >= date && !dateTest.IsWeekDay())
                                {
                                    if (targetOrdinal == ordinal)
                                    {
                                        dateFound = true;
                                    }
                                }
                                if (!dateTest.IsWeekDay())
                                {
                                    ordinal++;
                                }

                                break;
                            default:
                                if (dateTest >= date && dateTest.DayOfWeek == HelperMethods.GetDayOfWeekFromString(dayType))
                                {
                                    if (targetOrdinal == ordinal)
                                    {
                                        dateFound = true;
                                    }
                                }

                                if (dateTest.DayOfWeek == HelperMethods.GetDayOfWeekFromString(dayType))
                                {
                                    ordinal++;
                                }
                                break;
                        }
                        dateTest = (dateFound) ? dateTest : dateTest.AddDays(1);
                    }
                }
                else //for "last"
                {
                    while (!dateFound)
                    {
                        if (dateTest <= date && !ordinalReset)
                        {
                            dateTest = date.GetLastDayOfMonth().AddMonths(1);
                            ordinalReset = true;
                        }

                        //Test for type:
                        switch (dayType)
                        {
                            case "day":
                                dateFound = true;
                                break;
                            case "weekday":
                                if (dateTest.IsWeekDay())
                                {
                                        dateFound = true;
                                }

                                break;
                            case "weekend day":
                                if (!dateTest.IsWeekDay())
                                {
                                    dateFound = true;
                                }
                                break;
                            default:
                                if (dateTest.DayOfWeek == HelperMethods.GetDayOfWeekFromString(dayType))
                                {
                                    dateFound = true;
                                }
                                break;
                        }
                        dateTest = (dateFound) ? dateTest : dateTest.AddDays(-1);
                    }
                }
                return dateTest;
            }

            public static DateTime GetLastDayOfMonth(this DateTime date)
            {
                return new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
            }

            public static int ToOrdinal(this string ordinal)
            {
                var result = 0;
                switch (ordinal.ToLower())
                {
                    case "first":
                        result = 1;
                        break;
                    case "second":
                        result = 2;
                        break;
                    case "third":
                        result = 3;
                        break;
                    case "fourth":
                        result = 4;
                        break;
                    case "fifth":
                        result = 5;
                        break;
                    default:
                        result = -1;
                        break;
                }
                return result;
            }

            public static bool IsWeekDay(this DateTime date)
            {
                var weekdays = new List<DayOfWeek>
                    {
                        DayOfWeek.Monday,
                        DayOfWeek.Tuesday,
                        DayOfWeek.Wednesday,
                        DayOfWeek.Thursday,
                        DayOfWeek.Friday
                    };

                return weekdays.Contains(date.DayOfWeek);
            }

            public static List<DateTime> GetWeeks(this DateTime month, DayOfWeek startOfWeek)
            {
                var firstOfMonth = new DateTime(month.Year, month.Month, 1);
                var daysToAdd = ((Int32)startOfWeek - (Int32)month.DayOfWeek) % 7;
                var firstStartOfWeek = firstOfMonth.AddDays(daysToAdd);

                var current = firstStartOfWeek;
                var weeks = new List<DateTime>();
                while (current.Month == month.Month)
                {
                    weeks.Add(current);
                    current = current.AddDays(7);
                }

                return weeks;
            }

            public static int GetWeekOfMonth(this DateTime date)
            {
                var beginningOfMonth = new DateTime(date.Year, date.Month, 1);

                while (date.Date.AddDays(1).DayOfWeek != CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
                    date = date.AddDays(1);

                return (int)Math.Truncate((double)date.Subtract(beginningOfMonth).TotalDays / 7f) + 1;
            }


 public static DayOfWeek GetDayOfWeekFromString(string day)
        {
            var dow = DayOfWeek.Sunday;
            switch (day)
            {
                case "Sunday":
                    dow = DayOfWeek.Sunday;
                    break;
                case "Monday":
                    dow = DayOfWeek.Monday;
                    break;
                case "Tuesday":
                    dow = DayOfWeek.Tuesday;
                    break;
                case "Wednesday":
                    dow = DayOfWeek.Wednesday;
                    break;
                case "Thursday":
                    dow = DayOfWeek.Thursday;
                    break;
                case "Friday":
                    dow = DayOfWeek.Friday;
                    break;
                case "Saturday":
                    dow = DayOfWeek.Saturday;
                    break;
            }

            return dow;
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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