【问题标题】:Calculate the Week day of months from given date?从给定日期计算月份的星期几?
【发布时间】:2018-07-14 06:22:22
【问题描述】:

我正在努力寻找一种简单有效的解决方案来计算一个月的星期几。例如,如果给定日期是第一个星期一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);
    }
}

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

【问题讨论】:

  • 开始日期加28天,如果月份不变,再加7天。重复 6 次。

标签: c# .net date datetime


【解决方案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

【讨论】:

  • 请阅读您所写的内容。是否能够找到给定月份的第 2 个、第 3 个或第 4 个星期一?
【解决方案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;
    }

}

【讨论】:

    【解决方案3】:

    最近微软发布了一个DateTimeRecognizer project on GitHub 它允许您将自然语言日期时间解析为普通的旧 C# 日期时间对象。它已经过全面测试,所以没有猴子在那里工作。

    他们还发布了一个相同的 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;
                }
            }
        }
    }
    

    这就是你需要的。

    【讨论】:

    • nice.. +1.. 我想知道他们为什么称它为 GetSubsequent"DateTimes".. 因为我认为对于这个特定场景 GetSubsequentWeekday 或类似的东西会更有意义.. 除非有重载会改变行为。我需要找个时间看看这个……看起来很酷。
    • 这似乎不起作用。试试日期 new DateTime(2018, 2, 13).. 猜我说得太早了?
    • @Heriberto Lugo 它找出特定月份中一天的第一次出现。满足 op 查询的 Imo。
    • @HeribertoLugo 输入new DateTime(2018, 2, 13) 得到什么输出??
    • 你现在能检查一下吗@HeribertoLugo 我已经修改了代码。
    【解决方案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()。

    【讨论】:

      【解决方案5】:

      输入日期只需增加 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
      

      【讨论】:

      • 非常感谢。我已经对此进行了测试,并且效果很好。
      • +1 尽管在极少数情况下,这种方法在未来几个月不会显示正确的周数 --- 考虑 2019/March/31 是第 5 周,使用这种方法下个月将是第 4 周。但它比我的方法更实用,因为您可能不喜欢在输出中看到“未找到”。
      • @masoud 是的,我没有在示例中处理这些情况。这些日期可以映射到第 4 个工作日或一个月的最后一天,或者我们可以简单地假设不会使用这些日期(OP 没有提及)。
      【解决方案6】:

      试试下面的代码 sn -p

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

      演示https://dotnetfiddle.net/E0NAKc

      【讨论】:

        猜你喜欢
        • 2022-01-21
        • 1970-01-01
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 2021-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多