How to know the number of a week in each month

Asked

Viewed 5,869 times

7

I am working on ASP MVC4, and would like to know the number of weeks in a given month to generate a list of dates. For example, the user inserts a week, and in that week of each month I will generate a date. The user can enter the week of the month in which the occurrence will happen (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 on Monday. Assuming the user inserts terceira I’ll generate a list of 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

  • 1

    I’m thinking of creating a list of dates for each week in the month. I see where the first day of the month is (in the week) and start generating the lists (a list for each week), from that date. It’ll be the right way?

  • You already have a very similar question here Make sure it doesn’t suit you?

  • I even asked that question. It turns out to be different questions, because here I want from 1 to 5 the number of the week in the month, where it starts and where it ends. The other question has no way of knowing which second or third week of a given month

  • If one of the answers below solved your problem and there was no doubt left, choose the one you liked the most and mark it as correct/accepted by clicking on the " " that is next to it, which also marks your question as solved. If you still have any questions or would like further clarification, feel free to comment.

6 answers

5

The Elsdesire blog has this following question from reply ( 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 haven’t tested the code, uncoupling it is possible to predict that it does what you need.

  • I’ve been experimenting with your solution, and the truth is, I can tell what week a date is. Now if from here I can get to what I want I don’t know, I’ll try.

  • @Cesarean, you can treat the return of the Getweekinmonth() function which is an integer between 1 and 5 and convert to a string (first, second, third...) easily with a switch. With this + the information you already have you can assemble the output the way you want.

  • But the point is not to treat function return. The point is, I don’t know what date the function is receiving per parameter. I don’t care what week a date is, I want to know the date generated for a Monday in the third week, for example.

1

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

/// <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 exception when it is not possible to construct the date... because some dates are impossible, such as Sunday, first week, February 2014... does not exist, because this week has only one Saturday this month, and nothing more.

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"));
    }
}
  • I finally found a solution. I tested yours and it works too! Thanks for the help

  • Thanks for the vote, could show you what solution you chose?

  • I just posted

0

I ended up finding a solution, perhaps not the most effective. I built from the @Raulalmeira answer.

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

1º- 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 starting on the 1st of January

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

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

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

4º- I made the conditions to see which 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 cycle for and go iterating the month (that’s how I did, but I didn’t find it necessary to post).

I know that it is by far the most effective solution and I am aware of that, I just leave it here as I ended up solving the problem. Although I’ve seen better solutions than mine

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 part of the searchBaseCache variable is missing that you should do in the appropriate location of your application.

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

  • I am generating 5 lists, one for each week of the month using your other example. Then I test this answer. Thanks for the help!

-2

I resolved so:

private int GetWeekInMonth(DateTime date)
        {
            try
            {
                var weekNum = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(new DateTime(date.Year, date.Month, date.Day), CalendarWeekRule.FirstDay, DayOfWeek.Sunday);

                return weekNum;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

Browser other questions tagged

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