tags:

views:

1518

answers:

15

I am currently writing a small calendar in ASP.Net C#. Currently to produce the rows of the weeks I do the following for loop:

var iWeeks = 6;
for (int w = 0; w < iWeeks; w++) {

This works fine, however, some month will only have 5 weeks and in some rare cases, 4.

How can I calculate the number of rows that will be required for a particular month?

A: 

How about checking which week the first and last days will be in?

Lasse V. Karlsen
A: 

@lassevk, exactly... how do I do this?

GateKiller
A: 

The months in the Julian / Gregorian calendar have the same number of days each year, except February who can have 28 or 29 days depending on the leapness of the year. You can find the number of days in the Description section at http://en.wikipedia.org/wiki/Gregorian_calendar.

As @darkdog mentioned you have DateTime.DaysInMonth. Just do this:

var days = DateTime.DaysInMonth(year, month) + 
           WhatDayOfWeekTheMonthStarts(year, month);    
int rows = (days / 7);  
if (0 < days % 7)  
{  
    ++rows;
}

Take into consideration the fact that for globalization / localization purposes, some parts of the world use different calendars / methods of organization of the year.

kokos
A: 

DateTime.DaysInMonth

try this one

darkdog
A: 

Well, it depends on the culture you're using, but let's assume you can use Thread.CurrentThread.CurrentCulture, then the code to get the week of today would be:

Culture cultire = Thread.CurrentThread.CurrentCulture;
Calendar cal = culture.Calendar;
Int32 week = cal.GetWeekOfYear(DateTime.Today,
 culture.DateTimeFormat.CalendarWeekRule,
 culture.DateTimeFormat.FirstDayOfWeek);
Lasse V. Karlsen
A: 

Check Calendar.GetWeekOfYear. It should do the trick.

There is a problem with it, it does not follow the 4 day rule by ISO 8601, but otherwise it is neat.

Biri
A: 

you can get the days of a month by using DateTime.DaysInMonth(int WhichYear,int WhichMonth);

darkdog
A: 
GateKiller
A: 

The problem isn't the number of days in the month, it's how many weeks it spans over.

February in a non-leap year will have 28 days, and if the first day of the month is a monday, february will span exactly 4 week numbers.

However, if the first day of the month is a tuesday, or any other day of the week, february will span 5 week numbers.

A 31 day month can span 5 or 6 weeks the same way. If the month starts on a monday, the 31 days gives you 5 week numbers. If the month starts on saturday or sunday, it will span 6 week numbers.

So the right way to obtain this number is to find the week number of the first and last days of the month.


Edit #1: Here's how to calculate the number of weeks a given month spans: Edit #2: Fixed bugs in code

public static Int32 GetWeekForDateCurrentCulture(DateTime dt)
{
    CultureInfo culture = Thread.CurrentThread.CurrentCulture;
    Calendar cal = culture.Calendar;
    return cal.GetWeekOfYear(dt,
        culture.DateTimeFormat.CalendarWeekRule,
        culture.DateTimeFormat.FirstDayOfWeek);
}

public static Int32 GetWeekSpanCountForMonth(DateTime dt)
{
    DateTime firstDayInMonth = new DateTime(dt.Year, dt.Month, 1);
    DateTime lastDayInMonth = firstDayInMonth.AddMonths(1).AddDays(-1);
    return
        GetWeekForDateCurrentCulture(lastDayInMonth)
        - GetWeekForDateCurrentCulture(firstDayInMonth)
        + 1;
}
Lasse V. Karlsen
A: 

@lassevk, you get the idea :)

Could you help me with making some sort of mathematical formula to calculate the week span value?

GateKiller
A: 

First Find out which weekday the first day of the month is in. Just new up a datetime with the first day, always 1, and the year and month in question, there is a day of week property on it. Then from here, you can use the number of days in the month, "DateTime.DaysInMonth", in order to determine how many weeks when you divide by seven and then add the number of days from 1 that your first day falls on. For instance.

    public static int RowsForMonth(int month, int year)
    {
        DateTime first = new DateTime(year, month, 1);

        //number of days pushed beyond monday this one sits
        int offset = ((int)first.DayOfWeek) - 1;

        int actualdays = DateTime.DaysInMonth(month, year) +  offset;

        decimal rows = (actualdays / 7);
        if ((rows - ((int)rows)) > .1)
        {
            rows++;
        }
        return rows;
    }
DevelopingChris
+3  A: 

Here is the method that does it:

public int GetWeekRows(int year, int month)
{
    DateTime firstDayOfMonth = new DateTime(year, month, 1);
    DateTime lastDayOfMonth = new DateTime(year, month, 1).AddMonths(1).AddDays(-1);
    System.Globalization.Calendar calendar = System.Threading.Thread.CurrentThread.CurrentCulture.Calendar;
    int lastWeek = calendar.GetWeekOfYear(lastDayOfMonth, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    int firstWeek = calendar.GetWeekOfYear(firstDayOfMonth, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    return lastWeek - firstWeek + 1;
}

You can customize the calendar week rule by modifying the System.Globalization.CalendarWeekRule.FirstFourDayWeek part. I hope the code is self explanatory.

Serhat Özgel
A: 

@ChanChan and @Buyutec

Thank you for your code suggestions, however, neither of them produce the value of 6 for this month (August, 2008).

GateKiller
A: 

@GateKiller

In my country, this month begins with friday and ends with sunday. So the method returns 5 as expected. But I looked for and found a month which is supposed to have 6 rows (March 2009) on my calendar and the method returns 6 for that month. Can you verify that your current thread's culture has the accurate culture setting for the calendar you are referring to?

Serhat Özgel
A: 

@Buyutec, well spotted. Something else must be wrong with some of my code :)

I have accepted your answer since it was the one that didn't require correcting errors to work and looks clean and simple.

GateKiller