I need to return year and week of a given date. Sounds simple. But to be right 2012-01-01 have to return 2011-52, because week 1 in 2012 starts January 2th.
To find the week, I use:
GregorianCalendar calw = new GregorianCalendar(GregorianCalendarTypes.Localized);
return calw.GetWeekOfYear(DateTime.Parse("2012-01-01"), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday).ToString();
this return 52. (correct)
But how do I get the Year?
edit:
With the help from here: http://codebetter.com/petervanooijen/2005/09/26/iso-weeknumbers-of-a-date-a-c-implementation/
This seems to work:
private int weekYear(DateTime fromDate)
{
GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
int week = weekNumber(fromDate);
int month = cal.GetMonth(fromDate);
int year = cal.GetYear(fromDate);
//week starts after 31st december
if (week > 50 && month == 1)
year = year - 1;
//week starts before 1st January
if (week < 5 && month == 12)
year = year + 1;
return year;
}
private int weekNumber(DateTime fromDate)
{
// Get jan 1st of the year
DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
// Get dec 31st of the year
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
// ISO 8601 weeks start with Monday
// The first week of a year includes the first Thursday
// DayOfWeek returns 0 for sunday up to 6 for saterday
int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
int wk = nds / 7;
switch (wk)
{
case 0:
// Return weeknumber of dec 31st of the previous year
return weekNumber(startOfYear.AddDays(-1));
case 53:
// If dec 31st falls before thursday it is week 01 of next year
if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
return 1;
else
return wk;
default: return wk;
}
}
Noda Time handles this for you very easily:
Noda Time v1.x
using System;
using NodaTime;
public class Test
{
static void Main()
{
LocalDate date = new LocalDate(2012, 1, 1);
Console.WriteLine($"WeekYear: {date.WeekYear}"); // 2011
Console.WriteLine($"WeekOfWeekYear: {date.WeekOfWeekYear}"); // 52
}
}
Noda Time v2.x
using System;
using NodaTime;
using NodaTime.Calendars;
public class Test
{
static void Main()
{
LocalDate date = new LocalDate(2012, 1, 1);
IWeekYearRule rule = WeekYearRules.Iso;
Console.WriteLine($"WeekYear: {rule.GetWeekYear(date)}"); // 2011
Console.WriteLine($"WeekOfWeekYear: {rule.GetWeekOfWeekYear(date)}"); // 52
}
}
That's using the ISO calendar system where the week year starts in the first week with at least 4 days in that year. (Like CalendarWeekRule.FirstFourDayWeek.) If you want a different calendar system, specify it in the LocalDate constructor. Week year rules are handled slightly differently between 1.x and 2.x.
EDIT: Note that this gives the right value for both this situation (where the week-year is less than the calendar year) and the situation at the other end of the year, where the week-year can be more than the calendar year. For example, December 31st 2012 is in week 1 of week-year 2013.
That's the beauty of having a library do this for you: its job is to understand this sort of thing. Your code shouldn't have to worry about it. You should just be able to ask for what you want.
You can get the weeknumber according to the CalendarWeekRule in this way:
var d = new DateTime(2012, 01, 01);
System.Globalization.CultureInfo cul = System.Globalization.CultureInfo.CurrentCulture;
var firstDayWeek = cul.Calendar.GetWeekOfYear(
d,
System.Globalization.CalendarWeekRule.FirstDay,
DayOfWeek.Monday);
int weekNum = cul.Calendar.GetWeekOfYear(
d,
System.Globalization.CalendarWeekRule.FirstFourDayWeek,
DayOfWeek.Monday);
int year = weekNum >= 52 && d.Month == 1 ? d.Year - 1 : d.Year;
You probably want to compare CalendarWeekRule.FirstDay with CalendarWeekRule.FirstFourDayWeek. On this way you get the weeknumber and the year (DateTime.Year-1 if they differ).
CultureInfo.Calendar Property
Calendar.GetWeekOfYear Method
CalendarWeekRule Enumeration
That is just an edge case which you will have to add special code for. Get the year from the date string and then if the week = 52 and the month = 1 then subtract one from the year.
I have solving similar problem where the result should be in "YYYYWW" format. I wanted avoid hardcoded dates and using 3rd party libraries.
My test case was date 1.1.2017 which should return week 201652 (Iso YearWeek)
To get week number I have used thread: Get the correct week number of a given date which returns week number without the year.
Finally the correct year I got from Monday(first day of iso week) of required date:
// returns only week number
// from [Get the correct week number of a given date] thread
public static int GetIso8601WeekOfYear(DateTime time)
{
// Seriously cheat. If its Monday, Tuesday or Wednesday, then it'll
// be the same week# as whatever Thursday, Friday or Saturday are,
// and we always get those right
DayOfWeek day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(time);
if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
{
time = time.AddDays(3);
}
// Return the week of our adjusted day
var week = CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return week;
}
// returns int YearWeek in format "YYYYWW"
public static int GetIso8601YearWeekOfYear(DateTime time)
{
var delta = (-((time.DayOfWeek - CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 7) % 7));
var firstDayofWeek = time.AddDays(delta); // takeMonday
var week = GetIso8601WeekOfYear(time);
var yearWeek = (firstDayofWeek.Year * 100) + week;
return yearWeek;
}
In my approach I'm taking advantage of the fact, that GetWeekOfYear() displays a correct ISO-8601 week number for days with the same year as Thursday of the same week. So I look for Thursday that belongs to the same week as a given date, and then call GetWeekOfYear() on it.
I can't do that trick to get a correct year, as there's no iso8601-compliant method for this, so I make a year adjustment if Thursday belongs to a different year than a given date.
The solution is basically a three-liner:
using System.Globalization;
namespace TESTS
{
class Program
{
static void Main(string[] args)
{
//sample dates with correct week numbers in comments:
string[] dats = new string[] {
"2011-12-31","2012-01-01" //1152
,"2012-12-31","2013-01-01" //1301
,"2013-12-31","2014-01-01" //1401
,"2014-12-31","2015-01-01" //1501
,"2015-12-31", "2016-01-01" //1553
};
foreach (string str in dats)
{
Console.WriteLine("{0} {1}", str, GetCalendarWeek(DateTime.Parse(str)));
}
Console.ReadKey();
}
public static int GetCalendarWeek(DateTime dat)
{
CultureInfo cult = System.Globalization.CultureInfo.CurrentCulture;
// thursday of the same week as dat.
// value__ for Sunday is 0, so I need (true, not division remainder %) mod function to have values 0..6 for monday..sunday
// If you don't like casting Days to int, use some other method of getting that thursday
DateTime thursday = dat.AddDays(mod((int)DayOfWeek.Thursday-1,7) - mod((int)dat.DayOfWeek-1,7));
//week number for thursday:
int wk = cult.Calendar.GetWeekOfYear(thursday, cult.DateTimeFormat.CalendarWeekRule, cult.DateTimeFormat.FirstDayOfWeek);
// year adjustment - if thursday is in different year than dat, there'll be -1 or +1:
int yr = dat.AddYears(thursday.Year-dat.Year).Year;
// return in yyww format:
return 100 * (yr%100) + wk;
}
// true mod - helper function (-1%7=-1, I need -1 mod 7 = 6):
public static int mod(int x, int m)
{
return (x % m + m) % m;
}
}
Related
I want my new year to start at 14 March. Given any DateTime I want to get the day of year? How can I accomplish this with DateTime?
March 14 is the 73rd day of the year (74th in leap years) in the Gregorian calendar. 292 days remain until the end of the year. Is there a way I can define the new year of a year with DateTime?
int DayOfYear(DateTime date, int yearStartMonth, int yearStartDay)
{
var yearStart = new DateTime(d.Year, yearStartMonth, yearStartDay);
if(yearStart > d)
yearStart = yearStart.AddYears(-1);
return (d - yearStart).Days + 1;
}
try to use:
public static int DayOfYear(DateTime date)
{
var startDate= new DateTime(year:date.Year,month:3,day:14); //14 March
var diffDateDays=(date- startDate).Days;
if (diffDateDays > 0) return diffDateDays;
startDate= new DateTime(year:date.Year-1,month:3,day:14); //14 March of previous year
return (date- startDate).Days;
}
I am trying to shift a date by a number of given months, but also to keep the same day (for example, if the day of the date is Monday, and after shifting with x months the day is Thursday, I want also to subtract 3 days from the new obtained date. This algorithm should add/subtract days depending on the new obtained date, basically providing the closest date that represents the same day of week). As an example, if I have the start date 10.08.2016(Wednesday), and I add 3 months, I will get 10.11.2016(Thursday), so the closest Wednesday to that day is 09.11.2016.
What I managed to make till now looks something like this:
int startDayOfWeek = ((int)startDay.DayOfWeek) == 0 ? 7 : (int)startDay.DayOfWeek;
int newStartDayOfWeek = ((int)startDay.AddMonths(period).DayOfWeek) == 0 ? 7 : (int)startDay.AddMonths(period).DayOfWeek;
int shiftingDays = startDayOfWeek - newStartDayOfWeek;
if (shiftingDays > 3)
shiftingDays -= 7;
where startDay is the start date, and period is the number of months I want to shift to.
But this still fails some times, so any tips would be greately appreciated.
An example when this code fails would be:
startDate = 01.08.2016 (Monday) and period would be 5
After adding 5 months, I get 01.01.2017, which is Sunday, and the closest Monday would be on 02.01.2017, but I get -6 days.
Use this code. The idea is to divide the days by 7, round it, and multiply by 7.
DateTime endDate = startDay.AddMonths((int)period);
endDate = startDay.AddDays((int)Math.Round((double)(endDate - startDay ).Days / 7)*7);
Is that what you are looking for ?
static void Main( string[] args )
{
//DateTime startDay = DateTime.Now;
DateTime startDay = new DateTime( 2016, 8, 1 );
//DateTime startDay = new DateTime( 2016, 8, 10 );
DateTime newDay = startDay.AddMonths( 5 );
int startDayOfWeek = (int)startDay.DayOfWeek;
int newDayOfWeek = (int)newDay.DayOfWeek;
int shift1 = (7 + startDayOfWeek - newDayOfWeek) % 7;
int shift2 = (7 + newDayOfWeek - startDayOfWeek) % 7;
DateTime test = newDay + ((shift1 > shift2) ? - TimeSpan.FromDays( shift2 ) : TimeSpan.FromDays( shift1 ));
}
Can anyone please help me, how do I calculate fortnightly (14 days) logic using C#?, for a example 14 days start following sequence order on February
Monday start date 8 Feb (next 22 Feb, 7 March, 21 March etc..)
Thursday start date 11 February (next 25 Feb, 10 March, 24 March etc..)
Friday start date 12 February (next 26 Feb, 11 March, 25 March etc..)
My logic is not working for the 14 days day display, because 15 February will come 14 days add, it’ll display “First14days” date 29 February 2016, it is a wrong.
This is C# logic
Day.Days value are Monday, Thursday, Friday etc..
foreach (var Day in day)
{
Example Day.Days = Monday
Int 14days = (((int)Enum.Parse(typeof(DayOfWeek), Day.Days) - (int)today.DayOfWeek + 14) % 7);
DateTime First14days = today.AddDays(14days);
}
My output should be
Simply add TimeSpan.FromDays(14) to any date to get a fortnight further on
DateTime startDate = DateTime.Now;
TimeSpan fortnight = TimeSpan.FromDays(14);
for (int i = 0; i < 6; i++)
{
startDate += fortnight;
Console.WriteLine($"Date for fortnight {i}: {startDate:D}");
}
If I understand correct your question this code will be working for you.
DateTime time = DateTime.Now;
DateTime anotherTime = DateTime.Now;
var allTimes = new HashSet<DateTime>();
for (int i = 0; i < 6; i++)
{
anotherTime = time.AddDays(14);
time = anotherTime;
Console.WriteLine(anotherTime.ToLongDateString());
allTimes.Add(time);
}
// or with your example is possible to like this code.
foreach (var Day in day)
{
anotherTime = Day.AddDays(14);
time = anotherTime;
Console.WriteLine(anotherTime.ToLongDateString());
allTimes.Add(time);
}
First create two DataTime objects. then foreach few times, and in for loop statement set anotherTime = time.AddDays(14) after that set time = anotherTime.
//Output:
//Saturday, February 27, 2016
//Saturday, March 12, 2016
//Saturday, March 26, 2016
//Saturday, April 09, 2016
//Saturday, April 23, 2016
//Saturday, May 07, 2016
EDIT:
I create and HashSet where you can save all you DateTime who you make it.
So here's you all-in-one solution:
// determine the date of next given weekday
DateTime date = GetNextWeekday(DateTime.Today, DayOfWeek.Tuesday);
// create a list and add the start date (if you want)
List<DateTime> fortnights = new List<DateTime>() { date };
// add as many "fortnights" as you like (e.g. 5)
for (int i = 0; i < 5; i++)
{
date = date.Add(TimeSpan.FromDays(14));
fortnights.Add(date);
}
// use your list (here: just for printing the list in a console app)
foreach (DateTime d in fortnights)
{
Console.WriteLine(d.ToLongDateString());
}
Method to get the next weekday, from:
https://stackoverflow.com/a/6346190/2019384
public static DateTime GetNextWeekday(DateTime start, DayOfWeek day)
{
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysToAdd = ((int) day - (int) start.DayOfWeek + 7) % 7;
return start.AddDays(daysToAdd);
}
I have a code 2014P07W4 which means:
2014 = year
P07 = 7th month of the year
W4 = 4th week of the month.
I would like to work out the date of the First day of the 4th week in July 2014. In this example I would expect to see a date of 21/7/2014.
July 2014 weeks
Week 1 - 1st to 6th
Week 2 - 7th to 13th
Week 3 - 14th to 20th
Week 4 - 21st to 27th
Week 5 - 28th to 31st
From the code I know the week no = 4 then I want to be able to calculate the date 21/7/2014. I am assuming the first day of the week is a Monday
I am asking how to read that code and get the first day of the week specified
Hope this is clearer it has been a long day
You need to parse the code and extract the year, month, and weekNo an numbers.
Then, you can use this method to get the start day of the week:
int WeekStartDay(int year, int month, int weekNo)
{
DateTime monthStart = new DateTime(year, month, 1);
int monthStart_DayOfWeek = ((int)monthStart.DayOfWeek + 6) % 7;
int weekStart_DayOfMonth = 1;
if (1 < weekNo) {
weekStart_DayOfMonth += 7 - monthStart_DayOfWeek;
}
if (2 < weekNo) {
weekStart_DayOfMonth += 7 * (weekNo - 2);
}
return weekStart_DayOfMonth;
}
Take first day of month (2014/07/01), find next Monday (first day of 2nd week), add 14 days (first day of 4th week).
DateTime date = new DateTime(2014, 7, 1);
int daysToFirstDayOf2ndWeek = date.DayOfWeek == DayOfWeek.Monday
? 7
: ((int)DayOfWeek.Monday - (int)date.DayOfWeek + 7) % 7;
DateTime firstDayOf2ndWeek = date.AddDays(daysToFirstDayOf2ndWeek);
DateTime firstDayOf4thWeek = firstDayOf2ndWeek.AddDays(14);
may be this will works
string code = "2014P07W4";
int yr = int.Parse(code.Substring(0, 4));
int mnth = int.Parse(code.Substring(5, 2));
int week = int.Parse(code.Substring(8));
DateTime dt = new DateTime(yr, mnth, 1);
if (dt.DayOfWeek == DayOfWeek.Monday)
{
DateTime newdate = dt.AddDays((week - 1) * 7);
}
else
{
DateTime newdate = dt.AddDays((8 - (int)dt.DayOfWeek) % 7 + ((week - 2) * 7));
}
Given a date range, I need to know how many Mondays (or Tuesdays, Wednesdays, etc) are in that range.
I am currently working in C#.
Try this:
static int CountDays(DayOfWeek day, DateTime start, DateTime end)
{
TimeSpan ts = end - start; // Total duration
int count = (int)Math.Floor(ts.TotalDays / 7); // Number of whole weeks
int remainder = (int)(ts.TotalDays % 7); // Number of remaining days
int sinceLastDay = (int)(end.DayOfWeek - day); // Number of days since last [day]
if (sinceLastDay < 0) sinceLastDay += 7; // Adjust for negative days since last [day]
// If the days in excess of an even week are greater than or equal to the number days since the last [day], then count this one, too.
if (remainder >= sinceLastDay) count++;
return count;
}
Since you're using C#, if you're using C#3.0, you can use LINQ.
Assuming you have an Array/List/IQueryable etc that contains your dates as DateTime types:
DateTime[] dates = { new DateTime(2008,10,6), new DateTime(2008,10,7)}; //etc....
var mondays = dates.Where(d => d.DayOfWeek == DayOfWeek.Monday); // = {10/6/2008}
Added:
Not sure if you meant grouping them and counting them, but here's how to do that in LINQ as well:
var datesgrouped = from d in dates
group d by d.DayOfWeek into grouped
select new { WeekDay = grouped.Key, Days = grouped };
foreach (var g in datesgrouped)
{
Console.Write (String.Format("{0} : {1}", g.WeekDay,g.Days.Count());
}
It's fun to look at different algorithms for calculating day of week, and #Gabe Hollombe's pointing to WP on the subject was a great idea (and I remember implementing Zeller's Congruence in COBOL about twenty years ago), but it was rather along the line of handing someone a blueprint of a clock when all they asked what time it was.
In C#:
private int CountMondays(DateTime startDate, DateTime endDate)
{
int mondayCount = 0;
for (DateTime dt = startDate; dt < endDate; dt = dt.AddDays(1.0))
{
if (dt.DayOfWeek == DayOfWeek.Monday)
{
mondayCount++;
}
}
return mondayCount;
}
This of course does not evaluate the end date for "Mondayness", so if this was desired, make the for loop evaluate
dt < endDate.AddDays(1.0)
Here's some pseudocode:
DifferenceInDays(Start, End) / 7 // Integer division discarding remainder
+ 1 if DayOfWeek(Start) <= DayImLookingFor
+ 1 if DayOfWeek(End) >= DayImLookingFor
- 1
Where DifferenceInDays returns End - Start in days, and DayOfWeek returns the day of the week as an integer. It doesn't really matter what mapping DayOfWeek uses, as long as it is increasing and matches up with DayImLookingFor.
Note that this algorithm assumes the date range is inclusive. If End should not be part of the range, you'll have to adjust the algorithm slightly.
Translating to C# is left as an exercise for the reader.
Any particular language and therefore date format?
If dates are represented as a count of days, then the difference between two values plus one (day), and divide by 7, is most of the answer. If both end dates are the day in question, add one.
Edited: corrected 'modulo 7' to 'divide by 7' - thanks. And that is integer division.
You could try this, if you want to get specific week days between two dates
public List<DateTime> GetSelectedDaysInPeriod(DateTime startDate, DateTime endDate, List<DayOfWeek> daysToCheck)
{
var selectedDates = new List<DateTime>();
if (startDate >= endDate)
return selectedDates; //No days to return
if (daysToCheck == null || daysToCheck.Count == 0)
return selectedDates; //No days to select
try
{
//Get the total number of days between the two dates
var totalDays = (int)endDate.Subtract(startDate).TotalDays;
//So.. we're creating a list of all dates between the two dates:
var allDatesQry = from d in Enumerable.Range(1, totalDays)
select new DateTime(
startDate.AddDays(d).Year,
startDate.AddDays(d).Month,
startDate.AddDays(d).Day);
//And extracting those weekdays we explicitly wanted to return
var selectedDatesQry = from d in allDatesQry
where daysToCheck.Contains(d.DayOfWeek)
select d;
//Copying the IEnumerable to a List
selectedDates = selectedDatesQry.ToList();
}
catch (Exception ex)
{
//Log error
//...
//And re-throw
throw;
}
return selectedDates;
}
Add the smallest possible number to make the first day a Monday. Subtract the smallest possible number to make the last day a Monday. Calculate the difference in days and divide by 7.
Convert the dates to Julian Day Number, then do a little bit of math. Since Mondays are zero mod 7, you could do the calculation like this:
JD1=JulianDayOf(the_first_date)
JD2=JulianDayOf(the_second_date)
Round JD1 up to nearest multiple of 7
Round JD2 up to nearest multiple of 7
d = JD2-JD1
nMondays = (JD2-JD1+7)/7 # integer divide
I have had the same need today. I started with the cjm function since I don't understand the JonB function and since the Cyberherbalist function is not linear.
I had have to correct
DifferenceInDays(Start, End) / 7 // Integer division discarding remainder
+ 1 if DayOfWeek(Start) <= DayImLookingFor
+ 1 if DayOfWeek(End) >= DayImLookingFor
- 1
to
DifferenceInDays(Start, End) / 7 // Integer division discarding remainder
+ 1 if DayImLookingFor is between Start.Day and End.Day
With the between function that return true if, starting from the start day, we meet first the dayImLookingFor before the endDay.
I have done the between function by computing the number of day from startDay to the other two days:
private int CountDays(DateTime start, DateTime end, DayOfWeek selectedDay)
{
if (start.Date > end.Date)
{
return 0;
}
int totalDays = (int)end.Date.Subtract(start.Date).TotalDays;
DayOfWeek startDay = start.DayOfWeek;
DayOfWeek endDay = end.DayOfWeek;
///look if endDay appears before or after the selectedDay when we start from startDay.
int startToEnd = (int)endDay - (int)startDay;
if (startToEnd < 0)
{
startToEnd += 7;
}
int startToSelected = (int)selectedDay - (int)startDay;
if (startToSelected < 0)
{
startToSelected += 7;
}
bool isSelectedBetweenStartAndEnd = startToEnd >= startToSelected;
if (isSelectedBetweenStartAndEnd)
{
return totalDays / 7 + 1;
}
else
{
return totalDays / 7;
}
}
This will return a collection of integers showing how many times each day of the week occurs within a date range
int[] CountDays(DateTime firstDate, DateTime lastDate)
{
var totalDays = lastDate.Date.Subtract(firstDate.Date).TotalDays + 1;
var weeks = (int)Math.Floor(totalDays / 7);
var result = Enumerable.Repeat<int>(weeks, 7).ToArray();
if (totalDays % 7 != 0)
{
int firstDayOfWeek = (int)firstDate.DayOfWeek;
int lastDayOfWeek = (int)lastDate.DayOfWeek;
if (lastDayOfWeek < firstDayOfWeek)
lastDayOfWeek += 7;
for (int dayOfWeek = firstDayOfWeek; dayOfWeek <= lastDayOfWeek; dayOfWeek++)
result[dayOfWeek % 7]++;
}
return result;
}
Or a slight variation which lets you do FirstDate.TotalDaysOfWeeks(SecondDate) and returns a Dictionary
public static Dictionary<DayOfWeek, int> TotalDaysOfWeeks(this DateTime firstDate, DateTime lastDate)
{
var totalDays = lastDate.Date.Subtract(firstDate.Date).TotalDays + 1;
var weeks = (int)Math.Floor(totalDays / 7);
var resultArray = Enumerable.Repeat<int>(weeks, 7).ToArray();
if (totalDays % 7 != 0)
{
int firstDayOfWeek = (int)firstDate.DayOfWeek;
int lastDayOfWeek = (int)lastDate.DayOfWeek;
if (lastDayOfWeek < firstDayOfWeek)
lastDayOfWeek += 7;
for (int dayOfWeek = firstDayOfWeek; dayOfWeek <= lastDayOfWeek; dayOfWeek++)
resultArray[dayOfWeek % 7]++;
}
var result = new Dictionary<DayOfWeek, int>();
for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++)
result[(DayOfWeek)dayOfWeek] = resultArray[dayOfWeek];
return result;
}
A bit Modified Code is here works and Tested by me
private int CountDays(DayOfWeek day, DateTime startDate, DateTime endDate)
{
int dayCount = 0;
for (DateTime dt = startDate; dt < endDate; dt = dt.AddDays(1.0))
{
if (dt.DayOfWeek == day)
{
dayCount++;
}
}
return dayCount;
}
Example:
int Days = CountDays(DayOfWeek.Friday, Convert.ToDateTime("2019-07-04"),
Convert.ToDateTime("2019-07-27")).ToString();
I had a similar problem for a report. I needed the number of workdays between two dates.
I could have cycled through the dates and counted but my discrete math training wouldn't let me. Here is a function I wrote in VBA to get the number of workdays between two dates. I'm sure .net has a similar WeekDay function.
1
2 ' WorkDays
3 ' returns the number of working days between two dates
4 Public Function WorkDays(ByVal dtBegin As Date, ByVal dtEnd As Date) As Long
5
6 Dim dtFirstSunday As Date
7 Dim dtLastSaturday As Date
8 Dim lngWorkDays As Long
9
10 ' get first sunday in range
11 dtFirstSunday = dtBegin + ((8 - Weekday(dtBegin)) Mod 7)
12
13 ' get last saturday in range
14 dtLastSaturday = dtEnd - (Weekday(dtEnd) Mod 7)
15
16 ' get work days between first sunday and last saturday
17 lngWorkDays = (((dtLastSaturday - dtFirstSunday) + 1) / 7) * 5
18
19 ' if first sunday is not begin date
20 If dtFirstSunday <> dtBegin Then
21
22 ' assume first sunday is after begin date
23 ' add workdays from begin date to first sunday
24 lngWorkDays = lngWorkDays + (7 - Weekday(dtBegin))
25
26 End If
27
28 ' if last saturday is not end date
29 If dtLastSaturday <> dtEnd Then
30
31 ' assume last saturday is before end date
32 ' add workdays from last saturday to end date
33 lngWorkDays = lngWorkDays + (Weekday(dtEnd) - 1)
34
35 End If
36
37 ' return working days
38 WorkDays = lngWorkDays
39
40 End Function
private System.Int32 CountDaysOfWeek(System.DayOfWeek dayOfWeek, System.DateTime date1, System.DateTime date2)
{
System.DateTime EndDate;
System.DateTime StartDate;
if (date1 > date2)
{
StartDate = date2;
EndDate = date1;
}
else
{
StartDate = date1;
EndDate = date2;
}
while (StartDate.DayOfWeek != dayOfWeek)
StartDate = StartDate.AddDays(1);
return EndDate.Subtract(StartDate).Days / 7 + 1;
}
Four years later, I thought I'd run a test:
[TestMethod]
public void ShouldFindFridaysInTimeSpan()
{
//reference: http://stackoverflow.com/questions/248273/count-number-of-mondays-in-a-given-date-range
var spanOfSixtyDays = new TimeSpan(60, 0, 0, 0);
var setOfDates = new List<DateTime>(spanOfSixtyDays.Days);
var now = DateTime.Now;
for(int i = 0; i < spanOfSixtyDays.Days; i++)
{
setOfDates.Add(now.AddDays(i));
}
Assert.IsTrue(setOfDates.Count == 60,
"The expected number of days is not here.");
var fridays = setOfDates.Where(i => i.DayOfWeek == DayOfWeek.Friday);
Assert.IsTrue(fridays.Count() > 0,
"The expected Friday days are not here.");
Assert.IsTrue(fridays.First() == setOfDates.First(i => i.DayOfWeek == DayOfWeek.Friday),
"The expected first Friday day is not here.");
Assert.IsTrue(fridays.Last() == setOfDates.Last(i => i.DayOfWeek == DayOfWeek.Friday),
"The expected last Friday day is not here.");
}
My use of TimeSpan is a bit of overkill---actually I wanted to query TimeSpan directly.