Get the no of weeks from date duration with overlapping scenario - c#

I need to calculate the count of total assigned week and total benched week for an employee.
An employee is assigned in different projects in some time duration which will always start from Monday and always end on Friday. Monday to Friday will be considered as 1 week.There cant be more than 2 week duration for any project. Any overlapping weeks of assigned status should be adjusted. If employee staus is assigned and that time duration overlaps or falls with any of the benched week duration then that week duration for benched status should not be counted at all .
Below are the relevant scenario as below.
"AssignedHistory":[
{"Project":1,"status":"Assigned","Startdate":"01/03/2022", "Enddate":"01/07/2022" },
{"Project":2,"status":"Assigned","Startdate":"01/10/2022", "Enddate":"01/14/2022" },
{"Project":3,"status":"Assigned", "Startdate":"01/10/2022", "Enddate":"01/21/2022" },
{"Project":4,"status":"Assigned", "Startdate":"02/21/2022", "Enddate":"02/25/2022" },
{"Project":5,"status":"Bench","Startdate":"01/17/2022", "Enddate":"01/21/2022" },
{"Project":6,"status":"Bench","Startdate":"02/07/2022", "Enddate":"02/11/2022" }
{"Project":7,"status":"Bench","Startdate":"02/21/2022", "Enddate":"03/04/2022" }
]
Here I need to find the count of total assigned week and total benched week for an employee, and expected result should be :
Total assigned week:4
Total benched week :1
Since 1 week of assigned status is overlapping for 2 projects(no2 and no 3) from 10th Jan to 14 Jan so project 2 and 3 together will be counted as 2 .Also for assigned week of project 3 it is overlapping with benched week of project 5 from 17th Jan to 21st Jan so in that case bench week for project 5 will be counted as 0.Similarly for assigned week of project 4,duration from 21st feb to 25th feb is overlapping or falls under benched week of project 7 so in this case project 7 will be counted as 0.So only we have project 6 for benched week which doest not overlaps with any of the assined project duration.
Thats why total benched count will be 1.
This is how I am thinking.
var assignedweek = AssignedHistory.Where(x => new []{"Assigned"}.Contains(x.status)).ToList();
var benchedweek = AssignedHistory.Where(x => new []{"Bench"}.Contains(x.status)).ToList();
List<DateTime> AssignedWeeklist = assignedweek
.SelectMany(a => {
DateTime firstSunday = a.Startdate.AddDays(-(int)a.Startdate.DayOfWeek);
DateTime lastSunday = a.Enddate.AddDays(-(int)a.Enddate.DayOfWeek);
int weeks = (lastSunday - firstSunday).Days / 7 + 1;
// Enumerate one Sunday per week
return Enumerable.Range(0, weeks).Select(i => firstSunday.AddDays(7 * i));
})
.Distinct()
.ToList();
List<DateTime> BenchWeeklist = benchedweek
.SelectMany(a => {
DateTime firstSunday = a.Startdate.AddDays(-(int)a.Startdate.DayOfWeek);
DateTime lastSunday = a.Enddate.AddDays(-(int)a.Enddate.DayOfWeek);
int weeks = (lastSunday - firstSunday).Days / 7 + 1;
// Enumerate one Sunday per week
return Enumerable.Range(0, weeks).Select(i => firstSunday.AddDays(7 * i));
})
.Distinct()
.ToList();
int assignedweekcount = AssignedWeeklist.Count();
int benchedweekcount = BenchWeeklist.Except(AssignedWeeklist).Count();
It is giving correct assign week count But it is giving incorrect bench week count if there is overlapping bench week with assigned week.
Any way to do this?

you have to change the logic of your calcul on benchweek, you have to keep the sunday date by project:
( i have OS French, so the dates in sample are in format DD/MM/YYYY and not MM/DD/YYYY)
var AssignedHistory1 = new List<Projet>()
{
new Projet(1,"Assigned","03/01/2022", "07/01/2022" ),
new Projet(2,"Assigned","10/01/2022", "14/01/2022" ),
new Projet(3,"Assigned","10/01/2022", "21/01/2022" ),
new Projet(4,"Assigned","21/02/2022", "25/02/2022" ),
new Projet(5,"Bench", "17/01/2022", "21/01/2022" ),
new Projet(6,"Bench", "07/02/2022", "11/02/2022" ),
new Projet(7,"Bench", "21/02/2022", "04/03/2022" )
};
var AssignedHistory2 = new List<Projet>()
{
new Projet(1,"Assigned","17/01/2022", "28/01/2022" ),
new Projet(2,"Bench", "10/01/2022", "21/01/2022" )
};
var AssignedHistory3 = new List<Projet>()
{
new Projet(1,"Assigned","07/02/2022", "18/02/2022" ),
new Projet(2,"Bench", "14/02/2022", "25/02/2022" )
};
var listsamples = new List<List<Projet>> { AssignedHistory1, AssignedHistory2, AssignedHistory3 };
for(int i = 0; i < listsamples.Count;i++)
{
calculate(listsamples[i], $"Sample Assigned{i+1}");
}
void calculate(List<Projet> AssignedHistory, string txt)
{
var assignedweek = AssignedHistory.Where(x => new[] { "Assigned" }.Contains(x.Status)).ToList();
var benchedweek = AssignedHistory.Where(x => new[] { "Bench" }.Contains(x.Status)).ToList();
List<DateTime> AssignedWeeklist = assignedweek
.SelectMany(a =>
{
DateTime firstSunday = a.StartDate.AddDays(-(int)a.StartDate.DayOfWeek);
DateTime lastSunday = a.EndDate.AddDays(-(int)a.EndDate.DayOfWeek);
int weeks = (lastSunday - firstSunday).Days / 7 + 1;
// Enumerate one Sunday per week
return Enumerable.Range(0, weeks).Select(i => firstSunday.AddDays(7 * i));
})
.Distinct()
.ToList();
List<List<DateTime>> BenchWeeklist = benchedweek
.Select(a =>
{
DateTime firstSunday = a.StartDate.AddDays(-(int)a.StartDate.DayOfWeek);
DateTime lastSunday = a.EndDate.AddDays(-(int)a.EndDate.DayOfWeek);
int weeks = (lastSunday - firstSunday).Days / 7 + 1;
// Enumerate one Sunday per week
return new List<DateTime>() { firstSunday, lastSunday }.Distinct().ToList();
})
.Distinct()
.ToList();
int assignedweekcount = AssignedWeeklist.Count();
var benchedweekcount = 0;
foreach (var l in BenchWeeklist)
{
var found = false;
foreach (var it in l)
{
if (AssignedWeeklist.Contains(it)) found = true;
}
if (!found) benchedweekcount++;
}
Console.WriteLine($"AssignedWeek{n} count: {assignedweekcount}, BenchWeek{n} count: {benchedweekcount}");
}
result:
AssignedWeek1 count: 4, BenchWeek1 count: 1
AssignedWeek2 count: 2, BenchWeek2 count: 0
AssignedWeek3 count: 2, BenchWeek3 count: 0

Related

Get tasks done every Monday for the next 5 weeks

How do I get built-up start hours and end hours that if a user just wants to have done several tasks eg every Monday from 08 to 11 the next x number of weeks.
So how can I just do it in a smart way.
I have MoreAdd which tells how many weeks ahead it should make that way.
When I just create a single task. Then it looks like this.
var sTimer = model.StartTime;
var eTimer = model.EndTime;
SignUpInfo addSignUpInfo = new SignUpInfo
{
CompanyId = companyId,
Title = model.Title,
Info = model.Info,
StartTime = sTimer,
EndTimer = eTimer,
Closed = false,
Pay = PayValue,
TaskDone = false,
CreateTime = DateTime.Now,
CategoriId = model.SelectedKategori
};
_db.SignUpInfo.Add(addSignUpInfo);
_db.SaveChanges();
But how will I only do that if I write 5 then make it one from the next Monday and 5 times forward.
I guess you are struggling with determining the start- and end DateTimes for the next 5 weeks from the next Monday. You could use this method:
static IEnumerable<(DateTime start, DateTime end)> GetTimes(DateTime startTime, DateTime endTime, DayOfWeek startDay, int countWeeks)
{
if(endTime < startTime) throw new ArgumentException("TODO");
TimeSpan diff = endTime - startTime;
int daysUntilWeekDay = ((int) startDay - (int) startTime.DayOfWeek + 7) % 7;
DateTime beginningDate = startTime.AddDays(daysUntilWeekDay);
for (int i = 0; i <= countWeeks; i++)
{
DateTime date = beginningDate.AddDays(7 * i);
yield return (start: date, end:date.Add(diff));
}
}
Example:
DateTime dt = new DateTime(2019, 01, 20, 8, 0, 0); //yesterday, sunday, 8 o clock in the morning
foreach(var x in GetTimes(dt, dt.AddHours(3), DayOfWeek.Monday, 5))
Console.WriteLine("Start:{0} End:{1}", x.start, x.end);
With this method it's easy to build a loop that uses your existing code to save the tasks.

Comparing values in historic manner between 2 lists and increment the values if element is from first list or decerement if it's from second list - C#

I need to prepare a chart wherein I'm required to show 3 lines.
One for showing new issues for a week, second for closed issues for a week and third for total accumulative open issues from first week to last week.
For this reason, I have prepared a query and was able to create 2 separate lists successfully - one list maintains the weekly count of new issues and second list maintains the weekly count of closed issues.
Here is the sample data for first list (one which maintains new issues) :
[0]: { Week = {6/14/2015 12:00:00 AM}, Count = 1 }
[1]: { Week = {3/5/2017 12:00:00 AM}, Count = 1 }
[2]: { Week = {5/21/2017 12:00:00 AM}, Count = 4 }
[3]: { Week = {6/4/2017 12:00:00 AM}, Count = 7 }
[4]: { Week = {6/11/2017 12:00:00 AM}, Count = 4 }
[5]: { Week = {6/25/2017 12:00:00 AM}, Count = 7 }
[6]: { Week = {7/9/2017 12:00:00 AM}, Count = 3 }
From the above data, I get the total count of open issues for a particular week.
Note: For both these lists the Week values contain date which falls on Sunday.
As I need the week to start on Monday while displaying data in the chart.
Similarly for sample data for second list (one which maintains closed issues) :
[0]: { Week = {12/13/2015 12:00:00 AM}, Count = 1 }
[1]: { Week = {7/9/2017 12:00:00 AM}, Count = 3 }
[2]: { Week = {6/18/2017 12:00:00 AM}, Count = 2 }
[3]: { Week = {7/23/2017 12:00:00 AM}, Count = 8 }
[4]: { Week = {10/1/2017 12:00:00 AM}, Count = 6 }
[5]: { Week = {8/6/2017 12:00:00 AM}, Count = 3 }
[6]: { Week = {9/17/2017 12:00:00 AM}, Count = 1 }
From the above data, I get total count of closed issues for a particular week.
Here's the code for these lists :
var openIssuesList = getDetails.Where(x => x.ChangedTo == "Open").Select(x => new { Week = x.Date.AddDays(x.Date.DayOfWeek == DayOfWeek.Sunday ? 0 : 7 - (int)x.Date.DayOfWeek).Date, Detail = x }).GroupBy(x => x.Week).Select(x => new { Week = x.Key, Count = x.Count() }).ToList();
var closedIssuesList = getDetails.Where(x => x.ChangedTo == "Closed").Select(x => new { Week = x.Date.AddDays(x.Date.DayOfWeek == DayOfWeek.Sunday ? 0 : 7 - (int)x.Date.DayOfWeek).Date, Detail = x }).GroupBy(x => x.Week).Select(x => new { Week = x.Key, Count = x.Count() }).ToList();
Now the final piece that remains is to create a new list by using the values from these 2 lists which should contain data for total open issues for a week.
Explanation :
I need to compare the week values from the above 2 lists in historic manner(oldest to newest).
Fetch the oldest week value of all from both of these lists. (From the sample data above it should be 6/14/2015 which is in openIssuesList.) Keep fetching weeks (from oldest to newest) in this manner from the above 2 lists.
If week values are from first list i.e openIssuesList then increment the Count value by adding it's Count value with the Count value of previously fetched element (now present in the new third list) if any.
If week values are from second list i.e closedIssuesList then decrement the Count value by subtracting it's Count value with the Count value of previously fetched element (now present in the new third list) if any.
If the week values are equal (like 7/9/2017 from sample data), then first add the Count value of the openIssues list with the previously fetched element (now present in the new third list) if any and then subtract this newly calculated value with the Count value of the closedIssues list .
So from the above provided sample data here's how the new list should like :
[0]: { Week = {6/14/2015 12:00:00 AM}, Count = 1 } // 0+1 = 0 : Oldest week value of all - (fetched from openIssuesList)
[1]: { Week = {12/13/2015 12:00:00 AM}, Count = 0 } // 1-1 = 0 (fetched from closedIssuesList)
[2]: { Week = {3/5/2017 12:00:00 AM}, Count = 1 } // 0+1 = 1 - (fetched from openIssuesList)
[3]: { Week = {5/21/2017 12:00:00 AM}, Count = 5 } // 1+4 = 5 - (fetched from openIssuesList)
[4]: { Week = {6/4/2017 12:00:00 AM}, Count = 12 } // 5+7 = 12 - (fetched from openIssuesList)
[5]: { Week = {6/11/2017 12:00:00 AM}, Count = 16} // 12+4 = 16 - (fetched from openIssuesList)
[6]: { Week = {6/18/2017 12:00:00 AM}, Count = 14 } // 16-2 = 14 (fetched from closedIssuesList)
[7]: { Week = {6/25/2017 12:00:00 AM}, Count = 21 } //14+7 = 21 (fetched from openIssuesList)
[8]: { Week = {7/9/2017 12:00:00 AM}, Count = 21 } // These is common week from both lists. So 20 + (openIssuesList Count value) - (closedIssuesList Count value) i.e [21 + 3 - 3 = 21].
[9]: { Week = {7/23/2017 12:00:00 AM}, Count = 13 } // 21-8 = 13 (fetched from closedIssuesList)
[10]: { Week = {8/6/2017 12:00:00 AM}, Count = 10 } // 13-3 = 10 (fetched from closedIssuesList)
[11]: { Week = {9/17/2017 12:00:00 AM}, Count = 9 } // 10-1 = 9 (fetched from closedIssuesList)
[12]: { Week = {10/1/2017 12:00:00 AM}, Count = 3 } // 9-6 = 3 (fetched from closedIssuesList)
From the above data kindly see the 8th element of this list. The week in this list 7/9/2017 was common from both the openIssuesList (6th element) and closedIssuesList (2nd element)
What would be the code to achieve this list?
Note: I have to remove the Time element value in my code from all the DateTime values in these lists. Hence all the date values appear with 12:00:00 AM in these lists.
Group all issues by week and then calculate count depending on current total count and sum of open and closed issues for given week:
int totalCount = 0;
var issuesByWeek = from issue in getDetails
where issue.ChangedTo == "Open" || issue.ChangedTo == "Closed"
group issue by issue.Date.EndOfWeek() into g
orderby g.Key
select new
{
Week = g.Key,
Count = totalCount += g.Sum(i => i.ChangedTo == "Open" ? 1 : -1)
};
You don't need two lists for calculating this stats. If you need these lists for another purpose, then you can simply concat them and use
from issue in openIssuesList.Concat(closedIssuesList)
Test data for three weeks
var issues = new[]
{
new Issue { Date = DateTime.Today.AddDays(-16), ChangedTo = "Open" },
new Issue { Date = DateTime.Today.AddDays(-15), ChangedTo = "Unknown" },
new Issue { Date = DateTime.Today.AddDays(-15), ChangedTo = "Open" },
new Issue { Date = DateTime.Today.AddDays(-9), ChangedTo = "Closed" },
new Issue { Date = DateTime.Today.AddDays(-8), ChangedTo = "Open" },
new Issue { Date = DateTime.Today.AddDays(-6), ChangedTo = "Closed" },
new Issue { Date = DateTime.Today.AddDays(-5), ChangedTo = "Closed" }
};
Output:
[
{ "Week": "2017-10-22T00:00:00+03:00", "Count": 2 }, // 0 + 2
{ "Week": "2017-10-29T00:00:00+03:00", "Count": 1 }, // 2 + 1 - 2
{ "Week": "2017-11-05T00:00:00+03:00", "Count": 0 } // 1 - 1
]
Extension method is used for readability:
public static class DateTimeExtensions
{
public static DateTime EndOfWeek(this DateTime date) =>
date.AddDays(date.DayOfWeek == DayOfWeek.Sunday ? 0 : 7 - (int)date.DayOfWeek).Date;
}
Note: instead of string consider to use enum for issues statuses
Based on my previous answer, I've expanded the helper class
public class WeekCount
{
public DateTime Week { get; set; }
public int Count { get; set; }
public bool IsOpen { get; set; }
}
, you still need to modify your selects to use it
.Select(x => new WeekCount { Week = x.Key, Count = x.Count() })
, and the code becomes:
var totalIssuesList = openIssuesList.Select(o => new WeekCount { Week = o.Week, Count = o.Count, IsOpen = true }).ToList();
foreach (var closedWeekCount in closedIssuesList)
{
var totalWeekCount = totalIssuesList.FirstOrDefault(owc => owc.Week == closedWeekCount.Week);
if (totalWeekCount != null)
{
totalWeekCount.Count = totalWeekCount.Count - closedWeekCount.Count;
}
else
{
totalIssuesList.Add(new WeekCount { Week = closedWeekCount.Week, Count = closedWeekCount.Count, IsOpen = false });
}
}
totalIssuesList = totalIssuesList.OrderBy(twc => twc.Week).ToList();
var currentCount = 0;
foreach (var totalWeekCount in totalIssuesList)
{
if (totalWeekCount.IsOpen)
{
currentCount += totalWeekCount.Count;
}
else
{
currentCount -= totalWeekCount.Count;
}
totalWeekCount.Count = currentCount;
}
Do note that some of your calculations are wrong, it should be, for example:
[4]: { Week = {6/4/2017 12:00:00 AM}, Count = 12 } // 5+7 = 12

LINQ DateTimes between hours with duration

I'm trying to write a query that return dates that occur within a certain hour of the day plus duration. For example, any DateTimes that occur after (8PM + 8 hours), the hour and duration are variable. It is possible that hour + duration can be in the next day. A spike:
[Test]
public void should_find_dates_between_beginhour_plus_duration()
{
var dates = new []
{
new DateTime(2017, 1, 3, 12,0,0),
new DateTime(2017, 1, 4, 21,0,0),
new DateTime(2017, 1, 5, 2,0,0)
};
var beginHour = 20; //8pm
var duration = 8; //hours
var results = dates.Where(x => x.Hour >= beginHour && x <= x.???? + duration);
//should contain the last 2 dates
foreach (var date in results)
{
Console.WriteLine(date);
}
}
Thus winter/summer time shift does not important here, then you can calculate end hour before running your query. Filtering will be simple - you pick dates which have hour either bigger than begin hour (later in the evening), or smaller than end hour (i.e. earlier in the morning):
var endHour = DateTime.Today.AddHours(beginHour + duration).Hour;
var results = dates.Where(x => beginHour < endHour
? (beginHour <= x.Hour && x.Hour <= endHour)
: (beginHour <= x.Hour || x.Hour <= endHour));

Calculate the start date of a Financial Quarter a date is in

Assume Financial Quarters always start on the 1st of a month and they are always 3 calendar months long.
Different organisations start their Financial Year (FY) in different months - some may be 1st April , some may be 1st July or could be just 1st Jan (which will match normal Calendar Quarters).
Given a date and a month that the FY starts on how can you determine the start of the quarter that the date falls in.
E.g.
DateTime getStartOfFinancialQtr(DateTime date, int monthFinancialYearStartsOn)
15th Jan when FY starts Jan would = 1st Jan
getStartOfFinancialQtr(new DateTime(2013,1,15), 1) == new DateTime(2013,1,1)
15th August when FY starts April would be 1st July
getStartOfFinancialQtr(new DateTime(2013,8,15), 4) == new DateTime(2013,7,1)
BUT 15th Jan 2013 when FY starts February would be 1st November 2012
getStartOfFinancialQtr(new DateTime(2013,1,15), 2) == new DateTime(2012,11,1)
The following solution is the most simple implementation I could think of and works without any - unnecessary - loops:
DateTime getStartOfFinancialQtr(DateTime date, int monthFinancialYearStartsOn)
{
var actualMonth = date.Month;
var financialYear = date.Year;
var difference = actualMonth - monthFinancialYearStartsOn;
if(difference < 0)
{
--financialYear;
difference += 12;
}
var quarter = difference / 3;
return new DateTime(financialYear, monthFinancialYearStartsOn, 1).AddMonths(quarter * 3);
}
Isn't it as simple as this? Am I missing something to this? A quarter is defined as a period of three months, so you just have to find where the given date is, and then compute where the quarter begins based off that given month of the date.
public DateTime GetStartOfFinancialQtr(DateTime dtGiven, int startMonth) {
DateTime dtQuarter = new DateTime(dtGiven.Year, startMonth, 1);
// Start Q is less than the given date
if(startMonth > dtGiven.Month) {
while(dtQuarter > dtGiven) {
dtQuarter = dtQuarter.AddMonths(-3);
}
}
// Start Q is larger than the given date
else {
while(dtQuarter.Month + 3 <= dtGiven.Month) {
dtQuarter = dtQuarter.AddMonths(3);
}
}
return dtQuarter;
}
Below is the testing I ran:
Console.WriteLine(GetStartOfFinancialQtr(new DateTime(2013, 1, 15), 1).ToString());
Console.WriteLine(GetStartOfFinancialQtr(new DateTime(2013, 8, 15), 4).ToString());
Console.WriteLine(GetStartOfFinancialQtr(new DateTime(2013, 1, 15), 2).ToString());
Console output:
01/01/2013 000000
07/01/2013 000000
11/01/2012 000000
You can use the Year class of the Time Period Library for .NET:
// ----------------------------------------------------------------------
public void FiscalYearRange()
{
// calendar
TimeCalendar fiscalYearCalendar = new TimeCalendar(
new TimeCalendarConfig
{
YearBaseMonth = YearMonth.April,
YearType = YearType.FiscalYear
} );
// time range
TimeRange timeRange = new TimeRange( new DateTime( 2007, 10, 1 ), new DateTime( 2012, 2, 25 ) );
Console.WriteLine( "Time range: " + timeRange );
Console.WriteLine();
// fiscal quarter
Console.WriteLine( "Start Quarter: " + new Quarter( timeRange.Start, fiscalYearCalendar ) );
Console.WriteLine( "End Quarter: " + new Quarter( timeRange.End, fiscalYearCalendar ) );
Console.WriteLine();
// fiscal year
Year year = new Year( timeRange.Start, fiscalYearCalendar );
while ( year.Start < timeRange.End )
{
Console.WriteLine( "Fiscal Year: " + year );
year = year.GetNextYear();
}
} // FiscalYearRange
As mentioned, you can easily obtain the answer from Nearest Completed quarter. Here's how you make the modification:
public static class DateTimeExtensions {
public static DateTime NearestQuarterEnd(
this DateTime date,
int firstMonthOfFiscalYear
) {
IEnumerable<DateTime> candidates =
QuartersInYear(date.Year, firstMonthOfFiscalYear)
.Concat(QuartersInYear(date.Year - 1, firstMonthOfFiscalYear));
return candidates.SkipWhile(d => d > date).First();
}
static Dictionary<Tuple<int, int>, List<DateTime>> dict =
new Dictionary<Tuple<int, int>, List<DateTime>>();
static IEnumerable<DateTime> QuartersInYear(
int year,
int firstMonthOfFiscalYear
) {
Contract.Requires(firstMonthOfFiscalYear >= 1
&& firstMonthOfFiscalYear <= 12);
var key = Tuple.Create(year, firstMonthOfFiscalYear);
if(dict.ContainsKey(key)) {
return dict[key];
}
else {
var value =
Enumerable
.Range(0, 4)
.Select(k => firstMonthOfFiscalYear + 3 * k)
.Select(m => m <= 12 ? m : m % 12)
.Select(m => new DateTime(year, m, 1))
.OrderByDescending(d => d)
.ToList();
dict.Add(key, value);
return value;
}
}
}
Usage:
Console.WriteLine(new DateTime(2013, 1, 15).NearestQuarterEnd(1));
Console.WriteLine(new DateTime(2013, 8, 15).NearestQuarterEnd(4));
Console.WriteLine(new DateTime(2013, 1, 15).NearestQuarterEnd(2));
Output:
1/1/2013 12:00:00 AM
7/1/2013 12:00:00 AM
11/1/2012 12:00:00 AM
This passes all three of your test cases.

Get a list of weeks for a year - with dates

I've been racking my brains over this, but it's late on a Friday and I'm going round in circles.
I need to create a list of working weeks for a drop down list, with the week number as the value. So the code would output:
Monday 22nd August - Friday 26th September
Monday 29th August - Friday 2 September
Monday 5th September - Friday 9 September
etc..
For the whole year. Any ideas how I would achieve this?
Thanks.
I think the code below complies with ISO 8601:
var jan1 = new DateTime(DateTime.Today.Year , 1, 1);
//beware different cultures, see other answers
var startOfFirstWeek = jan1.AddDays(1 - (int)(jan1.DayOfWeek));
var weeks=
Enumerable
.Range(0,54)
.Select(i => new {
weekStart = startOfFirstWeek.AddDays(i * 7)
})
.TakeWhile(x => x.weekStart.Year <= jan1.Year)
.Select(x => new {
x.weekStart,
weekFinish=x.weekStart.AddDays(4)
})
.SkipWhile(x => x.weekFinish < jan1.AddDays(1) )
.Select((x,i) => new {
x.weekStart,
x.weekFinish,
weekNum=i+1
});
Bear in mind, that week calculations are done differently in different cultures and there is not a bug if you see week number 53!
using System.Globalization;
CultureInfo cultInfo = CultureInfo.CurrentCulture;
int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now,
cultInfo.DateTimeFormat.CalendarWeekRule,
cultInfo.DateTimeFormat.FirstDayOfWeek);
Just updating what Spender put, because I wanted to make the output of your Datetimes more towards what you wanted.
DateTime jan1 = new DateTime(DateTime.Today.Year, 1, 1);
//beware different cultures, see other answers
DateTime startOfFirstWeek = jan1.AddDays(1 - (int)(jan1.DayOfWeek));
var weeks=
Enumerable
.Range(0,54)
.Select(i => new {
weekStart = startOfFirstWeek.AddDays(i * 7)
})
.TakeWhile(x => x.weekStart.Year <= jan1.Year)
.Select(x => new {
x.weekStart,
weekFinish=x.weekStart.AddDays(4)
})
.SkipWhile(x => x.weekFinish.Year < jan1.Year)
.Select((x,i) => new {
WeekStart = x.weekStart.ToString("dddd, d, MMMM"),
WeekFinish = x.weekFinish.ToString("dddd, d, MMMM"),
weekNum=i+1
});
The change to correct the formatting to what you wanted is in the last select of the anonymous object.
You can use the Week class of the Time Period Library for .NET:
DateTime start = DateTime.Now.Date;
DateTime end = start.AddYears( 1 );
Week week = new Week( start );
while ( week.Start < end )
{
Console.WriteLine( "week " + week );
week = week.GetNextWeek();
}
You may need to tweak this a bit, but it should get you what you need:
static void Main(string[] args)
{
List<DateTime[]> weeks = new List<DateTime[]>();
DateTime beginDate = new DateTime(2011, 01, 01);
DateTime endDate = new DateTime(2012, 01, 01);
DateTime monday = DateTime.Today;
DateTime friday = DateTime.Today;
while (beginDate < endDate)
{
beginDate = beginDate.AddDays(1);
if (beginDate.DayOfWeek == DayOfWeek.Monday)
{
monday = beginDate;
}
else if (beginDate.DayOfWeek == DayOfWeek.Friday)
{
friday = beginDate;
}
else if (beginDate.DayOfWeek == DayOfWeek.Saturday)
{
weeks.Add(new DateTime[] { monday, friday });
}
}
for (int x = 0; x < weeks.Count; x++)
{
Console.WriteLine(weeks[x][0].Date.ToShortDateString() + " - " + weeks[x][1].Date.ToShortDateString());
}
Console.ReadLine();
}

Categories

Resources