How to get every "monday" day of given month ?
An example;
Input: 11.July.2017 (11.07.2017)
Output: ( 3,10,17,24,31 )
3.7.2017 Monday
10.7.2017 Monday
17.7.2017 Monday
24.7.2017 Monday
31.7.2017
I could get number of days of given month(For july 2017, it's 31 days). Then write an iteration(for loop a.e.) if dayOfWeek equals Monday, add to a list. But this is not good code because for loop will work 31 times. There should be a better algorithm to archive the goal.
I'm using C# .net framework 4.6
UPDATE
Thanks for all for your helps, after some answers I've got so far; I tested all codes with a simple & dirty benchmark codes to find faster algorithm.
Here is my benchmark code;
using System;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Jobs;
using BenchmarkDotNet.Engines;
using X.Core.Helpers;
namespace X.ConsoleBenchmark
{
[SimpleJob(RunStrategy.ColdStart, targetCount: 5)]
[MinColumn, MaxColumn, MeanColumn, MedianColumn]
public class LoopTest
{
[Benchmark]
public void CalculateNextSalaryDateWithLoopAllDays()
{
DateTime date = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
List<DateTime> allXDaysInMonth = date.GetAllXDaysInMonthWithLoopAllDays(DayOfWeek.Tuesday);
if (allXDaysInMonth != null && allXDaysInMonth.FirstOrDefault().Day != 4)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
[Benchmark]
public void CalculateNextSalaryDate()
{
DateTime date = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
List<DateTime> allXDaysInMonth = date.GetAllXDaysInMonth(DayOfWeek.Tuesday);
if (allXDaysInMonth != null && allXDaysInMonth.FirstOrDefault().Day != 4)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
[Benchmark]
public void Maccettura_GetAllDayOfWeekPerMonth()
{
DateTime exampleDate = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
var date = new DateTime(exampleDate.Year, exampleDate.Month, 1);
if (date.DayOfWeek != DayOfWeek.Thursday)
{
int daysUntilDayOfWeek = ((int)DayOfWeek.Thursday - (int)date.DayOfWeek + 7) % 7;
date = date.AddDays(daysUntilDayOfWeek);
}
List<DateTime> days = new List<DateTime>();
while (date.Month == exampleDate.Month)
{
days.Add(date);
date = date.AddDays(7);
}
if (days.FirstOrDefault().Day != 6)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
[Benchmark]
public void ScottHannen_GetWeekdaysForMonth()
{
DateTime exampleDate = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
IEnumerable<DateTime> days = ScottHannen_GetDaysInMonth(exampleDate).Where(day => day.DayOfWeek == DayOfWeek.Thursday);
if (days.FirstOrDefault().Day != 6)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
private IEnumerable<DateTime> ScottHannen_GetDaysInMonth(DateTime date)
{
var dateLoop = new DateTime(date.Year, date.Month, 1);
while (dateLoop.Month == date.Month)
{
yield return dateLoop;
dateLoop = dateLoop.AddDays(1);
}
}
[Benchmark]
public void Trioj_GetWeekdaysForMonth()
{
DateTime exampleDate = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
IEnumerable<DateTime> days = Trioj_GetDatesInMonthByWeekday(exampleDate, DayOfWeek.Thursday);
if (days.FirstOrDefault().Day != 6)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
private List<DateTime> Trioj_GetDatesInMonthByWeekday(DateTime date, DayOfWeek dayOfWeek)
{
// We know the first of the month falls on, well, the first.
var first = new DateTime(date.Year, date.Month, 1);
int daysInMonth = DateTime.DaysInMonth(date.Year, date.Month);
// Find the first day of the week that matches the requested day of week.
if (first.DayOfWeek != dayOfWeek)
{
first = first.AddDays(((((int)dayOfWeek - (int)first.DayOfWeek) + 7) % 7));
}
// A weekday in a 31 day month will only occur five times if it is one of the first three weekdays.
// A weekday in a 30 day month will only occur five times if it is one of the first two weekdays.
// A weekday in February will only occur five times if it is the first weekday and it is a leap year.
// Incidentally, this means that if we subtract the day of the first occurrence of our weekday from the
// days in month, then if that results in an integer greater than 27, there will be 5 occurrences.
int maxOccurrences = (daysInMonth - first.Day) > 27 ? 5 : 4;
var list = new List<DateTime>(maxOccurrences);
for (int i = 0; i < maxOccurrences; i++)
{
list.Add(new DateTime(first.Year, first.Month, (first.Day + (7 * i))));
}
return list;
}
[Benchmark]
public void Jonathan_GetWeekdaysForMonth()
{
DateTime exampleDate = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
IEnumerable<DateTime> days = Jonathan_AllDatesInMonth(exampleDate.Year, exampleDate.Month).Where(x => x.DayOfWeek == DayOfWeek.Thursday);
if (days.FirstOrDefault().Day != 6)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
private static IEnumerable<DateTime> Jonathan_AllDatesInMonth(int year, int month)
{
int days = DateTime.DaysInMonth(year, month);
for (int day = 1; day <= days; day++)
{
yield return new DateTime(year, month, day);
}
}
[Benchmark]
public void Swatsonpicken_GetWeekdaysForMonth()
{
DateTime exampleDate = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
IEnumerable<DateTime> days = Swatsonpicken_GetDaysOfWeek(exampleDate, DayOfWeek.Thursday);
if (days.FirstOrDefault().Day != 6)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
private static IEnumerable<DateTime> Swatsonpicken_GetDaysOfWeek(DateTime startDate, DayOfWeek desiredDayOfWeek)
{
var daysOfWeek = new List<DateTime>();
var workingDate = new DateTime(startDate.Year, startDate.Month, 1);
var offset = ((int)desiredDayOfWeek - (int)workingDate.DayOfWeek + 7) % 7;
// Jump to the first desired day of week.
workingDate = workingDate.AddDays(offset);
do
{
daysOfWeek.Add(workingDate);
// Jump forward seven days to get the next desired day of week.
workingDate = workingDate.AddDays(7);
} while (workingDate.Month == startDate.Month);
return daysOfWeek;
}
[Benchmark]
public void AliaksandrHmyrak_GetWeekdaysForMonth()
{
DateTime exampleDate = new DateTime(2017, 7, 3);
const int oneMillion = 1000000;
for (int i = 0; i < oneMillion; i++)
{
IEnumerable<DateTime> days = AliaksandrHmyrak_GetDaysOfWeek(exampleDate, DayOfWeek.Thursday);
if (days.FirstOrDefault().Day != 6)
{
throw new ApplicationException("Calculate method has errors.");
}
}
}
private static List<DateTime> AliaksandrHmyrak_GetDaysOfWeek(DateTime date, DayOfWeek dayOfWeek)
{
var daysInMonth = DateTime.DaysInMonth(date.Year, date.Month);
var i = 1;
List<DateTime> result = new List<DateTime>(5);
do
{
var testDate = new DateTime(date.Year, date.Month, i);
if (testDate.DayOfWeek == dayOfWeek)
{
result.Add(testDate);
i += 7;
}
else
{
i++;
}
} while (i <= daysInMonth);
return result;
}
}
}
And this is the results table;
I can remove any code and picture-name if you want
I marked Jonathan's answer. Simple, clean and faster (interestingly).
Enter this formula: =DATE(YEAR(A2),1,8)-WEEKDAY(DATE(YEAR(A2),1,6)) into a blank cell where you want to locate the result, and then drag the fill handle down to the cells you want to apply this formula, and the date of the first Monday from the given date has been displayed at once, see screenshot: Notes: 1.
(1) This formula =A2-MOD(A2-2,7) will return Monday as the beginning of week based on the given date. For returning Sunday as the start of a week, please apply this formula =A2-MOD(A2-1,7).
To get the first Monday of month in google sheets, you can use the EOMONTH formula with the WEEKDAY formula.
Other answers work, but I would prefer to make use of Jon Skeet's AllDaysInMonth function from foreach day in month
public static IEnumerable<DateTime> AllDatesInMonth(int year, int month)
{
int days = DateTime.DaysInMonth(year, month);
for (int day = 1; day <= days; day++)
{
yield return new DateTime(year, month, day);
}
}
And then you can call with LINQ like so:
var mondays = AllDatesInMonth(2017, 7).Where(i => i.DayOfWeek == DayOfWeek.Monday);
But I guess it depends on how many times you're going to use it as to wherther or not it's worth breaking out into a separate function.
Try something like this:
public static IEnumerable<DateTime> GetAllDayOfWeekPerMonth(int month, int year, DayOfWeek dayOfWeek)
{
var date = new DateTime(year, month, 1);
if(date.DayOfWeek != dayOfWeek)
{
int daysUntilDayOfWeek = ((int) dayOfWeek - (int) date.DayOfWeek + 7) % 7;
date = date.AddDays(daysUntilDayOfWeek);
}
List<DateTime> days = new List<DateTime>();
while(date.Month == month)
{
days.Add(date);
date = date.AddDays(7);
}
return days;
}
Demo fiddle here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With