Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting year and week from date

Tags:

c#

I need to return year and week of a given date. Sounds simple. But to be right 2012-01-01 have to return 2011-52, because week 1 in 2012 starts January 2th.

To find the week, I use:

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

this return 52. (correct)

But how do I get the Year?

edit:

With the help from here: http://codebetter.com/petervanooijen/2005/09/26/iso-weeknumbers-of-a-date-a-c-implementation/

This seems to work:

 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;
    }
}
like image 719
user408698 Avatar asked Apr 29 '12 10:04

user408698


2 Answers

Noda Time handles this for you very easily:

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

Noda Time 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
    }
}

That's using the ISO calendar system where the week year starts in the first week with at least 4 days in that year. (Like CalendarWeekRule.FirstFourDayWeek.) If you want a different calendar system, specify it in the LocalDate constructor. Week year rules are handled slightly differently between 1.x and 2.x.

EDIT: Note that this gives the right value for both this situation (where the week-year is less than the calendar year) and the situation at the other end of the year, where the week-year can be more than the calendar year. For example, December 31st 2012 is in week 1 of week-year 2013.

That's the beauty of having a library do this for you: its job is to understand this sort of thing. Your code shouldn't have to worry about it. You should just be able to ask for what you want.

like image 53
Jon Skeet Avatar answered Oct 04 '22 08:10

Jon Skeet


You can get the weeknumber according to the CalendarWeekRule in this way:

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;

You probably want to compare CalendarWeekRule.FirstDay with CalendarWeekRule.FirstFourDayWeek. On this way you get the weeknumber and the year (DateTime.Year-1 if they differ).

  • CultureInfo.Calendar Property
  • Calendar.GetWeekOfYear Method
  • CalendarWeekRule Enumeration
like image 40
Tim Schmelter Avatar answered Oct 04 '22 08:10

Tim Schmelter