ASP.NET Getting working weeks for every month - c#

I have a form that accept input of 'Month' and 'Year', I am writing here to ask any idea on how will I get all 'working weeks'?
I mean 'Working weeks' as Monday - Friday
So basically I need week1 to week4 or if available including week5.
For example if I input January 2013:
week1 = January 1 to January 4
week2 = January 7 to January 11
week3 = January 14 to January 18
week4 = January 21 to January 25
week5 = January 28 to January 31
How can I achieve that? Thanks for any help! Any suggestions or ideas will be greatly appreciated. Thanks mates! :)

You could use this Linq query:
int month = 1;
int year = 2013;
var cal = System.Globalization.CultureInfo.CurrentCulture.Calendar;
IEnumerable<int> daysInMonth = Enumerable.Range(1, cal.GetDaysInMonth(year, month));
List<Tuple<int, DateTime, DateTime>> listOfWorkWeeks = daysInMonth
.Select(day => new DateTime(year, month, day))
.GroupBy(d => cal.GetWeekOfYear(d, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday))
.Select(g => Tuple.Create(g.Key, g.First(), g.Last(d => d.DayOfWeek != DayOfWeek.Saturday && d.DayOfWeek != DayOfWeek.Sunday)))
.ToList();
// Item1 = week in year, Item2 = first day, Item3 = last working day
int weekNum = 1;
foreach (var weekGroup in listOfWorkWeeks)
{
Console.WriteLine("Week{0} = {1} {2} to {1} {3}"
, weekNum++
, System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(month)
, weekGroup.Item2.Day
, weekGroup.Item3.Day);
}
output for January:
Week1 = January 1 to January 4
Week2 = January 7 to January 11
Week3 = January 14 to January 18
Week4 = January 21 to January 25
Week5 = January 28 to January 31
and for February:
Week1 = February 1 to February 1
Week2 = February 4 to February 8
Week3 = February 11 to February 15
Week4 = February 18 to February 22
Week5 = February 25 to February 28

Find the first Monday of the month and year.
int year = 2013;
int month = 1;
DateTime testDate = new DateTime(year,month,1);
while ( testDate.DayOfWeek != DayOfWeek.Monday )
{
testDate = testDate.AddDays(1);
}
Then iterate over each week until you reach a year that isn't 2013.
// Should have first monday now.
// Loop until the month changes
while ( testDate.Month == month)
{
var monday = testDate;
var friday = testDate.AddDays(4);
// You now have both dates. Do whatever you need to.
// here.
// Increment test date by a week
testDate = testDate.AddDays(7)
}

In pseudo code:
Start from the first day of the month
While (day != Monday) take next date (+1 day)
See this SO post (Jon Skeet answer!) for checking if a day is a Monday.
Add 4 days to find the end of the working week
If it's in the same month, than you have a working week for your answer.
Add 7 days to find the next Monday
If the new Monday is still within the same month: repeat 3. and 4.
EDIT The above finds all complete working weeks.
To find the other weeks as well:
If the first day of the month is already a working day, find the next Friday. -> 1st working week
If the last friday is in the next month, finish the last working week at the last day of the month. -> last working week

Related

C# Time Period in weeks between 2 dates

I have a web application where the user will input 2 dates. A StartDate and an EndDate. Now I want to write it so that when StartDate and EndDate is selected to determine how many weeks there are and then to display the dates of those weeks for example if the user selects 01-11-2018 as the StartDate and 31-12-2018 as the EndDate then I want to display the following and keep in mind the Weeks are just for reference as to how it is going to look:
Week 98 : 01 November 2018 - 03 November 2018
Week 99 : 04 November 2018 - 10 November 2018
Week 100 : 11 November 2018 - 17 November 2018
I already have the amount of weeks by using this previous post.
Now I just want to be able to to display each individual weeks Start and End date in all the weeks. I tried creating a list with the weeks and then using a Foreach to check the weeks added but this is not quite right. I am just searching for the most efficient way of accomplishing this goal.
Links also checked with similar problems are :
Link1
I have made this snippet... not sure if everything is up to spec:
var startDate = new DateTime(2018, 11, 1);
var endDate = new DateTime(2018, 12, 31);
int diff = (7 + (startDate.DayOfWeek - DayOfWeek.Monday)) % 7;
var weekStartDate = startDate.AddDays(-1 * diff).Date;
var i = 1;
var weekEndDate = DateTime.MinValue;
while(weekEndDate < endDate) {
weekEndDate = weekStartDate.AddDays(6);
var shownStartDate = weekStartDate < startDate ? startDate : weekStartDate;
var shownEndDate = weekEndDate > endDate ? endDate : weekEndDate;
Console.WriteLine($"Week {i++}: {shownStartDate:dd MMMM yyyy} - {shownEndDate:dd MMMM yyyy}");
weekStartDate = weekStartDate.AddDays(7);
}
This assumes your weeks are "counting", starting on the week the start date is in, and uses monday as the first day of week and sunday as the last one (the ranges you see are monday - sunday except for the first/last week, which would use the start/end date instead if it doesn't happen to be monday or sunday)
You can run it online here: https://dotnetfiddle.net/jJ4Ydu
If you also need to know which week of the year it is, then it depends if you want the .NET style or the ISO8601 style... the typical one is the latter, and you can use, for example, the method found on this answer, so it'd look something like: https://dotnetfiddle.net/oJscjF
Notice how Dec-31st-2018 (which is monday) is the week 1 of 2019 on ISO8601, but week 53 for .NET

Group by all full weeks between date period - LINQ

I know how to count number of weeks between two dates.
I have a date period (start date and end date).
Is it possible to get Tuple<DateTime, DateTime> or something where item_1 is a start day of week and item_2 is the end? I mean I finally want to see List<Tuple<DateTime, DateTime>>.
For example my period is from 13/09/16 till 5/10/16
As a result I want to see a list with two corteges:
19/09/16 - 25/09/16
26/09/16 - 2/10/16
I have wrote a regular cycle for this but want to have LINQ.
for (var day = start.Date; day.Date <= end.Date; day = day.AddDays(1))
{
if (day.DayOfWeek == DayOfWeek.Monday)
{
if (day.AddDays(6) < end.Date)
result.Add(Tuple.Create(day.Date, day.AddDays(6).Date));
}
}
Also it would be nice to include culture info if a week starting from Sunday like in USA.
It's very crude... but try something like this:
DateTime start = DateTime.Parse("13/09/16");
DateTime end = DateTime.Parse("5/10/16");
CultureInfo culture = Thread.CurrentThread.CurrentCulture;
Enumerable.Range(0, (end - start).Days)
.Where(x => start.AddDays(x).DayOfWeek == culture.DateTimeFormat.FirstDayOfWeek)
.Select(x => new Tuple<DateTime, DateTime>(start.AddDays(x), start.AddDays(x + 6)))
.Where(x => x.Item2 < end);
This will enumerate to:
| index | first | second |
-----------------------------
| 0 | 19/09/16| 25/09/16|
| 1 | 26/09/16| 2/10/16 |
Given a date you can determine the date when the week started by subtracting the first day of week from the day of week of the date. You then need to handle negative numbers in the case where the first day of week is Monday (1) and the day of week of the date is Sunday (0) as 0 - 1 = -1 and not 6. Here is a function that does that:
int GetDayOfWeekOffset(DateTime date, CultureInfo cultureInfo) {
return ((int) (date.DayOfWeek - cultureInfo.DateTimeFormat.FirstDayOfWeek) + 7)%7;
}
So if the first day of the week (determined by CultureInfo) is Monday then the function will return 0, 1, ..., 6 for days Monday, Tuesday, ..., Sunday. When the first day of the week is Sunday then it will return 0, 1, ..., 6 for days Sunday, Monday, ..., Saturday.
You can subtract the number of days returned by the function to get the date a week started given a date in that week:
var firstWeekStart = startDate.AddDays(-GetDayOfWeekOffset(startDate, cultureInfo));
var lastWeekStart = endDate.AddDays(-GetDayOfWeekOffset(endDate, cultureInfo));
These two dates can be used to generate the desired list:
var weekCount = (int) (lastWeekStart - firstWeekStart).TotalDays/7 + 1;
var weeks = Enumerable
.Range(0, weekCount)
.Select(week => firstWeekStart.AddDays(7*week))
.Where(weekStart => startDate <= weekStart && weekStart.AddDays(6) <= endDate)
.Select(weekStart => Tuple.Create(weekStart, weekStart.AddDays(6)))
.ToList();
Notice the Where clause that ensures that only weeks inside the range of dates determined by startDate and endDate are included.
This approach is more "efficient" compared to the answer provided by Scott as the implicit foreach loop enumerates weeks and not days (so up to 7 times fever iterations). However, "efficiency" probably doesn't really matter as long as you don't have to create a very long list of weeks.

How to get date after N months with same day and same week of a given date

I am looking for some logic to get the date after N months having same day(Ex:Wednesday) and same week(ex: first or second...) of a given date.
ex: 12-06-2013(Wednesday & 3rd week of June) is the given date.
here I am adding 3 months to the given date.
the result should be is 14-Aug-2013(Wednesday & 3rd week of Aug).
please let me know if you need more clarification.
Thanks In advance.
Okay, so I'd personally use my Noda Time library to do this. It's entirely possible to do this with DateTime, but I'd personally find it harder. I'd also encourage you to use Noda Time in general, of course, as a better date/time API. So I'd have something like:
static LocalDate AddMonthsPreserveWeekDayAndWeek(LocalDate start, int months)
{
// This isn't the week of month in the "normal" sense; it's the nth
// occurrence of this weekday.
int week = ((start.DayOfMonth - 1) / 7) + 1;
// This will usually give the same day of month, but truncating where
// necessary
LocalDate monthsAdded = start.AddMonths(months);
LocalDate endOfPreviousMonth = monthsAdded.AddDays(-monthsAdded.Day);
// Get to the first occurrence of the right day-of-week
LocalDate firstRightDay = endOfPreviousMonth.Next(start.IsoDayOfWeek);
// Usually this will be right - but it might overflow to the next month,
// in which case we can just rewind by a week.
LocalDate candidate = firstRightDay.PlusWeeks(week - 1);
return candidate.Month == firstRightDay.Month ? candidate
: candidate.PlusWeeks(-1);
}
This is completely untested though - you should absolutely have a bunch of unit tests (ideally which you write before even including this code) which test all kinds of edge cases you're interested in.
Using standard MDSN year = 2013 month = 06 date = 12
1) Get day of the week from the specific date (Sunday is 0)
DateTime dateValue = new DateTime(year, month, date);
Console.WriteLine((int) dateValue.DayOfWeek); // Displays 3 implying it is Wed
2) Get the week of the month from the specific date
DayofWeek = 3 (from previous calculation)
Day = 12
EndOfWeek = Day + (6 - DayOfWeek) = 12 + 4 = 16
NoWeek = 0
while (EndOfWeek > 0)
{
EndOfWeek -= 7;
NoWeek++;
}
=> NoWeek = 3
3) Get first date after N month
DateTime newDate = new DateTime(year, month, 1)
newDate.AddMonths(N); // Let it be 2 => August 1, 2013
4) Get the day of the week for the new date
newDay = newDate.DayOfWeek // Return 4 implying Thursday
5) Get the last day after NoWeek
newDate.AddDays(6-newDay) => newDate.AddDays (6-4) => August 3,2013
NoWeek--;
while (NoWeek > 1)
{
newDate.AddDays(7);
NoWeek--;
}
=> newDate will be Augus 10,2013
6) Calculte required date
newDate.AddDays(DayofWeek) =>newDate will be August 14,2013

Quartz.Net - Every 3 months

I'm trying to call something every 3 months (quarterly) in Quartz.NET (using both stable and latest version 2 which is beta with same results).
I create cron trigger with 0 30 8 3 */3 ? * to be called every 3 months at 8.30am on third of the month it occurs.
So technically since its 2 of September today I would expect it to trigger tomorrow. However it next run time shows as being next month. Why is that so?
Updated: As per answers I got I created following method - could be useful for someone:
public static string CalculateMonthsWithInterval(int startMonth, int interval)
{
var months = new List<string>();
var monthNames = new [] {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
var monthSelector = startMonth % interval;
for (var i = 0; i < 12; i++)
{
if (i % interval == monthSelector)
{
months.Add(monthNames[i]);
}
}
return string.Join(",", months.ToArray());
}
Ps: I didn't use indexes for months because for some reason it wasn't working well with my Quartz (v2 BETA). Also its easier to read in DB level.
Example call - Every 3 months based on startDate:
var cronMonths = CronUtils.CalculateMonthsWithInterval((startDate.Month - 1), 3);
Well I think that's because the scheduler will verify which month can be divided by 3, since all month in Quartz are based 0 (according to: http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06), the month that will be scheduled will be january, april, july and october.
0 mod 3 = 0 -> JAN
1 mod 3 = 1 -> FEB
...
8 mod 3 = 2 -> SEP
9 mod 3 = 0 -> OCT
The Quartz scheduler will analyse your cron expression and keep only those where their modulus 3 equals to 0.
If you want it to be 1 month before that (march, june, september and october) you will have to set it to:
0 30 8 3 MAR,JUN,SEP,DEC ? *
A good page to create cron expressions: http://www.cronmaker.com/
Cron format:
0 0 12 1 1/3 ? *
Executes every:
1. Saturday, April 1, 2017 12:00 PM
2. Saturday, July 1, 2017 12:00 PM
3. Sunday, October 1, 2017 12:00 PM
4. Monday, January 1, 2018 12:00 PM
5. Sunday, April 1, 2018 12:00 PM

Calculate DateTime Weeks into Rows

I am currently writing a small calendar in ASP.Net C#. Currently to produce the rows of the weeks I do the following for loop:
var iWeeks = 6;
for (int w = 0; w < iWeeks; w++) {
This works fine, however, some month will only have 5 weeks and in some rare cases, 4.
How can I calculate the number of rows that will be required for a particular month?
This is an example of what I am creating:
As you can see for the above month, there are only 5 rows required, however. Take the this month (August 2008) which started on a Saturday and ends on a Monday on the 6th Week/Row.
Image found on google
This is an example of what I am creating:
As you can see for the above month, there are only 5 rows required, however. Take the this month (August 2008) which started on a Saturday and ends on a Monday on the 6th Week/Row.
Image found on google
Here is the method that does it:
public int GetWeekRows(int year, int month)
{
DateTime firstDayOfMonth = new DateTime(year, month, 1);
DateTime lastDayOfMonth = new DateTime(year, month, 1).AddMonths(1).AddDays(-1);
System.Globalization.Calendar calendar = System.Threading.Thread.CurrentThread.CurrentCulture.Calendar;
int lastWeek = calendar.GetWeekOfYear(lastDayOfMonth, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
int firstWeek = calendar.GetWeekOfYear(firstDayOfMonth, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return lastWeek - firstWeek + 1;
}
You can customize the calendar week rule by modifying the System.Globalization.CalendarWeekRule.FirstFourDayWeek part. I hope the code is self explanatory.
Well, it depends on the culture you're using, but let's assume you can use Thread.CurrentThread.CurrentCulture, then the code to get the week of today would be:
Culture culture = Thread.CurrentThread.CurrentCulture;
Calendar cal = culture.Calendar;
Int32 week = cal.GetWeekOfYear(DateTime.Today,
culture.DateTimeFormat.CalendarWeekRule,
culture.DateTimeFormat.FirstDayOfWeek);
How about checking which week the first and last days will be in?
you can get the days of a month by using DateTime.DaysInMonth(int WhichYear,int WhichMonth);
The months in the Julian / Gregorian calendar have the same number of days each year, except February who can have 28 or 29 days depending on the leapness of the year. You can find the number of days in the Description section at http://en.wikipedia.org/wiki/Gregorian_calendar.
As #darkdog mentioned you have DateTime.DaysInMonth. Just do this:
var days = DateTime.DaysInMonth(year, month) +
WhatDayOfWeekTheMonthStarts(year, month);
int rows = (days / 7);
if (0 < days % 7)
{
++rows;
}
Take into consideration the fact that for globalization / localization purposes, some parts of the world use different calendars / methods of organization of the year.
The problem isn't the number of days in the month, it's how many weeks it spans over.
February in a non-leap year will have 28 days, and if the first day of the month is a monday, february will span exactly 4 week numbers.
However, if the first day of the month is a tuesday, or any other day of the week, february will span 5 week numbers.
A 31 day month can span 5 or 6 weeks the same way. If the month starts on a monday, the 31 days gives you 5 week numbers. If the month starts on saturday or sunday, it will span 6 week numbers.
So the right way to obtain this number is to find the week number of the first and last days of the month.
Edit #1: Here's how to calculate the number of weeks a given month spans:
Edit #2: Fixed bugs in code
public static Int32 GetWeekForDateCurrentCulture(DateTime dt)
{
CultureInfo culture = Thread.CurrentThread.CurrentCulture;
Calendar cal = culture.Calendar;
return cal.GetWeekOfYear(dt,
culture.DateTimeFormat.CalendarWeekRule,
culture.DateTimeFormat.FirstDayOfWeek);
}
public static Int32 GetWeekSpanCountForMonth(DateTime dt)
{
DateTime firstDayInMonth = new DateTime(dt.Year, dt.Month, 1);
DateTime lastDayInMonth = firstDayInMonth.AddMonths(1).AddDays(-1);
return
GetWeekForDateCurrentCulture(lastDayInMonth)
- GetWeekForDateCurrentCulture(firstDayInMonth)
+ 1;
}
Try this,
DateTime.DaysInMonth
First Find out which weekday the first day of the month is in. Just new up a datetime with the first day, always 1, and the year and month in question, there is a day of week property on it.
Then from here, you can use the number of days in the month, DateTime.DaysInMonth, in order to determine how many weeks when you divide by seven and then add the number of days from 1 that your first day falls on. For instance,
public static int RowsForMonth(int month, int year)
{
DateTime first = new DateTime(year, month, 1);
//number of days pushed beyond monday this one sits
int offset = ((int)first.DayOfWeek) - 1;
int actualdays = DateTime.DaysInMonth(month, year) + offset;
decimal rows = (actualdays / 7);
if ((rows - ((int)rows)) > .1)
{
rows++;
}
return rows;
}
Check Calendar.GetWeekOfYear. It should do the trick.
There is a problem with it, it does not follow the 4 day rule by ISO 8601, but otherwise it is neat.

Categories

Resources