7

我需要返回给定日期的年份和星期。听起来很简单。但要正确,2012-01-01 必须返回 2011-52,因为 2012 年的第 1 周从 1 月 2 日开始。

为了找到星期,我使用:

GregorianCalendar calw = new GregorianCalendar(GregorianCalendarTypes.Localized);
return calw.GetWeekOfYear(DateTime.Parse("2012-01-01"), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday).ToString();

这返回 52。(正确)

但是我如何获得年?

编辑:

在此处的帮助下:http: //codebetter.com/petervanooijen/2005/09/26/iso-weeknumbers-of-a-date-ac-implementation/

这似乎有效:

 private int weekYear(DateTime fromDate)
    {
        GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
        int week = weekNumber(fromDate);
        int month = cal.GetMonth(fromDate);
        int year = cal.GetYear(fromDate);

        //week starts after 31st december
        if (week > 50 && month == 1)
            year = year - 1;
        //week starts before 1st January
        if (week < 5 && month == 12)
            year = year + 1;

        return year;
    }
private int weekNumber(DateTime fromDate)
{
    // Get jan 1st of the year
    DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
    // Get dec 31st of the year
    DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
    // ISO 8601 weeks start with Monday 
    // The first week of a year includes the first Thursday 
    // DayOfWeek returns 0 for sunday up to 6 for saterday
    int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
    int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
    int wk = nds / 7;
    switch (wk)
    {
        case 0:
            // Return weeknumber of dec 31st of the previous year
            return weekNumber(startOfYear.AddDays(-1));
        case 53:
            // If dec 31st falls before thursday it is week 01 of next year
            if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
                return 1;
            else
                return wk;
        default: return wk;
    }
}
4

5 回答 5

11

Noda Time很容易为您处理这个问题:

野田时间 v1.x

using System;
using NodaTime;

public class Test
{
    static void Main()
    {
        LocalDate date = new LocalDate(2012, 1, 1);
        Console.WriteLine($"WeekYear: {date.WeekYear}");             // 2011
        Console.WriteLine($"WeekOfWeekYear: {date.WeekOfWeekYear}"); // 52
    }
}

野田时间 v2.x

using System;
using NodaTime;
using NodaTime.Calendars;

public class Test
{
    static void Main()
    {
        LocalDate date = new LocalDate(2012, 1, 1);
        IWeekYearRule rule = WeekYearRules.Iso;
        Console.WriteLine($"WeekYear: {rule.GetWeekYear(date)}"); // 2011
        Console.WriteLine($"WeekOfWeekYear: {rule.GetWeekOfWeekYear(date)}"); // 52
    }
}

那是使用 ISO 日历系统,其中一周年从第一周开始,该年至少有 4 天。(如CalendarWeekRule.FirstFourDayWeek.)如果您想要不同的日历系统,请在LocalDate构造函数中指定它。周年规则在 1.x 和 2.x 之间的处理略有不同。

编辑:请注意,这为这种情况(周年小于日历年)和一年另一端的情况(周年可能大于日历年)提供了正确的值。例如,2012 年 12 月 31 日是 2013 年第 1 周。

这就是图书馆为你做这件事的美妙之处:它的工作就是理解这类事情。您的代码不必担心它。你应该能够要求你想要什么。

于 2012-04-29T11:25:23.370 回答
4

您可以通过以下方式获取weeknumber CalendarWeekRule

var d = new DateTime(2012, 01, 01);
System.Globalization.CultureInfo cul = System.Globalization.CultureInfo.CurrentCulture;
var firstDayWeek = cul.Calendar.GetWeekOfYear(
    d,
    System.Globalization.CalendarWeekRule.FirstDay,
    DayOfWeek.Monday);
int weekNum = cul.Calendar.GetWeekOfYear(
    d,
    System.Globalization.CalendarWeekRule.FirstFourDayWeek,
    DayOfWeek.Monday);
int year = weekNum >= 52 && d.Month == 1 ? d.Year - 1 : d.Year;

您可能想CalendarWeekRule.FirstDayCalendarWeekRule.FirstFourDayWeek. 通过这种方式,您可以获得周数和年份(DateTime.Year-1如果它们不同)。

于 2012-04-29T10:57:54.693 回答
2

这只是一个边缘情况,您必须为其添加特殊代码。从日期字符串中获取年份,然后如果周 = 52 且月份 = 1,则从年份中减去一个。

于 2012-04-29T10:54:18.587 回答
1

我已经解决了类似的问题,结果应该是“YYYYWW”格式。我想避免硬编码日期并使用 3rd 方库。

我的测试用例是日期 1.1.2017,它应该返回第 201652 周(Iso YearWeek)

要获取周数,我使用了线程:获取给定日期的正确周数,该日期返回没有年份的周数。最后,我从所需日期的星期一(iso 周的第一天)得到了正确的年份:

    // returns only week number
    // from [Get the correct week number of a given date] thread
    public static int GetIso8601WeekOfYear(DateTime time)
    {
        // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
        // be the same week# as whatever Thursday, Friday or Saturday are,
        // and we always get those right
        DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
        if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
        {
            time = time.AddDays(3);
        }

        // Return the week of our adjusted day
        var week = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
        return week;
    }

    // returns int YearWeek in format "YYYYWW"
    public static int GetIso8601YearWeekOfYear(DateTime time)
    {
        var delta = (-((time.DayOfWeek - CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 7) % 7));
        var firstDayofWeek = time.AddDays(delta); // takeMonday
        var week = GetIso8601WeekOfYear(time);
        var yearWeek = (firstDayofWeek.Year * 100) + week;
        return yearWeek;
    }
于 2017-04-07T14:46:58.393 回答
0

在我的方法中,我利用了这样一个事实,即显示与同一周的星期四同一年的日子GetWeekOfYear()的正确周数。ISO-8601所以我寻找与给定日期属于同一周的星期四,然后调用GetWeekOfYear()它。

我不能用这个技巧来获得正确的年份,因为没有符合 iso8601 的方法,所以如果星期四属于与给定日期不同的年份,我会进行年份调整。

解决方案基本上是三线:

using System.Globalization;

namespace TESTS
{
    class Program
    {
        static void Main(string[] args)
        {

            //sample dates with correct week numbers in comments:
            string[] dats = new string[] { 
                 "2011-12-31","2012-01-01"  //1152
                ,"2012-12-31","2013-01-01"  //1301
                ,"2013-12-31","2014-01-01"  //1401
                ,"2014-12-31","2015-01-01"  //1501
                ,"2015-12-31", "2016-01-01" //1553
            };

            foreach (string str in dats)
            {
                Console.WriteLine("{0} {1}", str, GetCalendarWeek(DateTime.Parse(str)));
            }

            Console.ReadKey();
    }


       public static int GetCalendarWeek(DateTime dat)
        {
            CultureInfo cult = System.Globalization.CultureInfo.CurrentCulture;

            // thursday of the same week as dat.
            // value__ for Sunday is 0, so I need (true, not division remainder %) mod function to have values 0..6 for monday..sunday
            // If you don't like casting Days to int, use some other method of getting that thursday
            DateTime thursday = dat.AddDays(mod((int)DayOfWeek.Thursday-1,7) - mod((int)dat.DayOfWeek-1,7));
            //week number for thursday:
            int wk = cult.Calendar.GetWeekOfYear(thursday, cult.DateTimeFormat.CalendarWeekRule, cult.DateTimeFormat.FirstDayOfWeek);
            // year adjustment - if thursday is in different year than dat, there'll be -1 or +1:
            int yr = dat.AddYears(thursday.Year-dat.Year).Year;

            // return in yyww format:
            return 100 * (yr%100) + wk;
        }

        // true mod - helper function (-1%7=-1, I need -1 mod 7 = 6):
        public static int mod(int x, int m)
        {
            return (x % m + m) % m;
        }


}
于 2015-01-08T20:04:42.423 回答