Group by all full weeks between date period - LINQ - c#

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.

Related

Getting the list of days of the current week from DateTime.Now

My paradoxical or perhaps trivial problem is to create me a list of the days in format DD - MM - YY from the date of today . Suppose we have today is the " 11/04/2015 " ok ? I would be interested to create a list of datetime that starts exactly from Monday, 02.11.2015 to Sunday, 08.11.2015 . How is this possible? I thought initially :
DateTime today = new DateTime.Now;
int posDayOfWeek = (int)today.DayOfWeek;
if (posDayOfWeek < 7 && posDayOfWeek > 1)
{
// And from there a black hole in my brain ....
}
I do not really know how to do ....
Thank you
cordially
Cristian Capannini
Assuming you always want Monday to Sunday, you just need something like:
DateTime today = DateTime.Today;
int currentDayOfWeek = (int) today.DayOfWeek;
DateTime sunday = today.AddDays(-currentDayOfWeek);
DateTime monday = sunday.AddDays(1);
// If we started on Sunday, we should actually have gone *back*
// 6 days instead of forward 1...
if (currentDayOfWeek == 0)
{
monday = monday.AddDays(-7);
}
var dates = Enumerable.Range(0, 7).Select(days => monday.AddDays(days)).ToList();
Just use this:
DayOfWeek[] days = {
DayOfWeek.Sunday,
DayOfWeek.Monday,
DayOfWeek.Tuesday,
DayOfWeek.Wednesday,
DayOfWeek.Thursday,
DayOfWeek.Friday,
DayOfWeek.Saturday };
It's simple. It's clear. And I've already typed it out for you.
Searching the web for something similar, I found this question/answer thread and expanded to create a sort order based on day of the week starting with yesterday:
//create a sort order that starts yesterday
DateTime orderStartDate = DateTime.Today.AddDays(-1);
List<int> sortOrder = Enumerable.Range(0,7).Select(days => (int)orderStartDate.AddDays(days).DayOfWeek).ToList();
//sort collection using the index of the sortOrder
collection.AddRange(list.OrderBy(list => sortOrder.FindIndex(days => day == list.TargetDay)));

How to calculate sum of amount for each 5 weeks before in linq?

I am having the amount field in income table in database, as well as the created date in same table. I need data like,
Week 1 => Sum(amount for week 1)
Week 2 => Sum(amount for week 2)
Week 3 => Sum(amount for week 3)
Week 4 => Sum(amount for week 4)
Week 5 => Sum(amount for week 5)
What should be my linq query. I am using entity framework.
Edited:
Say previous 4 week of current week + current week =5 weeks. here current week is the week of today's date. eg. today is 26'th Aug 2014 so current week is from 24'th Aug 2014 (Sunday) to 30'th Aug 2014 (Saturday).
You can use the methods in EntityFunctions to perform date and time arithmetic. So you should start by working out the start and end dates, then use TruncateTime if necessary to truncate your created date to a date (instead of date and time), and use DiffDays to work out "number of days since the start of the period". Then just divide by 7 to group...
DateTime today = DateTime.Today;
DateTime start = today.AddDays(-(int) today.DayOfWeek) // Sunday...
.AddDays(-28); // 4 weeks ago
DateTime end = start.AddDays(7 * 5);
var result = from entry in db.Entries
where entry.Created >= start && entry.Created < end
group entry.Amount by EntityFunctions.DiffDays(start,
EntityFunctions.TruncateTime(entry.Created)) / 7 into g
select new { Week = g.Key + 1, Sum = g.Sum() };
While I'd expect that to work, I haven't personally done any date/time work in EF myself. The general approach should be fine, it's just that you may need to tweak it. Also note that this won't give you any results for weeks that don't have any entries - it's probably easiest to do that outside EF.
EDIT: If the summing part isn't working, it's easy to do the summing locally instead:
var query = from entry in db.Entries
where entry.Created >= start && entry.Created < end
group entry.Amount by EntityFunctions.DiffDays(start,
EntityFunctions.TruncateTime(entry.Created)) / 7;
var result = query.AsEnumerable() // Execute the rest locally
.Select(g => new { Week = g.Key + 1, Sum = g.Sum() });

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

Compare today datetime to match (First, second, third, fourth, fifth) weekday(mon, tuesday ect.) of current month

Is There any built in function in c# to compare Compare today's datetime to match like: (First, second, third, fourth, fifth) weekday(mon, tuesday ect.) of current month
or can any one please provide the custom solution for the same.
Regards
Well, you can easily find out whether the day matches:
// Note: consider time zones...
DateTime today = DateTime.Today;
if (today.DayOfWeek == DayOfWeek.Monday)
{
...
}
and you know that the first occurrence of each day of the week will be in the range 1-7, the second will be in the range 8-14 etc. So:
// Check if it's the second Friday of the month...
int targetOccurrence = 2;
DayOfWeek targetDay = DayOfWeek.Friday;
DateTime today = DateTime.Today;
if (today.DayOfWeek == targetDay &&
(today.Day + 6) / 7 == targetOccurrence)
{
// Yes, it's the second Friday
}
If you want to find out whether it's before or after the second Friday of the month, that's slightly harder. Not impossible by any means, but more fiddly.
You can use
DateTime.Now.DayOfWeek
To fetch the current day of week:
DayOfWeek dToday = DateTime.Now.DayOfWeek;
int iDay = dToday.GetHashCode(); // a number between 0-6 representing
// the days in the week
string sDayName = dToday.ToString(); // can be either Sunday, Monday .. Satruday
Use the DateTime.DayOfWeek property.
e.g.
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
{
Console.WriteLine("Someone's got a case of the Mondays!");
}

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