How to know the number of a week in each month

7

I'm working on ASP MVC4, and I would like to know how many weeks in a given month to generate a list with dates. For example, the user enters a week, and in that week of each month I generate a date. The user can enter the week of the month in which the occurrence will occur (in which I will generate the date):

primeira - First week of the month

segunda - Second week of the month

terceira - Third week of the month

quarta - Fourth week of the month

ultima - Last week of the month

At the end of the user choosing the week of the month, I will generate a date for that same week in the month on Monday. Assuming the user enters terceira I'll generate a list with the dates:

10/02/2014 - date in the third week of February to Monday

10/03/2014 - date in the third week of March to Monday

14/04/2014 - date in the third week of April to Monday

    
asked by anonymous 05.02.2014 / 10:59

5 answers

5

The Elsdesire blog has this question following the answer (in English).

The implementation presented is this:

public static int GetWeekInMonth(DateTime date)
{
    DateTime tempdate = date.AddDays(-date.Day + 1);
    CultureInfo ciCurr = CultureInfo.CurrentCulture;
    int weekNumStart = ciCurr.Calendar.GetWeekOfYear(tempdate, CalendarWeekRule.FirstFourDayWeek, ciCurr.DateTimeFormat.FirstDayOfWeek);
    int weekNum = ciCurr.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, ciCurr.DateTimeFormat.FirstDayOfWeek);
    return weekNum - weekNumStart + 1;
}

Although you have not tested the code, removing it is possible to predict that it does what you need.

    
05.02.2014 / 11:29
1

Try this method:

public static IList<DateTime> obterSemanaDeCadaMes(int ano, int semanaDoMes, DayOfWeek dia)
{
    int semana_atual = 1, mes_atual = 1;
    DateTime date = new DateTime(ano, 1, 1);
    IList<DateTime> dates = new List<DateTime>();

    while (date.Year == ano)
    {
        if (date.DayOfWeek == dia && semana_atual == semanaDoMes)
            dates.Add(date);

        // Incrementa semana do mês
        if (date.DayOfWeek.Equals(DayOfWeek.Sunday))
            semana_atual++;

        // Se mudar o mês reseta a semana
        if (mes_atual != date.Month)
        {
            mes_atual++;
            semana_atual = 1;
        }

        date = date.AddDays(1);
    }

    return dates;
}

To use:

static void Main(string[] args)
{
    var dates = obterSemanaDeCadaMes(2014, 3, DayOfWeek.Monday);

    foreach (var data in dates)
    {
        Console.WriteLine(item.ToString("dd/MM/yyyy"));
    }
}
    
05.02.2014 / 13:39
1

I just built the method you want to generate dates, given the week of the month and the day of the week :

/// <summary>
/// Gera uma data, dados ano, mês, semana do mês e dia da semana.
/// A semana do mês é um número de 1 até 6.
/// </summary>
/// <param name="ano">Ano da data a ser construída.</param>
/// <param name="mes">Mês da data a ser construída. Número de 1 até 12.</param>
/// <param name="semana">Semana do mês da data a ser construída. Número de 1 até 6. Note que o número máximo depende do mês. O Mês com menos semanas, terá no mínimo 4 semanas (exemplo 2015/fev).</param>
/// <param name="diaDaSemana">Dia da semana da data a ser construída.</param>
public static DateTime GerarData(int ano, int mes, int semana, DayOfWeek diaDaSemana)
{
    const long ticksNoDia = 10000000L * 60 * 60 * 24;
    var dataPrimeiroDia = new DateTime(ano, mes, 1);
    var diffDias = (semana - 1) * 7 - (int)dataPrimeiroDia.DayOfWeek + (int)diaDaSemana;
    var data = new DateTime(dataPrimeiroDia.Ticks + ticksNoDia * diffDias);

    if (data.Month != mes)
        throw new Exception("Não existe tal data!");

    return data;
}

Note that the method throws an exception when the date can not be built ... because some dates are impossible, such as Sunday, the first week, February 2014 ... does not exist, because this week has only one Saturday in this month, and nothing else.

    
05.02.2014 / 16:41
0

Follow untested code that does what you need:

    static Dictionary<int, Dictionary<String, DateTime>> searchBaseCache;
    static DateTime GetDateGiven(int year, int month, int weekNum, int dayOfWeek)
    {
        Dictionary<string, DateTime> searchBase;
        if (!searchBaseCache.ContainsKey(year))
        {
            searchBaseCache.Add(year,BuildSearchBase(year));
        }
        searchBase = searchBaseCache[year];
        return searchBase[string.Format("{0}-{1}-{2}-{3}", year, month, weekNum, dayOfWeek)];
    }

    private static Dictionary<string, DateTime> BuildSearchBase(int year)
    {
        Dictionary<String, DateTime> compDates = new Dictionary<string, DateTime>(365);
        DateTime d = new DateTime(year, 1, 1);
        while (d.Year == year)
        {
            compDates.Add(string.Format("{0}-{1}-{2}-{3}", year, d.Month, GetWeekInMonth(d), d.DayOfWeek), d);
        }
        return compDates;
    }

Only the boot portion of the searchBaseCache variable that you should make in the appropriate place of your application is missing.

The GetDateGiven function will return a DateTime object given the year, month, week number, and day of the week.

    
05.02.2014 / 12:10
0

I just found a solution, maybe not the most effective one. I built from the response of @ RaulAlmeira.

var listaDatas = new List<DateTime>(); //Lista que vai receber as datas

1st - I created a list for each week of the month

listaDatasPrimeiraSemana = new List<DateTime>();
listaDatasSegundaSemana = new List<DateTime>();
listaDatasTerceiraSemana = new List<DateTime>();
listaDatasQuartaSemana = new List<DateTime>();
listaDatasQuintaSemana = new List<DateTime>();

2º- I started a date beginning on the 1st of January

DateTime date = DateTime(2014, 1, 1);

3º- I filled the lists of weeks, running the five weeks to fill every day in the respective lists

while (numSemana <= 5) //Enquanto a semana for menor de 5 continua a percorrer
{
    DateTime tempdate = data.AddDays(-data.Day + 1);
    CultureInfo ciCurr = CultureInfo.CurrentCulture;
    int weekNumStart = ciCurr.Calendar.GetWeekOfYear(tempdate, CalendarWeekRule.FirstFourDayWeek, ciCurr.DateTimeFormat.FirstDayOfWeek);
    int weekNum = ciCurr.Calendar.GetWeekOfYear(data, CalendarWeekRule.FirstFourDayWeek, ciCurr.DateTimeFormat.FirstDayOfWeek);
    numSemana = weekNum - weekNumStart + 1;
    if (data.AddDays(1).Month != data.Month) { break; }
    if (numSemana == 1)
    {
        listaDatasPrimeiraSemana.Add(data);
    }
    if (numSemana == 2)
    {
        listaDatasSegundaSemana.Add(data);
    }
    if (numSemana == 3)
    {
        listaDatasTerceiraSemana.Add(data);
    }
    if (numSemana == 4)
    {
        listaDatasQuartaSemana.Add(data);
    }
    if (numSemana == 5)
    {
        listaDatasQuintaSemana.Add(data);
    }
    data = data.AddDays(1);
}

4th - I was able to see what week the user chose

if (servico.SemanaMensalPeriod == "Primeira") //servico.SemanaMensalPeriod contém a semana escolhida pelo utilizador
{
    foreach (var item in listaDatasPrimeiraSemana)//Percorro a primeira semana
    {
        if (item.DayOfWeek == DayOfWeek.Monday) { listaDatas.Add(item); } //Verifico se na semana há alguma segunda feira, e caso exista adiciono à lista de datas
    }
}
...
Condição if igual à de cima para verificar se tenho alguma segunda-feira nas restantes semanas
...

ATTENTION

The code above only shows the result for the month of January, to do for a period of time or for the whole year just put the code on top of a for loop and go iterating the month (it was like I did, but I did not find it necessary to post).

I know this is by far the most effective solution and I know it, I just leave here how I solved the problem. Although I've seen better solutions here than mine

    
05.02.2014 / 17:07