Get the correct week number of a given date

2019-01-01 02:21发布

I have Googled a lot and found a lot of solutions, but none of them give me the correct week number for the 2012-12-31. Even the example on MSDN (link) fails.

2012-12-31 is Monday, therefore it should be Week 1, but every method I tried gives me 53. Here are some of the methods, that I have tried:

From the MDSN Library:

DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar cal = dfi.Calendar;

return cal.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);

Solution 2:

return new GregorianCalendar(GregorianCalendarTypes.Localized).GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);

Solution 3:

CultureInfo ciCurr = CultureInfo.CurrentCulture;
int weekNum = ciCurr.Calendar.GetWeekOfYear(dtPassed, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return weekNum;

Update

The following method actually returns 1 when date is 2012-12-31. In other words, my problem was that my methods were not following the ISO-8601 standard.

// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
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
    return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}

11条回答
时光乱了年华
2楼-- · 2019-01-01 02:27

The easiest way to determine the week number ISO 8601 style using c# and the DateTime class.

Ask this: the how-many-eth thursday of the year is the thursday of this week. The answer equals the wanted week number.

var dayOfWeek = (int)moment.DayOfWeek;
// Make monday the first day of the week
if (--dayOfWeek < 0)
    dayOfWeek = 6;
// The whole nr of weeks before this thursday plus one is the week number
var weekNumber = (moment.AddDays(3 - dayOfWeek).DayOfYear - 1) / 7 + 1;
查看更多
看风景的人
3楼-- · 2019-01-01 02:28

C# to Powershell port from code above from il_guru:

function GetWeekOfYear([datetime] $inputDate)
{
   $day = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetDayOfWeek($inputDate)
   if (($day -ge [System.DayOfWeek]::Monday) -and ($day -le [System.DayOfWeek]::Wednesday))
   {
      $inputDate = $inputDate.AddDays(3)
   }

   # Return the week of our adjusted day
   $weekofYear = [System.Globalization.CultureInfo]::InvariantCulture.Calendar.GetWeekOfYear($inputDate, [System.Globalization.CalendarWeekRule]::FirstFourDayWeek, [System.DayOfWeek]::Monday)
   return $weekofYear
}
查看更多
长期被迫恋爱
4楼-- · 2019-01-01 02:30

There can be more than 52 weeks in a year. Each year has 52 full weeks + 1 or +2 (leap year) days extra. They make up for a 53th week.

  • 52 weeks * 7days = 364 days.

So for each year you have at least one an extra day. Two for leap years. Are these extra days counted as separate weeks of their own?

How many weeks there are really depends on the starting day of your week. Let's consider this for 2012.

  • US (Sunday -> Saturday): 52 weeks + one short 2 day week for 2012-12-30 & 2012-12-31. This results in a total of 53 weeks. Last two days of this year (Sunday + Monday) make up their own short week.

Check your current Culture's settings to see what it uses as the first day of the week.

As you see it's normal to get 53 as a result.

  • Europe (Monday -> Sunday): January 2dn (2012-1-2) is the first monday, so this is the first day of the first week. Ask the week number for the 1st of January and you'll get back 52 as it is considered part of 2011 last's week.

It's even possible to have a 54th week. Happens every 28 years when the 1st of January and the 31st of December are treated as separate weeks. It must be a leap year too.

For example, the year 2000 had 54 weeks. January 1st (sat) was the first one week day, and 31st December (sun) was the second one week day.

var d = new DateTime(2012, 12, 31);
CultureInfo cul = CultureInfo.CurrentCulture;

var firstDayWeek = cul.Calendar.GetWeekOfYear(
    d,
    CalendarWeekRule.FirstDay,
    DayOfWeek.Monday);

int weekNum = cul.Calendar.GetWeekOfYear(
    d,
    CalendarWeekRule.FirstDay,
    DayOfWeek.Monday);

int year = weekNum == 52 && d.Month == 1 ? d.Year - 1 : d.Year;
Console.WriteLine("Year: {0} Week: {1}", year, weekNum);

Prints out: Year: 2012 Week: 54

Change CalendarWeekRule in the above example to FirstFullWeek or FirstFourDayWeek and you'll get back 53. Let's keep the start day on Monday since we are dealing with Germany.

So week 53 starts on monday 2012-12-31, lasts one day and then stops.

53 is the correct answer. Change the Culture to germany if want to to try it.

CultureInfo cul = CultureInfo.GetCultureInfo("de-DE");
查看更多
看风景的人
5楼-- · 2019-01-01 02:32

The question is: How do you define if a week is in 2012 or in 2013? Your supposition, I guess, is that since 6 days of the week are in 2013, this week should be marked as the first week of 2013.

Not sure if this is the right way to go. That week started on 2012 (On monday 31th Dec), so it should be marked as the last week of 2012, therefore it should be the 53rd of 2012. The first week of 2013 should start on monday the 7th.

Now, you can handle the particular case of edge weeks (first and last week of the year) using the day of week information. It all depends on your logic.

查看更多
时光乱了年华
6楼-- · 2019-01-01 02:34
  DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
  DateTime date1 = new DateTime(2011, 1, 1);
  Calendar cal = dfi.Calendar;

  Console.WriteLine("{0:d}: Week {1} ({2})", date1, 
                    cal.GetWeekOfYear(date1, dfi.CalendarWeekRule, 
                                      dfi.FirstDayOfWeek),
                    cal.ToString().Substring(cal.ToString().LastIndexOf(".") + 1));      
查看更多
栀子花@的思念
7楼-- · 2019-01-01 02:35

Good news! A pull request adding System.Globalization.ISOWeek to .NET Core was just merged and is currently slated for the 3.0 release. Hopefully it will propagate to the other .NET platforms in a not-too-distant future.

The type has the following signature, which should cover most ISO week needs:

namespace System.Globalization
{
    public static class ISOWeek
    {
        public static int GetWeekOfYear(DateTime date);
        public static int GetWeeksInYear(int year);
        public static int GetYear(DateTime date);
        public static DateTime GetYearEnd(int year);
        public static DateTime GetYearStart(int year);
        public static DateTime ToDateTime(int year, int week, DayOfWeek dayOfWeek);
    }
}

You can find the source code here.

查看更多
登录 后发表回答