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;
}
Related
I have been trying to find the 5th week date of a day in a month like 5th week Monday date, 5th week Tue date, Wed... and so on based on the date from the same month. This date could belong to any week of same month.
I tried like
DateTime MonthEventDate=05/01/2016; //Date format in dd/MM/yyyy format
DayOfWeek EventDay="Sunday"; //For Example i want to find 5th Sunday in January Month, but days too will change everytime based on user selection
string SelectedWeek="5"; //Here i'm getting the week in which i need to find the given date i.e, 5th Monday or Tuesday & so on
if (SelectedWeek == "5")
{
//Here i tried to add number of days to my initial day to find 5th day date, but every time its returning next month value
MonthEventDate = MonthEventDate.AddDays((EventDay < MonthEventDate.DayOfWeek ? 31 : 28) + EventDay - MonthEventDate.DayOfWeek);
}
I know the logic is wrong but i want to get date of 5th day of the week, and if that day is not present, return 0. Looking for some guidance
Note: Here Month will change based on User Input, so how to return Date of fifth day, if it exist in the given month
This should give you the 5th day (if there is one) ...
DateTime dayInMonth = DateTime.Now;
DayOfWeek dayToFind = DayOfWeek.Friday;
var fifth= Enumerable.Range(1, DateTime.DaysInMonth(dayInMonth.Year, dayInMonth.Month))
.Select(day => new DateTime(dayInMonth.Year, dayInMonth.Month, day))
.Where(day => day.DayOfWeek == dayToFind)
.Skip(4)
.FirstOrDefault();
Extending #Soner Gönül's answer. In input you put required day of week, required month and required year. On output you get date of same day of week in fifth weeks, or null
public DateTime? FifthDay(DayOfWeek dayOfWeek, byte monthNum, int year)
{
if (monthNum > 12 || monthNum < 1)
{
throw new Exception("Month value should be between 1 and 12");
}
var searchDate = new DateTime(year, monthNum, 1);
var weekDay = searchDate.DayOfWeek;
if (weekDay == dayOfWeek)
{
searchDate = searchDate.AddDays(28);
}
for (DateTime d = searchDate; d < d.AddDays(7); d = d.AddDays(1))
{
if (d.DayOfWeek == dayOfWeek)
{
searchDate = searchDate.AddDays(28);
break;
}
}
if (searchDate.Month == monthNum)
return searchDate;
return null;
}
You can use a simple math like this (no validations included)
static DateTime? FindDate(int year, int month, DayOfWeek dayOfWeek, int weekOfMonth = 5)
{
var baseDate = new DateTime(year, month, 1);
int firstDateOffset = ((int)dayOfWeek - (int)baseDate.DayOfWeek + 7) % 7;
var date = baseDate.AddDays(firstDateOffset + 7 * (weekOfMonth - 1));
return date.Month == month ? date : (DateTime?)null;
}
I think the code is self explanatory. The only trick that probably needs explanation is the line
int firstDateOffset = ((int)dayOfWeek - (int)baseDate.DayOfWeek + 7) % 7;
which handles the case when let say the month starts in Friday and you asked for Monday, and is a short equivalent of
int firstDateOffset = (int)dayOfWeek - (int)baseDate.DayOfWeek;
if (firstDateOffset < 0) firstDateOffset += 7;
Usage in your example
var monthEventDate = FindDate(2016, 1, DayOfWeek.Sunday, 5);
You can refer this demo code
int requiredDay = 5; //Day number i.e 0-6(Sunday to SaturDay)
DateTime day = new DateTime(2016, 1, 1); //Month,year,Date
if (DateTime.DaysInMonth(day.Year, day.Month) > 28)
{
//Get the first day name of the month
int firstMonthDay = (int)day.DayOfWeek;
int offset=0;
//Number of days from the first day for the required day
if (firstMonthDay <= requiredDay)
offset = requiredDay - firstMonthDay;
else
offset = 7 - firstMonthDay + requiredDay;
//
DateTime firstoccurence = day.AddDays((double)offset);
DateTime fifthOccurence = firstoccurence.AddDays(28);
if (fifthOccurence.Month == firstoccurence.Month)
MessageBox.Show(fifthOccurence.ToString());
else
MessageBox.Show("No 5th Occurence for this day");
}
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 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 ##
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;
How do I find the start of the week (both Sunday and Monday) knowing just the current time in C#?
Something like:
DateTime.Now.StartWeek(Monday);
Use an extension method:
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
}
Which can be used as follows:
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Sunday);
The quickest way I can come up with is:
var sunday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
If you would like any other day of the week to be your start date, all you need to do is add the DayOfWeek value to the end
var monday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Monday);
var tuesday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Tuesday);
A little more verbose and culture-aware:
System.Globalization.CultureInfo ci =
System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
DayOfWeek today = DateTime.Now.DayOfWeek;
DateTime sow = DateTime.Now.AddDays(-(today - fdow)).Date;
Using Fluent DateTime:
var monday = DateTime.Now.Previous(DayOfWeek.Monday);
var sunday = DateTime.Now.Previous(DayOfWeek.Sunday);
Ugly but it at least gives the right dates back
With start of week set by system:
public static DateTime FirstDateInWeek(this DateTime dt)
{
while (dt.DayOfWeek != System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
dt = dt.AddDays(-1);
return dt;
}
Without:
public static DateTime FirstDateInWeek(this DateTime dt, DayOfWeek weekStartDay)
{
while (dt.DayOfWeek != weekStartDay)
dt = dt.AddDays(-1);
return dt;
}
Let's combine the culture-safe answer and the extension method answer:
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
return DateTime.Today.AddDays(-(DateTime.Today.DayOfWeek- fdow));
}
}
This would give you the preceding Sunday (I think):
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek, 0, 0, 0);
For Monday
DateTime startAtMonday = DateTime.Now.AddDays(DayOfWeek.Monday - DateTime.Now.DayOfWeek);
For Sunday
DateTime startAtSunday = DateTime.Now.AddDays(DayOfWeek.Sunday- DateTime.Now.DayOfWeek);
This may be a bit of a hack, but you can cast the .DayOfWeek property to an int (it's an enum and since its not had its underlying data type changed it defaults to int) and use that to determine the previous start of the week.
It appears the week specified in the DayOfWeek enum starts on Sunday, so if we subtract 1 from this value that'll be equal to how many days the Monday is before the current date. We also need to map the Sunday (0) to equal 7 so given 1 - 7 = -6 the Sunday will map to the previous Monday:-
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
dayOfWeek = dayOfWeek == 0 ? 7 : dayOfWeek;
DateTime startOfWeek = now.AddDays(1 - (int)now.DayOfWeek);
The code for the previous Sunday is simpler as we don't have to make this adjustment:-
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
DateTime startOfWeek = now.AddDays(-(int)now.DayOfWeek);
using System;
using System.Globalization;
namespace MySpace
{
public static class DateTimeExtention
{
// ToDo: Need to provide culturaly neutral versions.
public static DateTime GetStartOfWeek(this DateTime dt)
{
DateTime ndt = dt.Subtract(TimeSpan.FromDays((int)dt.DayOfWeek));
return new DateTime(ndt.Year, ndt.Month, ndt.Day, 0, 0, 0, 0);
}
public static DateTime GetEndOfWeek(this DateTime dt)
{
DateTime ndt = dt.GetStartOfWeek().AddDays(6);
return new DateTime(ndt.Year, ndt.Month, ndt.Day, 23, 59, 59, 999);
}
public static DateTime GetStartOfWeek(this DateTime dt, int year, int week)
{
DateTime dayInWeek = new DateTime(year, 1, 1).AddDays((week - 1) * 7);
return dayInWeek.GetStartOfWeek();
}
public static DateTime GetEndOfWeek(this DateTime dt, int year, int week)
{
DateTime dayInWeek = new DateTime(year, 1, 1).AddDays((week - 1) * 7);
return dayInWeek.GetEndOfWeek();
}
}
}
Putting it all together, with Globalization and allowing for specifying the first day of the week as part of the call we have
public static DateTime StartOfWeek ( this DateTime dt, DayOfWeek? firstDayOfWeek )
{
DayOfWeek fdow;
if ( firstDayOfWeek.HasValue )
{
fdow = firstDayOfWeek.Value;
}
else
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
fdow = ci.DateTimeFormat.FirstDayOfWeek;
}
int diff = dt.DayOfWeek - fdow;
if ( diff < 0 )
{
diff += 7;
}
return dt.AddDays( -1 * diff ).Date;
}
Step 1:
Create a static class
public static class TIMEE
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
public static DateTime EndOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 - (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(1 * diff).Date;
}
}
Step 2: Use this class to get both start and end day of the week
DateTime dt = TIMEE.StartOfWeek(DateTime.Now ,DayOfWeek.Monday);
DateTime dt1 = TIMEE.EndOfWeek(DateTime.Now, DayOfWeek.Sunday);
var now = System.DateTime.Now;
var result = now.AddDays(-((now.DayOfWeek - System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 7) % 7)).Date;
This would give you midnight on the first Sunday of the week:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek, t.Hour, t.Minute, t.Second);
This gives you the first Monday at midnight:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek - 1, t.Hour, t.Minute, t.Second);
Try with this in C#. With this code you can get both the first date and last date of a given week. Here Sunday is the first day and Saturday is the last day, but you can set both days according to your culture.
DateTime firstDate = GetFirstDateOfWeek(DateTime.Parse("05/09/2012").Date, DayOfWeek.Sunday);
DateTime lastDate = GetLastDateOfWeek(DateTime.Parse("05/09/2012").Date, DayOfWeek.Saturday);
public static DateTime GetFirstDateOfWeek(DateTime dayInWeek, DayOfWeek firstDay)
{
DateTime firstDayInWeek = dayInWeek.Date;
while (firstDayInWeek.DayOfWeek != firstDay)
firstDayInWeek = firstDayInWeek.AddDays(-1);
return firstDayInWeek;
}
public static DateTime GetLastDateOfWeek(DateTime dayInWeek, DayOfWeek firstDay)
{
DateTime lastDayInWeek = dayInWeek.Date;
while (lastDayInWeek.DayOfWeek != firstDay)
lastDayInWeek = lastDayInWeek.AddDays(1);
return lastDayInWeek;
}
I tried several, but I did not solve the issue with a week starting on a Monday, resulting in giving me the coming Monday on a Sunday. So I modified it a bit and got it working with this code:
int delta = DayOfWeek.Monday - DateTime.Now.DayOfWeek;
DateTime monday = DateTime.Now.AddDays(delta == 1 ? -6 : delta);
return monday;
The same for end of the week (in style of Compile This's answer):
public static DateTime EndOfWeek(this DateTime dt)
{
int diff = 7 - (int)dt.DayOfWeek;
diff = diff == 7 ? 0 : diff;
DateTime eow = dt.AddDays(diff).Date;
return new DateTime(eow.Year, eow.Month, eow.Day, 23, 59, 59, 999) { };
}
Thanks for the examples. I needed to always use the "CurrentCulture" first day of the week and for an array I needed to know the exact Daynumber.. so here are my first extensions:
public static class DateTimeExtensions
{
//http://stackoverflow.com/questions/38039/how-can-i-get-the-datetime-for-the-start-of-the-week
//http://stackoverflow.com/questions/1788508/calculate-date-with-monday-as-dayofweek1
public static DateTime StartOfWeek(this DateTime dt)
{
//difference in days
int diff = (int)dt.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; //sunday=always0, monday=always1, etc.
//As a result we need to have day 0,1,2,3,4,5,6
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-1 * diff).Date;
}
public static int DayNoOfWeek(this DateTime dt)
{
//difference in days
int diff = (int)dt.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; //sunday=always0, monday=always1, etc.
//As a result we need to have day 0,1,2,3,4,5,6
if (diff < 0)
{
diff += 7;
}
return diff + 1; //Make it 1..7
}
}
Here is a correct solution. The following code works regardless if the first day of the week is a Monday or a Sunday or something else.
public static class DateTimeExtension
{
public static DateTime GetFirstDayOfThisWeek(this DateTime d)
{
CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
var first = (int)ci.DateTimeFormat.FirstDayOfWeek;
var current = (int)d.DayOfWeek;
var result = first <= current ?
d.AddDays(-1 * (current - first)) :
d.AddDays(first - current - 7);
return result;
}
}
class Program
{
static void Main()
{
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine("Current culture set to en-US");
RunTests();
Console.WriteLine();
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("da-DK");
Console.WriteLine("Current culture set to da-DK");
RunTests();
Console.ReadLine();
}
static void RunTests()
{
Console.WriteLine("Today {1}: {0}", DateTime.Today.Date.GetFirstDayOfThisWeek(), DateTime.Today.Date.ToString("yyyy-MM-dd"));
Console.WriteLine("Saturday 2013-03-02: {0}", new DateTime(2013, 3, 2).GetFirstDayOfThisWeek());
Console.WriteLine("Sunday 2013-03-03: {0}", new DateTime(2013, 3, 3).GetFirstDayOfThisWeek());
Console.WriteLine("Monday 2013-03-04: {0}", new DateTime(2013, 3, 4).GetFirstDayOfThisWeek());
}
}
Modulo in C# works bad for -1 mod 7 (it should be 6, but C# returns -1)
so... a "one-liner" solution to this will look like this :)
private static DateTime GetFirstDayOfWeek(DateTime date)
{
return date.AddDays(
-(((int)date.DayOfWeek - 1) -
(int)Math.Floor((double)((int)date.DayOfWeek - 1) / 7) * 7));
}
I did it for Monday, but with similar logic for Sunday.
public static DateTime GetStartOfWeekDate()
{
// Get today's date
DateTime today = DateTime.Today;
// Get the value for today. DayOfWeek is an enum with 0 being Sunday, 1 Monday, etc
var todayDayOfWeek = (int)today.DayOfWeek;
var dateStartOfWeek = today;
// If today is not Monday, then get the date for Monday
if (todayDayOfWeek != 1)
{
// How many days to get back to Monday from today
var daysToStartOfWeek = (todayDayOfWeek - 1);
// Subtract from today's date the number of days to get to Monday
dateStartOfWeek = today.AddDays(-daysToStartOfWeek);
}
return dateStartOfWeek;
}
The following method should return the DateTime that you want. Pass in true for Sunday being the first day of the week, false for Monday:
private DateTime getStartOfWeek(bool useSunday)
{
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
if(!useSunday)
dayOfWeek--;
if(dayOfWeek < 0)
{// day of week is Sunday and we want to use Monday as the start of the week
// Sunday is now the seventh day of the week
dayOfWeek = 6;
}
return now.AddDays(-1 * (double)dayOfWeek);
}
You could use the excellent Umbrella library:
using nVentive.Umbrella.Extensions.Calendar;
DateTime beginning = DateTime.Now.BeginningOfWeek();
However, they do seem to have stored Monday as the first day of the week (see the property nVentive.Umbrella.Extensions.Calendar.DefaultDateTimeCalendarExtensions.WeekBeginsOn), so that previous localized solution is a bit better. Unfortunate.
Edit: looking closer at the question, it looks like Umbrella might actually work for that too:
// Or DateTime.Now.PreviousDay(DayOfWeek.Monday)
DateTime monday = DateTime.Now.PreviousMonday();
DateTime sunday = DateTime.Now.PreviousSunday();
Although it's worth noting that if you ask for the previous Monday on a Monday, it'll give you seven days back. But this is also true if you use BeginningOfWeek, which seems like a bug :(.
Following on from Compile This' answer, use the following method to obtain the date for any day of the week:
public static DateTime GetDayOfWeek(DateTime dateTime, DayOfWeek dayOfWeek)
{
var monday = dateTime.Date.AddDays((7 + (dateTime.DayOfWeek - DayOfWeek.Monday) % 7) * -1);
var diff = dayOfWeek - DayOfWeek.Monday;
if (diff == -1)
{
diff = 6;
}
return monday.AddDays(diff);
}
This will return both the beginning of the week and the end of the week dates:
private string[] GetWeekRange(DateTime dateToCheck)
{
string[] result = new string[2];
TimeSpan duration = new TimeSpan(0, 0, 0, 0); //One day
DateTime dateRangeBegin = dateToCheck;
DateTime dateRangeEnd = DateTime.Today.Add(duration);
dateRangeBegin = dateToCheck.AddDays(-(int)dateToCheck.DayOfWeek);
dateRangeEnd = dateToCheck.AddDays(6 - (int)dateToCheck.DayOfWeek);
result[0] = dateRangeBegin.Date.ToString();
result[1] = dateRangeEnd.Date.ToString();
return result;
}
I have posted the complete code for calculating the begin/end of week, month, quarter and year on my blog
ZamirsBlog
Calculating this way lets you choose which day of the week indicates the start of a new week (in the example I chose Monday).
Note that doing this calculation for a day that is a Monday will give the current Monday and not the previous one.
//Replace with whatever input date you want
DateTime inputDate = DateTime.Now;
//For this example, weeks start on Monday
int startOfWeek = (int)DayOfWeek.Monday;
//Calculate the number of days it has been since the start of the week
int daysSinceStartOfWeek = ((int)inputDate.DayOfWeek + 7 - startOfWeek) % 7;
DateTime previousStartOfWeek = inputDate.AddDays(-daysSinceStartOfWeek);
I work with a lot of schools, so correctly using Monday as the first day of the week is important here.
A lot of the most terse answers here don't work on Sunday -- we often end up returning the date of tomorrow on Sunday, which is not good for running a report on last week's activities.
Here's my solution, which returns last Monday on Sunday, and today on Monday.
// Adding 7 so remainder is always positive; Otherwise % returns -1 on Sunday.
var daysToSubtract = (7 + (int)today.DayOfWeek - (int)DayOfWeek.Monday) % 7;
var monday = today
.AddDays(-daysToSubtract)
.Date;
Remember to use a method parameter for "today" so it's unit testable!!
Here is a combination of a few of the answers. It uses an extension method that allows the culture to be passed in. If one is not passed in, the current culture is used. This will give it maximum flexibility and reuse.
/// <summary>
/// Gets the date of the first day of the week for the date.
/// </summary>
/// <param name="date">The date to be used</param>
/// <param name="cultureInfo">If none is provided, the current culture is used</param>
/// <returns>The date of the beggining of the week based on the culture specifed</returns>
public static DateTime StartOfWeek(this DateTime date, CultureInfo cultureInfo=null) =>
date.AddDays(-1 * (7 + (date.DayOfWeek - (cultureInfo ?? CultureInfo.CurrentCulture).DateTimeFormat.FirstDayOfWeek)) % 7).Date;
Example Usage:
public static void TestFirstDayOfWeekExtension() {
DateTime date = DateTime.Now;
foreach(System.Globalization.CultureInfo culture in CultureInfo.GetCultures(CultureTypes.UserCustomCulture | CultureTypes.SpecificCultures)) {
Console.WriteLine($"{culture.EnglishName}: {date.ToShortDateString()} First Day of week: {date.StartOfWeek(culture).ToShortDateString()}");
}
}
If you want Saturday or Sunday or any day of week, but not exceeding the current week (Sat-Sun), I got you covered with this piece of code.
public static DateTime GetDateInCurrentWeek(this DateTime date, DayOfWeek day)
{
var temp = date;
var limit = (int)date.DayOfWeek;
var returnDate = DateTime.MinValue;
if (date.DayOfWeek == day)
return date;
for (int i = limit; i < 6; i++)
{
temp = temp.AddDays(1);
if (day == temp.DayOfWeek)
{
returnDate = temp;
break;
}
}
if (returnDate == DateTime.MinValue)
{
for (int i = limit; i > -1; i++)
{
date = date.AddDays(-1);
if (day == date.DayOfWeek)
{
returnDate = date;
break;
}
}
}
return returnDate;
}
We like one-liners: Get the difference between the current culture's first day of week and the current day, and then subtract the number of days from the current day:
var weekStartDate = DateTime.Now.AddDays(-((int)now.DayOfWeek - (int)DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek));