计算从给定日期开始的周数周?

时间:2018-02-04 05:04:06

标签: c# .net date datetime

我正在努力寻找一种简单而有效的解决方案来计算一个月的工作日。例如,如果给定日期是第一个星期一Monday 5th March 2018,那么我想获得接下来6个月中每个月的第一个星期一的日期,例如:Monday 2nd April 2018Monday 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);
    }
}

但我很困惑,不知道如何修改上面的代码来解决这个问题。任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:4)

  

最近微软发布了 DateTimeRecognizer project on GitHub   它允许您将自然语言日期时间解析为Plain Old C#   DateTime对象。它经过了彻底的测试,所以没有猴子在那里工作。

他们还发布了同样的nuget包。您可以通过nuget包管理器安装。

首先安装nuget包:

Microsoft Date Recognizer Nuget Package

然而,所有这一切都是不碍事的。我开发了一个小型实用程序,它首先从自然语言中提取日期时间,然后查找下个月同一天的第一次出现日期。

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;
            }
        }
    }
}

这就是你所需要的。

Here's what you need

答案 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);
    }
}

demo https://dotnetfiddle.net/E0NAKc