[英]How do I determine the nth day of type for a given date time in c#?
I developed an extension method that solves this specific problem, and I have posted that code below. 我开发了一种扩展方法来解决此特定问题,并将该代码张贴在下面。 I hope it helps someone out. 我希望它可以帮助某人。
I have been tasked with adding functionality to an app which will allow setting up recurring meetings (exactly the same way as Outlook does). 我的任务是向应用程序添加功能,该功能将允许设置定期会议(与Outlook完全相同)。
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. 我一直在努力地进行这项工作,但我一直认为必须已经有了一些东西。
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: 一个简单的用法示例,用于获取最接近传递日期的月份的第二个 * Monday *:
var newDate= someDate.GetNextDateOfType("second", "Monday");
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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.