Loop within a date range for each month and each day - c#

I have two text-boxes which are used to select a From and a To date. I need to have a loop where the outer loop will be for a year and the inner loop will run for each month.
Problem is with the code below, if I choose 11/01/2011 and 06/30/2012, my month loop runs once for month 11. After that the loop exits.. Any help is appreciated.
I'm using the code below to look into a SharePoint Calendar List (using CAML query) and fetch number of times 3, 5 consecutive days a certain room is available excluding week ends. Idea is to use CAML query to get the number of free days for each month and keep repeating till the last selected month.
int year = 0, month = 0;
for (year = Calendar1.SelectedDate.Year; year <= Calendar2.SelectedDate.Year; year++)
{
int i = year;
for (month = Calendar1.SelectedDate.Month; month <= Calendar2.SelectedDate.Month; month++)
{
int j = month;
}
}

Would something like this work?
for (DateTime date = Calendar1.SelectedDate; date < Calendar2.SelectedDate; date = date.AddMonths(1))
{
//code
}

If I understand you correctly you want to iterate through each month between the 2 dates. If so, this should work:
var dt2 = Calendar2.SelectedDate.Year;
var current = Calendar1.SelectedDate;
while (current < dt2)
{
current = current.AddMonths(1);
//do your work for each month here
}

Your starting and ending number for your inner loop should be conditional.
If you're on the start year then the start month should be the selected month; otherwise it should be 1.
If you're on the end year then the end month should be the selected month; otherwise it should be 12.
Example:
var startYear = Calendar1.SelectedDate.Year;
var endYear = Calender2.SelectedDate.Year;
var startMonth = Calender1.SelectedDate.Month;
var endMonth = Calender2.SelectedDate.Month;
for (var year = startYear; year <= endYear; year++)
{
var sm = year == startYear ? startMonth : 1;
var em = year == endYear ? endMonth : 12;
for (var month = sm; month <= em; month++)
{
}
}

For the start year, you need to start your inner loop from the appropriate month, and run through all 12 months, except on the end year, where you should run to the appropriate month. Something like this should work:
int year = 0, month = 0;
for (year = Calendar1.SelectedDate.Year; year <= Calendar2.SelectedDate.Year; year++)
{
int i = year;
for (month = (i==Calendar1.SelectedDate.Year ? Calendar1.SelectedDate.Month : 1); month <= (i==Calendar2.SelectedDate.Year ? Calendar2.SelectedDate.Month : 12); month++)
{
int j = month;
}
}

//Function return First day in Month For Date --example : 01-09-2012
public static DateTime FirstDayOfMonthFromDateTime(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, 1);
}
//code used to loop throw a Date range for each month
DateTime FirstDayInMonth = FirstDayOfMonthFromDateTime(Date);
DateTime TempDay = FirstDayInMonth;
int days = DateTime.DaysInMonth(FirstDayInMonth.Year, FirstDayInMonth.Month);
for (int i = 0; i < days; i++)
{
System.Out.Println(TempDay.toString());
TempDay.AddDays(1);
}
//then used code for each month in year (simple loop from 1-12)..

private static void Main(string[] args)
{
Console.WriteLine(DateTime.DaysInMonth(2020, 1));
var start = new DateTime(1900, 1, 1);
var end = new DateTime(2000, 12, 31);
end = new DateTime(end.Year, end.Month, DateTime.DaysInMonth(end.Year, end.Month));
var diff = Enumerable.Range(0, Int32.MaxValue)
.Select(e => start.AddMonths(e))
.TakeWhile(e => e <= end)
.Select(e => e);
foreach (var item in diff)
{
Console.WriteLine("Start Date - " + item.ToString("dd-MM-yyyy"));
Console.WriteLine("End Date - " + item.AddDays(DateTime.DaysInMonth(item.Year, item.Month) - 1).ToString("dd-MM-yyyy"));
}
}

Related

Count occurrence for each day of the week between two dates

I want to count occurrences, for each day of the week, between two given dates.
For example:
Between 20/07/2014 to 27/7/2014, an 8 day span, there were:
Sunday=2, monday=1, tuesday=1,...
Try this:
DateTime start = new DateTime(2014,07,20);
DateTime end = new DateTime(2014,07,27);
TimeSpan ts = end - start;
int limit = ts.Days;
var result = Enumerable.Range(0,limit+1)
.Select(x => start.AddDays(x))
.GroupBy(x => x.DayOfWeek)
.Select(x => new {day = x.Key, count = x.Count()});
We create a range of dates from start to end, inclusive of both dates, and then group by the day of week to get the days and corresponding counts.
Demo
You better convert the days first to DateTime instances:
DateTime d1 = new DateTime(2014,07,20);
DateTime d2 = new DateTime(2014,07,27);
Next you calculate the total days between the two dates:
int days = (int) Math.Floor((d2-d1).TotalDays)+1;
As well as the day of the week of the first date:
int dow = (int) d1.DayOfWeek;
Now we devide the number of days by seven and assign that number to all days: since this is the minimum occurences for each day:
int d7 = days/7;
int[] counts = new int[7];
for(int i = 0; i < 7; i++) {
counts[i] = d7;
}
The remainder of the days are distributed with the day of the week of d1 first:
int remainder = days-7*d7;
int dowi = dow;
while(remainder > 0) {
counts[dowi]++;
dowi = (dowi+1)%7;//next day of the week
remainder--;
}
Then we can return the arrray:
return counts;
Full method:
public static int[] countDelta (DateTime d1, DateTime d2) {
int days = (int) Math.Floor((d2-d1).TotalDays)+1;
int dow = (int) d1.DayOfWeek;
int d7 = days/7;
int[] counts = new int[7];
for(int i = 0; i < 7; i++) {
counts[i] = d7;
}
int remainder = days-7*d7;
int dowi = dow;
while(remainder > 0) {
counts[dowi]++;
dowi = (dowi+1)%7;//next day of the week
remainder--;
}
return counts;
}
The result of a csharp interactive session:
csharp> Foo.countDelta(new DateTime(2014,07,20),new DateTime(2014,07,27));
{ 2, 1, 1, 1, 1, 1, 1 }
The method runs in constant time (if the dates differ much, this will not have an impact on performance). The only constraint is that calendar must be modern: if somewhere in history, people skipped a few "days of the week", this could result in some problems.
You can try something like this. It may be not the best solution, but it's the first that came in mind:
var startDate = DateTime.Now;
var endDate = startDate.AddDays(15);
var rusultDictionary = new Dictionary<DayOfWeek, int>();
while (!startDate.Date.Equals(endDate.Date))
{
rusultDictionary[startDate.DayOfWeek] = rusultDictionary.ContainsKey(startDate.DayOfWeek) ? rusultDictionary[startDate.DayOfWeek] + 1 : 1;
startDate = startDate.AddDays(1);
}
the simple way is for loop each day in the period, and use switch case or if else to check the current date.DayOfWeek to count and save the week number, something like the following:
int mondays = 0;
switch(current.DayOfWeek){
case DayOfWeek.Monday:
mondays++;
break;
...
}
public static Dictionary<DayOfWeek, int> CountDayOfWeeks(DateTime #from, DateTime to)
{
var start = #from.Date;
var ret = Enum.GetValues(typeof(DayOfWeek)).Cast<DayOfWeek>().ToDictionary(x => x, x => 0);
while (start <= to)
{
ret[start.DayOfWeek]++;
start = start.AddDays(1);
}
return ret;
}
you can achieve it using Linq:
DateTime StartDate = DateTime.Now.AddDays(-14);
DateTime EndDate = DateTime.Now;
DayOfWeek day = DayOfWeek.Monday;
First get the all days between two dates:
List<DateTime> dates = Enumerable.Range(0, (int)((EndDate - StartDate).TotalDays) + 1)
.Select(n => StartDate.AddDays(n))
.ToList();
Now get Count on the base of day, currently it will get Count of Monday:
var MondayCount = dates.Count(x => x.DayOfWeek == day);
FIDDLE:
https://dotnetfiddle.net/ZopkFY

Calculate the Number of Mondays in a Month

I want to calculate the number of weeks within a month.
The first week of January 2014 starting from the first Monday is the 6th. So, January has 4 weeks.
The first week of March 2014 starting from the first Monday is the 3rd. So, March has 5 weeks.
I want to know how many weeks there are in a month counting from the first Monday, not the first day.
How do I do this?
I have this code but it is used to get week number of the month for specific dates.
public int GetWeekNumberOfMonth(DateTime date)
{
date = date.Date;
DateTime firstMonthDay = new DateTime(date.Year, date.Month, 1);
DateTime firstMonthMonday = firstMonthDay.AddDays((DayOfWeek.Monday + 7 - firstMonthDay.DayOfWeek) % 7);
if (firstMonthMonday > date)
{
firstMonthDay = firstMonthDay.AddMonths(-1);
firstMonthMonday = firstMonthDay.AddDays((DayOfWeek.Monday + 7 - firstMonthDay.DayOfWeek) % 7);
}
return (date - firstMonthMonday).Days / 7 + 1;
}
Try this:
Get the number of days in the current month, and find the first day. For each day in the month, see if the day is a Monday, if so, increment the value.
public static int MondaysInMonth(DateTime thisMonth)
{
int mondays = 0;
int month = thisMonth.Month;
int year = thisMonth.Year;
int daysThisMonth = DateTime.DaysInMonth(year, month);
DateTime beginingOfThisMonth = new DateTime(year, month, 1);
for (int i = 0; i < daysThisMonth; i++)
if (beginingOfThisMonth.AddDays(i).DayOfWeek == DayOfWeek.Monday)
mondays++;
return mondays;
}
You can use it like this with the current date:
Console.WriteLine(MondaysInMonth(DateTime.Now));
Output:
4
or with any month you choose:
Console.WriteLine(MondaysInMonth(new DateTime(year, month, 1)))
Just correction to Cyral code :
i must start from 0 as he is using AddDays method .
Reason :the above example returns 5 for NOV and 4 for DEC which is wrong..
Edited code :
public static int MondaysInMonth(DateTime thisMonth)
{
int mondays = 0;
int month = thisMonth.Month;
int year = thisMonth.Year;
int daysThisMonth = DateTime.DaysInMonth(year, month);
DateTime beginingOfThisMonth = new DateTime(year, month, 1);
for (int i = 0; i < daysThisMonth; i++)
if (beginingOfThisMonth.AddDays(i).DayOfWeek == DayOfWeek.Monday)
mondays++;
return mondays;
}
I tried to use that code, but in some cases it didn't work. So I found this code on MSDN.
public static int MondaysInMonth(this DateTime time)
{
//extract the month
int daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
var firstOfMonth = new DateTime(time.Year, time.Month, 1);
//days of week starts by default as Sunday = 0
var firstDayOfMonth = (int)firstOfMonth.DayOfWeek;
var weeksInMonth = (int)Math.Ceiling((firstDayOfMonth + daysInMonth) / 7.0);
return weeksInMonth;
}
I created it like a extension method, so I can use like that:
var dateTimeNow = DateTime.Now;
var weeks = dateTimeNow.MondaysInMonth();
The faster method without looping
private static double GetDaysCount(DateTime sampleDate, int DayOfWeekToMatch)
{
int FirstDayOfMonth = (int)(new DateTime(sampleDate.Year, sampleDate.Month, 1).DayOfWeek);
int FirstOccurrenceOn = 0;
if (FirstDayOfMonth < DayOfWeekToMatch)
FirstOccurrenceOn = DayOfWeekToMatch - FirstDayOfMonth + 1;
else
FirstOccurrenceOn = (7 - FirstDayOfMonth) + DayOfWeekToMatch + 1;
int totalDays = DateTime.DaysInMonth(sampleDate.Year, sampleDate.Month);
return Math.Ceiling((totalDays - FirstOccurrenceOn) / 7.0f);
}

How to get set of dates in a specific week ,given the month and the year?

How to get The dates in a specific week given the month and the year ?
For example:
My parameters :
June - 2013 - The second week
I want the result set like this :
9-6-2013
10-6-2013
11-6-2013
12-6-2013
13-6-2013
I want it starting from Sun to Thu .
Well in my Noda Time library I would:
Start from the end of the previous month
Loop as many times as you want finding the next Sunday
Go from there, yielding the days (so you can just use a foreach loop):
So:
IEnumerable<LocalDate> GetSundayToWednesday(int year, int month, int week)
{
LocalDate date = new LocalDate(year, month, 1).PlusDays(-1);
for (int i = 0; i < week; i++)
{
date = date.Next(IsoDayOfWeek.Sunday);
}
// You always want 4 days, Sunday to Wednesday
for (int i = 0; i < 4; i++)
{
yield return date;
date = date.PlusDays(1);
}
}
Using just DateTime, I'd probably start at the first day of the month that it could be (week * 7 + 1) and loop until I hit the right day of week, then go from there:
IEnumerable<DateTime> GetSundayToWednesday(int year, int month, int week)
{
// Consider breaking this part out into a separate method?
DateTime date = new DateTime(year, month, week * 7 + 1);
for (int i = 0; i < 7; i++)
{
if (date.DayOfWeek == DayOfWeek.Sunday)
{
break;
}
date = date.AddDays(1);
}
// You always want 4 days, Sunday to Wednesday
for (int i = 0; i < 4; i++)
{
yield return date;
date = date.AddDays(1);
}
}
Looping like this isn't terribly efficient - you could just work out how many days to advance - but it's more obviously right. You can very easily end up with off-by-one errors (or going back into the previous month) with a more efficient approach. You may choose to put more effort into being efficient if this is important, of course.
I have not really tested this but I think that does more or less what you want:
int year = 2013;
int month = 6;
int lookupWeek = 2;
int daysInMonth = DateTime.DaysInMonth(year, month);
int weekCounter = 1;
List<DateTime> weekDays = new List<DateTime>();
for (int day = 1; day <= daysInMonth; day++)
{
DateTime date = new DateTime(year,month,day);
if(date.DayOfWeek == DayOfWeek.Sunday && day > 1) weekCounter++;
if(weekCounter == lookupWeek) weekDays.Add(date);
}
If you are interested in the client-side (JavaScript) route, then date.js might be worth a look, it allows for the following:
// What date is next thursday?
Date.today().next().thursday();
// Add 3 days to Today
Date.today().add(3).days();
// Is today Friday?
Date.today().is().friday();
// Number fun
(3).days().ago();
// 6 months from now
var n = 6;
n.months().fromNow();
// Set to 8:30 AM on the 15th day of the month
Date.today().set({ day: 15, hour: 8, minute: 30 });
// Convert text into Date
Date.parse('today');
Date.parse('t + 5 d'); // today + 5 days
Date.parse('next thursday');
Date.parse('February 20th 1973');
Date.parse('Thu, 1 July 2004 22:30:00');
I find the natural language syntax (i.e. 'next thursday') to be quite powerful.
This method gives the days in a specific week of a month:
static IEnumerable<string> DaysInWeek(int year, int month, int week)
{
var date = new DateTime(year, month, 1);
var calendar = new GregorianCalendar();
var firstWeek = calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFullWeek, DayOfWeek.Sunday);
var days = calendar.GetDaysInMonth(year, month);
var daysInWeek = (from day in Enumerable.Range(0, calendar.GetDaysInMonth(year, month) - 1)
let dayDate = date.AddDays(day)
let week2 = calendar.GetWeekOfYear(dayDate, CalendarWeekRule.FirstFullWeek, DayOfWeek.Sunday) - firstWeek + 1
where week2 == week
select day + 1).ToList();
foreach (var d in daysInWeek) yield return string.Format("{0:00}-{1:00}-{2:0000}", d, month, year);
}
And the output of this:
foreach (var d in DaysInWeek(week, year, month).Take(5)) Log.Info(d);
Would be:
09-06-2013
10-06-2013
11-06-2013
12-06-2013
13-06-2013
Note: I have edited the code. There was a little bug; because in many months, first week and last week are not complete weeks and some days of that week belongs to another month.
If you were keen to use linq (I almost always am!), you could do this:
int year = 2013;
int month = 6;
int weekOfMonth = 2;
var dates = Enumerable.Range(1, DateTime.DaysInMonth(year, month))
.Select(day => new DateTime(year, month, day))
.GroupBy(g=> g.DayOfYear/7)
.ToList();
var week = dates.Min(g => g.Key) + weekOfMonth - 1;
var result = dates.Where(g=> g.Key.Equals(week)).Select(g => g.ToList());
try this
protected void button_click(object sender, EventArgs e)
{
DateTime dt = new DateTime(2013, 6, 1);
string[] dates = getDates(dt);
}
public string[] getDates(DateTime dt)
{
string[] result = new string[7]; ;
for (int i = getDay(dt.DayOfWeek.ToString()); i < 7; i++)
{
if (i == 0)
{
break;
}
else
{
dt = dt.AddDays(1);
}
}
for (int i = 0; i < 7; i++)
{
dt = dt.AddDays(1);
result[i] = dt.ToShortDateString();
}
return result;
}
public int getDay(string day)
{
switch (day)
{
case "Monday":
return 0;
case "Tuesday":
return 1;
case "Wednesday":
return 2;
case "Thursday":
return 3;
case "Friday":
return 4;
case "Saturday":
return 5;
case "Sunday":
return 6;
default:
return 0;
}
}## Heading ##

How to find the 3rd Friday in a month with C#?

Given a date (of type DateTime), how do I find the 3rd Friday in the month of that date?
I'm going to repeat my answer from here with one little addition.
The language-agnostic version:
To get the first particular day of the month, start with the first day of the month: yyyy-mm-01. Use whatever function is available to give a number corresponding to the day of the week; in C# this would be DateTime.DayOfWeek. Subtract that number from the day you are looking for; for example, if the first day of the month is Wednesday (3) and you're looking for Friday (5), subtract 3 from 5, leaving 2. If the answer is negative, add 7. Finally add that to the first of the month; for my example, the first Friday would be the 3rd.
To get the last Friday of the month, find the first Friday of the next month and subtract 7 days.
To get the 3rd Friday of the month, add 14 days to the first Friday.
I haven't tested this, but since the third Friday can't possibly occur before the 15th of the month, create a new DateTime, then just increment until you get to a Friday.
DateTime thirdFriday= new DateTime(yourDate.Year, yourDate.Month, 15);
while (thirdFriday.DayOfWeek != DayOfWeek.Friday)
{
thirdFriday = thirdFriday.AddDays(1);
}
I followed User:Mark Ransom's algorithm and wrote a generalized day finder. For example to get the 3rd friday of december 2013,
int thirdFriday = DayFinder.FindDay(2013, 12, DayOfWeek.Friday, 3);
And here is the function definition. It doesn't have any iterative loops, so its efficient.
public class DayFinder
{
//For example to find the day for 2nd Friday, February, 2016
//=>call FindDay(2016, 2, DayOfWeek.Friday, 2)
public static int FindDay(int year, int month, DayOfWeek Day, int occurance)
{
if (occurance <= 0 || occurance > 5)
throw new Exception("Occurance is invalid");
DateTime firstDayOfMonth = new DateTime(year, month, 1);
//Substract first day of the month with the required day of the week
var daysneeded = (int)Day - (int)firstDayOfMonth.DayOfWeek;
//if it is less than zero we need to get the next week day (add 7 days)
if (daysneeded < 0) daysneeded = daysneeded + 7;
//DayOfWeek is zero index based; multiply by the Occurance to get the day
var resultedDay = (daysneeded + 1) + (7 * (occurance - 1));
if (resultedDay > (firstDayOfMonth.AddMonths(1) - firstDayOfMonth).Days)
throw new Exception(String.Format("No {0} occurance(s) of {1} in the required month", occurance, Day.ToString()));
return resultedDay;
}
}
Probably best to abstract this to a method to do any date/day combination:
(Extension Method)
public static bool TryGetDayOfMonth(this DateTime instance,
DayOfWeek dayOfWeek,
int occurance,
out DateTime dateOfMonth)
{
if (instance == null)
{
throw new ArgumentNullException("instance");
}
if (occurance <= 0 || occurance > 5)
{
throw new ArgumentOutOfRangeException("occurance", "Occurance must be greater than zero and less than 6.");
}
bool result;
dateOfMonth = new DateTime();
// Change to first day of the month
DateTime dayOfMonth = instance.AddDays(1 - instance.Day);
// Find first dayOfWeek of this month;
if (dayOfMonth.DayOfWeek > dayOfWeek)
{
dayOfMonth = dayOfMonth.AddDays(7 - (int)dayOfMonth.DayOfWeek + (int)dayOfWeek);
}
else
{
dayOfMonth = dayOfMonth.AddDays((int)dayOfWeek - (int)dayOfMonth.DayOfWeek);
}
// add 7 days per occurance
dayOfMonth = dayOfMonth.AddDays(7 * (occurance - 1));
// make sure this occurance is within the original month
result = dayOfMonth.Month == instance.Month;
if (result)
{
dateOfMonth = dayOfMonth;
}
return result;
}
Results:
DateTime myDate = new DateTime(2013, 1, 1)
DateTime dateOfMonth;
myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 1, out dateOfMonth)
// returns: true; dateOfMonth = Sunday, 1/6/2013
myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 4, out dateOfMonth)
// returns: true; dateOfMonth = Sunday, 1/27/2013
myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 5, out dateOfMonth)
// returns: false;
myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 1, out dateOfMonth)
// returns: true; dateOfMonth = Wednesday, 1/2/2013
myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 4, out dateOfMonth)
// returns: true; dateOfMonth = Wednesday, 1/23/2013
myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 5, out dateOfMonth)
// returns: true; dateOfMonth = Wednesday, 1/30/2013
// etc
Old post, but I found remarkably few decent answers online for this surely quite common problem! Mark Ransom's answer should be the last word on this algorithm-wise, but here is a C# helper class (in this case I think clearer than extensions) for anyone who wants a quick answer to the common problems of "first day of week in month", "xth day of week in month" and "last day of week in month".
I modified it to return DateTime.MinValue if the Xth day of the week falls outside the provided month rather than wrapping to the next month, because that to me seems more useful.
I've thrown in a LINQPad-runnable example program too.
void Main()
{
DayOfWeek dow = DayOfWeek.Friday;
int y = 2014;
int m = 2;
String.Format("First {0}: {1}", new object[] { dow, DateHelper.FirstDayOfWeekInMonth(y, m, dow) }).Dump();
"".Dump();
String.Format("Last {0}: {1}", new object[] { dow, DateHelper.LastDayOfWeekInMonth(y, m, dow) }).Dump();
"".Dump();
for(int i = 1; i <= 6; i++)
String.Format("{0} #{1}: {2}", new object[] { dow, i, DateHelper.XthDayOfWeekInMonth(y, m, dow, i) }).Dump();
}
public class DateHelper
{
public static DateTime FirstDayOfWeekInMonth(int year, int month, DayOfWeek day)
{
DateTime res = new DateTime(year, month, 1);
int offset = -(res.DayOfWeek - day);
if (offset < 0)
offset += 7;
res = res.AddDays(offset);
return res;
}
public static DateTime LastDayOfWeekInMonth(int year, int month, DayOfWeek day)
{
DateTime dt = new DateTime(year, month, 1).AddMonths(1);
DateTime res = FirstDayOfWeekInMonth(dt.Year, dt.Month, day);
res = res.AddDays(-7);
return res;
}
public static DateTime XthDayOfWeekInMonth(int year, int month, DayOfWeek day, int x)
{
DateTime res = DateTime.MinValue;
if (x > 0)
{
res = FirstDayOfWeekInMonth(year, month, day);
if (x > 1)
res = res.AddDays((x - 1) * 7);
res = res.Year == year && res.Month == month ? res : DateTime.MinValue;
}
return res;
}
}
Prints:
First Friday: 07/02/2014 00:00:00
Last Friday: 28/02/2014 00:00:00
Friday #1: 07/02/2014 00:00:00
Friday #2: 14/02/2014 00:00:00
Friday #3: 21/02/2014 00:00:00
Friday #4: 28/02/2014 00:00:00
Friday #5: 01/01/0001 00:00:00
Friday #6: 01/01/0001 00:00:00
Slightly more optimized version:
DateTime Now = DateTime.Now;
DateTime TempDate = new DateTime(Now.Year, Now.Month, 1);
// find first friday
while (TempDate.DayOfWeek != DayOfWeek.Friday)
TempDate = TempDate.AddDays(1);
// add two weeks
TempDate = TempDate.AddDays(14);
This is a version that uses LINQ and functional programming style.
It works like this.
First, take all of the days of the month. Then select only the ones of the right day (Friday). Finally take the nth (3rd) entry and return.
// dt: The date to start from (usually DateTime.Now)
// n: The nth occurance (3rd)
// weekday: the day of the week to look for
public DateTime GetNthWeekdayOfMonth(DateTime dt, int n, DayOfWeek weekday)
{
var days = Enumerable.Range(1, DateTime.DaysInMonth(dt.Year, dt.Month)).Select(day => new DateTime(dt.Year, dt.Month, day));
var weekdays = from day in days
where day.DayOfWeek == weekday
orderby day.Day ascending
select day;
int index = n - 1;
if (index >= 0 && index < weekdays.Count())
return weekdays.ElementAt(index);
else
throw new InvalidOperationException("The specified day does not exist in this month!");
}
My reasoning goes like this
the 15th is the first possible "third Friday" (1,8,15)
therefore we're looking for the first Friday on or after the 15th
DayOfWeek is an enumeration starting with 0 for Sunday
Therefore you have to add an offet of 5-(int)baseDay.DayOfWeek to the 15th
Except that the above offset can be negative, which we fix by adding 7, then doing modulo 7.
In code:
public static DateTime GetThirdFriday(int year, int month)
{
DateTime baseDay = new DateTime(year, month, 15);
int thirdfriday = 15 + ((12 - (int)baseDay.DayOfWeek) % 7);
return new DateTime(year, month, thirdfriday);
}
Since there are only 7 possible results, you could also do this:
private readonly static int[] thirdfridays =
new int[] { 20, 19, 18, 17, 16, 15, 21 };
public static int GetThirdFriday(int year, int month)
{
DateTime baseDay = new DateTime(year, month, 15);
return thirdfridays[(int)baseDay.DayOfWeek];
}
I pass this the DateTime for the start of the month I am looking at.
private DateTime thirdSunday(DateTime timeFrom)
{
List<DateTime> days = new List<DateTime>();
DateTime testDate = timeFrom;
while (testDate < timeFrom.AddMonths(1))
{
if (testDate.DayOfWeek == DayOfWeek.Friday)
{
days.Add(testDate);
}
testDate = testDate.AddDays(1);
}
return days[2];
}
I know of no clean/built in way of doing this. But it's not too hard to code up:
DateTime now = DateTime.Now;
for (int i = 0; i < 7; ++i)
{
DateTime d = new DateTime(now.Year, now.Month, i+1);
if (d.DayOfWeek == DayOfWeek.Friday)
{
return d.AddDays(14);
}
}
public DateTime GetThirdThursday(DateTime now)
{
DateTime ThirdThursday;
now = DateTime.Now;
string wkday;
DateTime firstday = new DateTime(now.Year, now.Month, 1);
ThirdThursday = firstday.AddDays(15);
// ThirdThursday = now.AddDays((now.Day - 1) * -1).AddDays(14);
wkday = ThirdThursday.DayOfWeek.ToString();
while (wkday.CompareTo("Thursday") < 0)
{
ThirdThursday.AddDays(1);
}
return ThirdThursday;
}
Late to the game but here's my solution to add DateTime extension functionality which accounts for the January to December issue when subtracting occurrence values and accounts for if the occurrence is 5 - which in my case should return the last occurrence which would either be number 4 or 5 depending on where the day lands in the month:
public static DateTime NthOf(this DateTime CurDate, int Occurrence, DayOfWeek Day)
{
//Last day of month if 5 - return last day.
if (Occurrence == 5)
{
return LastDayOfMonth(CurDate, Day);
}
var fday = new DateTime(CurDate.Year, CurDate.Month, 1, CurDate.Hour, CurDate.Minute, CurDate.Second);
var firstoccurrence = fday.DayOfWeek == Day ? fday : fday.AddDays(Day - fday.DayOfWeek);
// CurDate = 2011.10.1 Occurance = 1, Day = Friday >> 2011.09.30 FIX.
if (firstoccurrence.Month < CurDate.Month)
{
Occurrence = Occurrence + 1;
} else if (firstoccurrence.Month == 12 && CurDate.Month == 1)
{
Occurrence = Occurrence + 1;
}
return firstoccurrence.AddDays(7 * (Occurrence - 1));
}
public static DateTime LastDayOfMonth(this DateTime CurDate, DayOfWeek Day)
{
DateTime EndOfMonth = new DateTime(CurDate.Year, CurDate.Month, 1).AddMonths(1).AddDays(-1);
while (EndOfMonth.DayOfWeek != Day)
{
EndOfMonth = EndOfMonth.AddDays(-1);
}
return EndOfMonth;
}
The you can call your method with something like this:
Console.WriteLine(DateTime.Now.NthOf(3, DayOfWeek.Friday).ToString());
This would return the third Friday of the current month and log it to the console as a string value. It extends from DateTime nicely and does not require any usage of a static helper class or any additional moving parts.
int numday = 0;
int dayofweek = 5; //friday
DateTime thirdfriday;
for (int i = 0; i < (date.AddMonths(1) - date).Days && numday <3; i++)
{
if ((int)date.AddDays(i).DayOfWeek == dayofweek)
{
numday++;
}
if (numday == 3)
{
thirdfriday = date.AddDays(i);
}
}
Sorry to jump in late on this... Might help someone else tho.
Begin rant: Loops, yuck. Too much code, yuck. Not Generic Enough, yuck.
Here's a simple function with a free overload.
public DateTime DateOfWeekOfMonth(int year, int month, DayOfWeek dayOfWeek, byte weekNumber)
{
DateTime tempDate = new DateTime(year, month, 1);
tempDate = tempDate.AddDays(-(tempDate.DayOfWeek - dayOfWeek));
return
tempDate.Day > (byte)DayOfWeek.Saturday
? tempDate.AddDays(7 * weekNumber)
: tempDate.AddDays(7 * (weekNumber - 1));
}
public DateTime DateOfWeekOfMonth(DateTime sender, DayOfWeek dayOfWeek, byte weekNumber)
{
return DateOfWeekOfMonth(sender.Year, sender.Month, dayOfWeek, weekNumber);
}
Your usage:
DateTime thirdFridayOfMonth = DateOfWeekOfMonth(DateTime.Now, DayOfWeek.Friday, 3);
Here's my algorithm:
Find the number of days until the upcoming Friday.
Initialize a counter and set it to 1. Subtract seven days from the date returned from [1], then compare the month from the date returned against the date returned from (1).
If the months are not equal, return the counter from [2].
If the months are equal, recurse into [2] and add 1 to the counter created in [2].
The counter will give you the nth Friday of the month for that date (or its upcoming Friday).
Following works great, no validation for occurrence is provided. You can find any nth day for the given date month either from start or last. Provide minus occurrence value if you are looking for from the last.
public static DateTime GetDayOfMonth(DateTime dateValue, DayOfWeek dayOfWeek, int occurance)
{
List<DateTime> dayOfWeekRanges = new List<DateTime>();
//move to the first of th month
DateTime startOfMonth = new DateTime(dateValue.Year, dateValue.Month, 1);
//move startOfMonth to the dayOfWeek requested
while (startOfMonth.DayOfWeek != dayOfWeek)
startOfMonth = startOfMonth.AddDays(1);
do
{
dayOfWeekRanges.Add(startOfMonth);
startOfMonth = startOfMonth.AddDays(7);
} while (startOfMonth.Month == dateValue.Month);
bool fromLast = occurance < 0;
if (fromLast)
occurance = occurance * -1;
if (fromLast)
return dayOfWeekRanges[dayOfWeekRanges.Count - occurance];
else
return dayOfWeekRanges[occurance - 1];
}
Here is my two cents...
An optimized solution without unnecessary loops or tests :
public static DateTime ThirdFridayOfMonth(DateTime dateTime)
{
int day = dateTime.Day;
return dateTime.AddDays(21 - day - ((int)dateTime.DayOfWeek + 37 - day) % 7);
}
I wrote extended version of #justcoding121's code that can get from the last day of the month. I don't know this algorithm is right, but it works so far.
public static int? GetNthDayOfWeekInMonth(int year, int month, DayOfWeek dow, int weekNumOfMonth)
{
if (weekNumOfMonth < -5 || weekNumOfMonth == 0 || weekNumOfMonth > 5)
throw new ArgumentOutOfRangeException("weekNumOfMonth", $"must be between 1~5 or -1~-5. ({weekNumOfMonth})");
int daysOfMonth = DateTime.DaysInMonth(year, month);
if (weekNumOfMonth > 0)
{
var firstDay = new DateTime(year, month, 1);
var firstDayOfTargetDOW = (int)dow - (int)firstDay.DayOfWeek;
if (firstDayOfTargetDOW < 0)
firstDayOfTargetDOW += 7;
var resultedDay = (firstDayOfTargetDOW + 1) + (7 * (weekNumOfMonth - 1));
if (resultedDay > daysOfMonth)
return null;
return resultedDay;
}
else
{
var lastDay = new DateTime(year, month, daysOfMonth);
var firstDayOfTargetDOW = (int)lastDay.DayOfWeek - (int)dow;
if (firstDayOfTargetDOW < 0)
firstDayOfTargetDOW += 7;
var resultedDay = firstDayOfTargetDOW + (7 * (Math.Abs(weekNumOfMonth) - 1));
if (resultedDay > daysOfMonth)
return null;
return (daysOfMonth - resultedDay);
}
}
usage
Assert.AreEqual(02, DateTimeHelper.GetNthDayOfWeekInMonth(2019, 11, DayOfWeek.Saturday, 1));
Assert.AreEqual(30, DateTimeHelper.GetNthDayOfWeekInMonth(2019, 11, DayOfWeek.Saturday, -1));
I know this post is old. I have this solution, trying to find a more clean code. #unclebob
public static DateTime FindTheNthDay(
int year, int month, DayOfWeek day, int occurrence)
{
var startDate = new DateTime(year, month, 1);
while(startDate.DayOfWeek != day)
{
startDate = startDate.AddDays(1);
}
var nDays = 7 * (occurrence - 1);
var result = startDate.AddDays(nDays);
return result;
}
> FindTheNthDay(2006, 11, DayOfWeek.Friday, 4)
[11/24/2006 12:00:00 AM]
> FindTheNthDay(2005, 11, DayOfWeek.Friday, 4)
[11/25/2005 12:00:00 AM]
> FindTheNthDay(2004, 11, DayOfWeek.Friday, 4)
[11/26/2004 12:00:00 AM]
> FindTheNthDay(2003, 11, DayOfWeek.Friday, 4)
[11/28/2003 12:00:00 AM]
> FindTheNthDay(1983, 11, DayOfWeek.Friday, 4)
[11/25/1983 12:00:00 AM]
> FindTheNthDay(1978, 11, DayOfWeek.Friday, 4)
[11/24/1978 12:00:00 AM]
> FindTheNthDay(1972, 11, DayOfWeek.Friday, 4)
[11/24/1972 12:00:00 AM]
public static bool IsThirdWednesday(DateTime inputDate)
{
DateTime firstDayOfMonth = new DateTime(inputDate.Year, inputDate.Month, 1);
DateTime firstDayOfNextMonth = firstDayOfMonth.AddMonths(1);
int wednesdayCount = 0;
while(firstDayOfMonth < firstDayOfNextMonth)
{
if (firstDayOfMonth.DayOfWeek == DayOfWeek.Wednesday)
wednesdayCount++;
if (wednesdayCount == 3)
{
if (inputDate == firstDayOfMonth)
return true;
else
return false;
}
firstDayOfMonth = firstDayOfMonth.AddDays(1);
}
return false;
}

How do I get the month number from the year and week number in c#?

As the title says, given the year and the week number, how do I get the month number?
edit: if a week crosses two months, I want the month the first day of the week is in.
edit(2): This is how I get the week number:
CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(DateTime.Now, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
I'm just trying to do the reverse.
If you assume that the first day of your definition of week is the same day as the 1st day of the year, then this will work:
int year = 2000;
int week = 9;
int month = new DateTime(year, 1, 1).AddDays(7 * (week - 1)).Month;
Obviously, a true answer would depend on how you define the first day of the week, and how you define how a week falls into a month when it overlaps more than one.
This is what I ended up doing:
static int GetMonth(int Year, int Week)
{
DateTime tDt = new DateTime(Year, 1, 1);
tDt.AddDays((Week - 1) * 7);
for (int i = 0; i <= 365; ++i)
{
int tWeek = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
tDt,
CalendarWeekRule.FirstDay,
DayOfWeek.Monday);
if (tWeek == Week)
return tDt.Month;
tDt = tDt.AddDays(1);
}
return 0;
}
I would have preferred something simpler, but it works :)
Wouldn't it also depend on the day of the week?
this should be able to help
public int getMonth(int weekNum, int year)
{
DateTime Current = new DateTime(year, 1, 1);
System.DayOfWeek StartDOW = Current.DayOfWeek;
int DayOfYear = (weekNum * 7) - 6; //1st day of the week
if (StartDOW != System.DayOfWeek.Sunday) //means that last week of last year's month
{
Current = Current.AddDays(7 - (int)Current.DayOfWeek);
}
return Current.AddDays(DayOfYear).Month;
}
Another problem you could face is that most years do not start at the beginning of a week, which shifts everything.
Assumptions:
Sunday is the first day of the week.
Partial week still counts as week 1
Outputs beginning and ending month as integer array.
public int[] getMonth(int weekNum, int year)
{
DateTime StartYear = new DateTime(year, 1, 1);
System.DayOfWeek StartDOW = StartYear.DayOfWeek;
DateTime DayOfYearWeekStart = default(DateTime);
DateTime DayOfYearWeekEnd = default(DateTime);
int x = 0;
if ((StartDOW == System.DayOfWeek.Sunday)) {
DayOfYearWeekStart = StartYear.AddDays((weekNum - 1) * 7);
DayOfYearWeekEnd = DayOfYearWeekStart.AddDays(6);
} else {
for (x = 0; x <= 7; x += 1) {
if (StartYear.AddDays(x).DayOfWeek == DayOfWeek.Sunday) {
break; // TODO: might not be correct. Was : Exit For
}
}
if (weekNum == 1) {
DayOfYearWeekStart = StartYear;
DayOfYearWeekEnd = StartYear.AddDays(x - 1);
} else if (weekNum > 1) {
DayOfYearWeekStart = StartYear.AddDays(((weekNum - 2) * 7) + x);
DayOfYearWeekEnd = DayOfYearWeekStart.AddDays(6);
}
}
int[] Month = new int[2];
Month[0] = DayOfYearWeekStart.Month;
Month[1] = DayOfYearWeekEnd.Month;
return Month;
}
You cant. You need at least the day on which the 1st week starts (or when the week starts), to get an accurate answer.
You cant. A week may start in one month and end in another.
I think you're assuming that a "week" is any group of 7 sequential days. It isn't. Given Year(2008), Week(5), you could be in either January or Febuary, depending on when your "week" starts.
In .NET 3.0 and later you can use the ISOWeek-Class.
public static int MonthOfFirstDay(int year, int week)
{
return ISOWeek.ToDateTime(year, week, DayOfWeek.Monday).Month;
}
Note that the year might not fit, as the first week of a year can already start in end of December the year before. For instance the first week of 2020 started on Monday 2019-12-30.
// Calculate the week number according to ISO 8601
public static int Iso8601WeekNumber(DateTime dt)
{
return CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
// ...
DateTime dt = DateTime.Now;
// Calculate the WeekOfMonth according to ISO 8601
int weekOfMonth = Iso8601WeekNumber(dt) - Iso8601WeekNumber(dt.AddDays(1 - dt.Day)) + 1;

Categories