我正在努力寻找一种简单而有效的解决方案来计算一个月的工作日。例如,如果给定日期是第一个星期一Monday 5th March 2018
,那么我想获得接下来6个月中每个月的第一个星期一的日期,例如:Monday 2nd April 2018
和Monday 3rd May 2018
等等上。
我尝试使用this question中的以下代码。但是,下面的代码只返回我希望它返回整个日期的周数。
static class DateTimeExtensions
{
static GregorianCalendar _gc = new GregorianCalendar();
public static int GetWeekOfMonth(this DateTime time)
{
DateTime first = new DateTime(time.Year, time.Month, 1);
return time.GetWeekOfYear() - first.GetWeekOfYear() + 1;
}
static int GetWeekOfYear(this DateTime time)
{
return _gc.GetWeekOfYear(time, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
}
}
但我很困惑,不知道如何修改上面的代码来解决这个问题。任何帮助将不胜感激。
答案 0 :(得分:4)
最近微软发布了 DateTimeRecognizer project on GitHub 它允许您将自然语言日期时间解析为Plain Old C# DateTime对象。它经过了彻底的测试,所以没有猴子在那里工作。
他们还发布了同样的nuget包。您可以通过nuget包管理器安装。
首先安装nuget包:
然而,所有这一切都是不碍事的。我开发了一个小型实用程序,它首先从自然语言中提取日期时间,然后查找下个月同一天的第一次出现日期。
using Microsoft.Recognizers.Text;
using Microsoft.Recognizers.Text.DateTime;
using System;
using System.Collections.Generic;
using System.Linq;
namespace RecognizerDemo
{
class Program
{
static void Main(string[] args)
{
try
{
string Query = string.Empty;
Console.WriteLine("Enter date: ");
Query = Console.ReadLine();
DateTime parsedDate = ExtractDateFromNaturalLanguage(Query);
List<DateTime> futureDates = GetSubsequentDateTimes(parsedDate);
foreach (var item in futureDates)
{
Console.WriteLine(item.ToLongDateString());
}
}
catch(Exception ex)
{
Console.WriteLine($"Failed because: {ex.Message}");
}
}
static List<DateTime> GetSubsequentDateTimes(DateTime date)
{
try
{
List<DateTime> futureDates = new List<DateTime>();
DayOfWeek dayOfWeekOriginalDate = date.DayOfWeek;
int month = date.Month;
futureDates.Add(date);
for (int i = month + 1; i <= month + 5; i++)
{
DateTime dt = new DateTime(date.Year, i, 1);
while (dt.DayOfWeek != dayOfWeekOriginalDate)
{
dt = dt.AddDays(1);
}
futureDates.Add(dt);
}
return futureDates;
}
catch(Exception ex)
{
throw;
}
}
static DateTime ExtractDateFromNaturalLanguage(string Query)
{
try
{
DateTimeModel model = DateTimeRecognizer.GetInstance().GetDateTimeModel(Culture.English);
List<ModelResult> parsedResults = model.Parse(Query);
Dictionary<string, string> resolvedValue = (parsedResults.SelectMany(x => x.Resolution).FirstOrDefault().Value as List<Dictionary<string, string>>).FirstOrDefault();
string parsedDate = string.Empty;
if (resolvedValue["type"] == "daterange")
parsedDate = resolvedValue["start"];
if (resolvedValue["type"] == "date")
parsedDate = resolvedValue["value"];
DateTime parsedDateTimeObject = DateTime.Parse(parsedDate);
return parsedDateTimeObject;
}
catch (Exception ex)
{
throw;
}
}
}
}
这就是你所需要的。
答案 1 :(得分:4)
使用Crontab和一些聪明的linq,您不仅可以获得任何月份的第一天,还可以获得所需日期的任意组合,只需少于10行代码:
首先,通过NuGet安装NCronTab:Install-Package ncrontab -Version 3.3.0
其次,以星期一为例,创建crontab表达式(上面的链接很有用),它只返回所有月份的星期一:
var schedule = CrontabSchedule.Parse("0 0 * * 1");
这说:“零分钟,零时(即午夜),任何一天,任何一个月,星期一”
该计划为您提供了一个功能,您可以调用该功能以获得任何时段的星期一。
最后,对于聪明的linq:我们希望按月分组星期一,然后在每个月中选择第一个。它看起来像这样:
var mondays = schedule
// the occurrences in the date range we want
.GetNextOccurrences(new DateTime(2018, 3, 1), new DateTime(2018, 9, 30))
.ToLookup(
date => (date.Year * 100) + date.Month, // The 'key' becomes a "period". i.e. yyyyMM
date => date) // this is our grouping by month
.Select(d => d.First()) // Take the first instance per group
.ToList(); // you now have 6 Mondays!
可以轻松调整Select
以使用d.ElementAtOrDefault(n)
查找该月的第一天,第二周......周日。如果您想要上个月d.Last()
。
答案 2 :(得分:4)
只需在输入日期中添加4周,如有必要,再添加7天:
static DateTime GetNextDate(DateTime d1)
{
System.Diagnostics.Debug.Assert(d1.Day <= 28, "Behavior not described");
DateTime d2 = d1.AddDays(28);
// the following evaluates to 1 for 1-7, 2 for 8-14, etc
int n1 = (d1.Day - 1) / 7 + 1;
int n2 = (d2.Day - 1) / 7 + 1;
if (n2 != n1)
{
d2 = d2.AddDays(7);
}
return d2;
}
示例输入和输出:
Thu 2018-Mar-01 > Thu 2018-Apr-05
Fri 2018-Mar-02 > Fri 2018-Apr-06
Sat 2018-Mar-03 > Sat 2018-Apr-07
Sun 2018-Mar-04 > Sun 2018-Apr-01
Mon 2018-Mar-05 > Mon 2018-Apr-02
Tue 2018-Mar-06 > Tue 2018-Apr-03
Wed 2018-Mar-07 > Wed 2018-Apr-04
Thu 2018-Mar-08 > Thu 2018-Apr-12
Fri 2018-Mar-09 > Fri 2018-Apr-13
Sat 2018-Mar-10 > Sat 2018-Apr-14
Sun 2018-Mar-11 > Sun 2018-Apr-08
Mon 2018-Mar-12 > Mon 2018-Apr-09
Tue 2018-Mar-13 > Tue 2018-Apr-10
Wed 2018-Mar-14 > Wed 2018-Apr-11
Thu 2018-Mar-15 > Thu 2018-Apr-19
Fri 2018-Mar-16 > Fri 2018-Apr-20
Sat 2018-Mar-17 > Sat 2018-Apr-21
Sun 2018-Mar-18 > Sun 2018-Apr-15
Mon 2018-Mar-19 > Mon 2018-Apr-16
Tue 2018-Mar-20 > Tue 2018-Apr-17
Wed 2018-Mar-21 > Wed 2018-Apr-18
Thu 2018-Mar-22 > Thu 2018-Apr-26
Fri 2018-Mar-23 > Fri 2018-Apr-27
Sat 2018-Mar-24 > Sat 2018-Apr-28
Sun 2018-Mar-25 > Sun 2018-Apr-22
Mon 2018-Mar-26 > Mon 2018-Apr-23
Tue 2018-Mar-27 > Tue 2018-Apr-24
Wed 2018-Mar-28 > Wed 2018-Apr-25
答案 3 :(得分:2)
我已将myCustomDateChains
方法添加到您的DateTimeExtensions
课程中。它将返回您未来6个月内寻找的内容。请注意,如果您将月份的第5周作为输入,则下个月有可能在第5周没有星期一。在这种情况下,下个月会有“未找到”字符串。
static class DateTimeExtensions
{
static GregorianCalendar _gc = new GregorianCalendar();
public static string[] myCustomDateChains(this DateTime date)
{
string dayName = date.ToString("dddd");
int weekOfMonth = GetWeekOfMonth(date);
string[] array = new string[6];
//loop next 6 months
for (int i = 1; i < 7; i++)
{
DateTime dt = date.AddMonths(i);
DateTime dtFirstDayOfMonth = dt.AddDays(-(dt.Day - 1));
//seek for day in appropriate week
for (int j = 0; j < 7; j++)
{
if (dtFirstDayOfMonth.AddDays(j + (7 * (weekOfMonth - 1))).ToString("dddd") == dayName)
{
array[i - 1] = dtFirstDayOfMonth.AddDays(j + (7 * (weekOfMonth - 1))).ToString();
break;
}
}
//5th week of choosen month
if (array[i - 1] == "")
{
array[i - 1] = "doesnt found";
}
}
return array;
}
static int GetWeekOfYear(this DateTime time)
{
return _gc.GetWeekOfYear(time, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
}
public static int GetWeekOfMonth(this DateTime time)
{
DateTime first = new DateTime(time.Year, time.Month, 1);
return time.GetWeekOfYear() - first.GetWeekOfYear() + 1;
}
}
答案 4 :(得分:1)
这似乎是你要找的东西。
public static void Main(string[] args)
{
for (int mth = 1; mth <= 12; mth++)
{
DateTime dt = new DateTime(2010, mth, 1);
while (dt.DayOfWeek != DayOfWeek.Monday)
{
dt = dt.AddDays(1);
}
Console.WriteLine(dt.ToLongDateString());
}
Console.ReadLine();
}
参考Here
答案 5 :(得分:1)
尝试以下代码段
static void Main(string[] args)
{
int requiredMonths = 6;
int weekDays = 7;
DateTime date = new DateTime(2018, 2, 5);
DateTime[] result = new DateTime[requiredMonths];
for (int i = 0; i < requiredMonths; i++)
{
DateTime firstDayOfNextMonth = date.AddMonths(i).AddDays(-date.Day + 1);
for (int j = 0; j < weekDays; j++)
{
if (firstDayOfNextMonth.AddDays(j).DayOfWeek.Equals(DayOfWeek.Monday))
{
result[i] = firstDayOfNextMonth.AddDays(j);
}
}
}
foreach (var item in result)
{
Console.WriteLine(item);
}
}