zoukankan      html  css  js  c++  java
  • ISO 8601 Week of Year format in Microsoft .Net

    Several people have noticed that Calendar.GetWeekOfYear() is almost like the ISO 8601 week when passed CalendarWeekRule.FirstFourDayWeek and DayOfWeek.Monday, however it is a little bit different.  Specifically ISO 8601 always has 7 day weeks.  If the first partial week of a year doesn't contain Thursday, then it is counted as the last week of the previous year.  Likewise, if the last week of the previous year doesn't contain Thursday then its treated like the first week of the next year.  GetWeekOfYear() has the first behavior, but not the second.  Ie:

    DateDayGetWeekOfYearISO 8601 Week
    12/31/2000 Sunday 52 of 2000 52 of 2000
    1/1/2001 Monday 1 of 2001 1 of 2001
    1/1/2005 Saturday 53 of 2004 53 of 2004
    12/31/2007 Monday 53 of 2007 1 of 2008

    Notice that the ISO 8601 week at the end of 2007 is different than the GetWeekOfYear() week.  For GetWeekOfYear(), both the last week and the first week have fewer than 7 days.  Also notice that even though its a 2007 date, its considered the first week of 2008.  Similarly the first day of 2005 is considered to be the last week of 2004 by either method.

    A simple workaround to consistently get the ISO 8601 week is to realize that consecutive days Monday through Sunday in ISO 8601 weeks all have the same week #.  So Monday has the same week # as Thursday.  Since Thursday is the critical day for determining when the week starts each year my solution is to add 3 days if the day is Monday, Tuesday or Wednesday.  The adjusted days are still in the same week, and use values that GetWeekOfYear and ISO 8601 agree on.

    Note that if the requirement is to compute a date in the 2004W536 form, the code will still have to detect that a week 53 in January means that we need to decrement the year by 1, and a week 1 in December requires incrementing the year by 1.

    Here's my example.  I made this a complete program, however GetIso8601WeekOfYear() is the worker function.  I used a static calendar, which probably isn't necessary.  Bala pointed out that one could derive a class from GregorianCalendar and override GetWeekOfYear(), but I'm not sure what the repercussions of using such a calendar elsewhere would be.  You can try it if you want, but for now this sample is just a simple static method.  Main is just here to run through a bunch of days and show when the week calculations differ. 

     1 using System;
     2 using System.Globalization;
     3 
     4 class Test
     5 {
     6     // Need a calendar.  Culture's irrelevent since we specify start day of week
     7     private static Calendar cal = CultureInfo.InvariantCulture.Calendar;
     8     
     9     // This presumes that weeks start with Monday.
    10     // Week 1 is the 1st week of the year with a Thursday in it.
    11     public static int GetIso8601WeekOfYear(DateTime time)
    12     {
    13         // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it'll 
    14         // be the same week# as whatever Thursday, Friday or Saturday are,
    15         // and we always get those right
    16         DayOfWeek day = cal.GetDayOfWeek(time);
    17         if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
    18         {
    19             time = time.AddDays(3);
    20         }
    21         
    22         // Return the week of our adjusted day
    23         return cal.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    24     }
    25     
    26     static void Main(string[] args)
    27     {
    28         // 1/1/1990 starts on a Monday
    29         DateTime dt = new DateTime(1990, 1, 1);
    30         Console.WriteLine("Starting at " + dt + " day: " + cal.GetDayOfWeek(dt) + " Week: " +GetIso8601WeekOfYear(dt));
    31 
    32         for (int i = 0; i < 100000; i++)
    33         {
    34             for (int days = 0; days < 7; dt=dt.AddDays(1), days++)
    35             {
    36                 if (GetIso8601WeekOfYear(dt) != cal.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday))
    37                 {
    38                     Console.WriteLine("Iso Week " + GetIso8601WeekOfYear(dt) + 
    39                         " GetWeekOfYear: " + cal.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday) + 
    40                         " Date: " + dt + " Day: " + cal.GetDayOfWeek(dt));
    41                 }
    42             }
    43         }
    44     }
    45 }
  • 相关阅读:
    redis总结
    java程序启动脚本
    mysql生成百万测试数据脚本
    java分布式锁的实现及在springboot中的应用
    mysql使用总结
    一个java实现代码(服务)编排的思路(未完)
    sentinel自定义统一限流降级处理
    shell学习
    oracle查看被锁的事务进程sql
    Sql查询两个时间段有重叠的记录
  • 原文地址:https://www.cnblogs.com/vayne/p/2783913.html
Copyright © 2011-2022 走看看