How to know the week of a given month?

Asked

Viewed 3,924 times

7

I am working on ASP.NET MVC 4, and I intend to know what is the week of a given month.

For example, the user wants to set a frequency of occurrences, and as such says:

  • The occurrence will happen every 2 weeks;
  • The event will take place this week to Monday and Thursday;

When retrieving this data from the user, I have to generate a date list with this data. The result of the list will be something like:

03/02/2014 - corresponds to the Monday of the second week of February;

06/02/2014 - corresponds to the Thursday of the second week of February;

17/02/2014 - corresponds to the Monday of the fourth week of February;

20/02/2014 - corresponds to the Thursday of the fourth week of February;

03/03/2014 - corresponds to the Monday of the first week of March;

06/03/2014 - corresponds to the Thursday of the first week of March;

... So forth

So I want to try to know how to calculate/know the weeks of the month (I think the solution is to know the number of the week in the year), and still the day of the week in the same week.

3 answers

4


I wrote this algorithm

  1. Calculate the first day of the current week (in my example, the first day of the week and 'Sunday').
  2. Calculates the Monday and the Thursday of this week, and adds to' list
  3. Advance 2 weeks, and return to step 2

Input data

  • weekCount: total number of weeks to be examined
  • skipWeeks: number of weeks to jump/forward. In your example where "The occurrence will happen every 2 weeks", skipWeeks would be 1. That is, the algorithm will examine a week, advance 1 week, examine the week, advance 1 week, etc.
  • daysOfWeek: days of the week (ex: new[] {DayOfWeek.Monday, DayOfWeek.Thursday})
  • (optional) startDate: day to start the search. Default is the current day.

public IEnumerable<DateTime> AgendarAlertas(int weekCount, int skipWeeks, IEnumerable<DayOfWeek> daysOfWeek )
{
    return AgendarAlertas(weekCount, skipWeeks, daysOfWeek, DateTime.Today);
}

public IEnumerable<DateTime> AgendarAlertas(int weekCount, int skipWeeks, IEnumerable<DayOfWeek> daysOfWeek , DateTime startDate)
{
    var dates = new List<DateTime>();

    Calendar calendar = new GregorianCalendar();
    DateTime firstDayOfWeek = DateTime.Today.StartOfWeek(DayOfWeek.Sunday);

    for (int currentWeek = 0; currentWeek < weekCount; currentWeek++)
    {
        //calcular dias da semana
        dates.AddRange(
            daysOfWeek.Select(dayOfWeek =>
                                firstDayOfWeek.NextDayOfWeek(dayOfWeek)));

        //avancar "skipWeeks"
        firstDayOfWeek = calendar.AddWeeks(firstDayOfWeek, skipWeeks + 1);
        currentWeek += skipWeeks;
    }

    //filtrar dias passados
    return dates.SkipWhile(date => date < startDate);
}

It takes 2 Extension methods

public static class DateTimeExtensions
{
    public static DateTime NextDayOfWeek(this DateTime dt, DayOfWeek day)
    {
        int diff = day - dt.DayOfWeek;

        //se o dia ja passou, calcular o da proxima semana
        if (diff < 0)
            diff += 7;

        return dt.AddDays(diff).Date;
    }

    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
    {
        int diff = dt.DayOfWeek - startOfWeek;
        if (diff < 0)
            diff += 7;

        return dt.AddDays(-1 * diff).Date;
    }
}

Upshot :

AgendarAlertas(11, 1, new[] {DayOfWeek.Thursday, DayOfWeek.Friday});

06/02/2014 00:00:00 //proxima quinta-feira
07/02/2014 00:00:00 //proxima sexta-feira
20/02/2014 00:00:00 //proxima quinta-feira + 2 semanas
21/02/2014 00:00:00 //proxima sexta-feira  + 2 semanas
06/03/2014 00:00:00 //proxima quinta-feira + 4 semanas
07/03/2014 00:00:00 //proxima sexta-feira  + 4 semanas
20/03/2014 00:00:00 //proxima quinta-feira + 6 semanas
21/03/2014 00:00:00 //proxima sexta-feira  + 6 semanas
03/04/2014 00:00:00 //proxima quinta-feira + 8 semanas
04/04/2014 00:00:00 //proxima sexta-feira  + 8 semanas
17/04/2014 00:00:00 //proxima quinta-feira + 10 semanas
18/04/2014 00:00:00 //proxima sexta-feira  + 10 semanas
  • I tested both answers and they work correctly. Although the other is "easier" to implement yours is also quite complete! Thank you ;)

  • @Cesarmiguel So to remember that the other form has worse performance.. If you want next year’s Mondays, with an interval of 2 weeks, the loop will run ~365 times. My loop would run 52 / 2 = 26 times, one per week of the year, skipping weeks that don’t matter.

  • @Cesarmiguel improved the algorithm to be easier to use and to read, and also improved the performance a little.

  • Thank you @dcastro , of this great help! I will proceed to the changes.

3

Option 1:

public static void obterDiasComIntervaloSemanal(DateTime data, int intervalo, int total_semanas, DayOfWeek[] dias)
{
    int semana_atual = 1;    
    while (semana_atual <= total_semanas)
    {
        if (dias.Contains(data.DayOfWeek) && semana_atual % intervalo == 0)
            Console.WriteLine(data.ToString("dd/MM/yyyy")); // Aqui você decide o quer fazer se quiser adicionar numa lista de datas a data atual...
        if (data.DayOfWeek.Equals(DayOfWeek.Sunday))
            semana_atual++;
        data = data.AddDays(1);
    }
}

And to use:

static void Main(string[] args)
{
    DayOfWeek[] dias = {
                       DayOfWeek.Monday,
                       DayOfWeek.Thursday
                   };
    obterDiasComIntervaloSemanal(new DateTime(2014, 02, 01), 2, 10, dias);
}

Upshot: inserir a descrição da imagem aqui

Option 2:

public static DateTime getDateInterval(int year, int month, int week, DayOfWeek day)
{
    int current_week = 1;
    var days = DateTime.DaysInMonth(year, month);

    DateTime date = new DateTime(year, month, 1);

    for (int i = 1; i <= days; i++)
    {
        if (date.DayOfWeek == day && current_week == week)
            break;
        if (date.DayOfWeek.Equals(DayOfWeek.Sunday))
            current_week++;
        date = date.AddDays(1);
    }

    return date;
}

To use:

static void Main(string[] args)
{
                           // year month week   day of week
    var data1 = getDateInterval(2014, 2, 2, DayOfWeek.Monday); // 03/02/2014
    var data2 = getDateInterval(2014, 2, 2, DayOfWeek.Thursday); // 06/02/2014
    var data3 = getDateInterval(2014, 2, 4, DayOfWeek.Monday); // 17/02/2014
}
  • The algorithm has a bug. If I want Sundays, it will go into infinite loop and end up in stack overflow. I think just take the else to solve the bug.

  • Really dcastro, thanks for the warning.

1

Solving your problem in the simplest way: one is iterating directly on dates.

Stay like this:

var date = new DateTime(2014, 2, 4);
var intervaloSemanas = 2;
var diasDaSemana = new DayOfWeek[] { DayOfWeek.Monday, DayOfWeek.Thursday, };

var dataDeStop = date.AddDays(80);
var incremento = TimeSpan.FromDays(7 * intervaloSemanas);

for (var dt = date.AddDays(-(int)date.DayOfWeek);
     dt <= dataDeStop;
     dt += incremento)
{
    foreach (var dayOfWeek in diasDaSemana)
        Console.WriteLine("{0:yyyy'-'MM'-'dd}", dt.AddDays((int)dayOfWeek));
}

Output:

inserir a descrição da imagem aqui

This code is also very fast, because it goes straight to the dates you want.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.