Trying to code a correct function that returns the number of weeks in a given year, but without success.
Example of the function I'm looking for :
int weeks = GetWeeksInYear ( 2012 )
should return 52 weeks // means there are only 52 weeks in 2012.
P.s.: in a year can be 52, 53, 54 weeks, not sure about 51
See the Calendar.GetWeekOfYear method
public int GetWeeksInYear(int year)
{
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
DateTime date1 = new DateTime(year, 12, 31);
Calendar cal = dfi.Calendar;
return cal.GetWeekOfYear(date1, dfi.CalendarWeekRule,
dfi.FirstDayOfWeek);
}
Be carefull to figure out the correct CalendarWeekRule and FirstDayOfWeek for a Calendar that matches the culture your customers are used to. (for some calenders it might vary...)
Update 14 Oct 2019
If you're using .NET Core 3.0 and you want to get the number of weeks in a year conforming to ISO 8601 - you can use ISOWeek's GetWeeksInYear method.
using System;
using System.Globalization;
public class Program
{
public static void Main()
{
Console.WriteLine(ISOWeek.GetWeeksInYear(2009)); // returns 53
}
}
Working example: https://dotnetfiddle.net/EpIbZQ
I had the issue when I assign 2018 to year parameter of other methods, so I extended the Code of Tim Schmelter. I do not know, maybe there are codes that work faster:
//you can try like that
int weeks = DateHelper.GetWeeksInGivenYear(2018);
int weeks = DateHelper.GetWeeksInGivenYear(2020);
// This presumes that weeks start with Monday.
// Week 1 is the 1st week of the year with a Thursday in it.
public static int GetIso8601WeekOfYear(this 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
return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(time, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
//gets given year last week no
public static int GetWeeksInGivenYear(int year)
{
DateTime lastDate = new DateTime(year, 12, 31);
int lastWeek = GetIso8601WeekOfYear(lastDate);
while (lastWeek == 1)
{
lastDate = lastDate.AddDays(-1);
lastWeek = GetIso8601WeekOfYear(lastDate);
}
return lastWeek;
}
P.s.: in a year can be 52, 53, 54 weeks, not sure about 51
1. If we will check With Calendar we will get results that we can have only 53 or 54 weeks.
2. This is incorrect result (read the end of my answer)
You can check it with the following app:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
namespace TestConsoleApp
{
class Program
{
public static void Main(string[] args)
{
var b = CountWeeksForYearsRange(1, 4000);
var c = b.Where(a => a.Value != 53).ToDictionary(a=>a.Key, a=>a.Value);
}
static DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
static Calendar calendar = DateTimeFormatInfo.CurrentInfo.Calendar;
private static int CountWeeksInYear(int year)
{
DateTime date = new DateTime(year, 12, 31);
return calendar.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
}
private static Dictionary<int,int> CountWeeksForYearsRange(int yearStart, int yearEnd)
{
Dictionary<int, int> rez = new Dictionary<int, int>();
for (int i = yearStart; i <= yearEnd; i++)
{
rez.Add(i, CountWeeksInYear(i));
}
return rez;
}
}
}
and there will be only 53 and 54 values.
This means that for faster work of method we can have pre-coded function for such situation.
Years with not 53 weeks
Years with not 53 and not 54 weeks:
So in this case we can generate simple array of years that have 54 weeks from 0 to 4000 years:
12,40,68,96,108,136,164,192,204,232,260,288,328,356,384,412,440,468,496,508,536,564,592,604,632,660,688,728,756,784,812,840,868,896,908,936,964,992,1004,1032,1060,1088,1128,1156,1184,1212,1240,1268,1296,1308,1336,1364,1392,1404,1432,1460,1488,1528,1556,1584,1612,1640,1668,1696,1708,1736,1764,1792,1804,1832,1860,1888,1928,1956,1984,2012,2040,2068,2096,2108,2136,2164,2192,2204,2232,2260,2288,2328,2356,2384,2412,2440,2468,2496,2508,2536,2564,2592,2604,2632,2660,2688,2728,2756,2784,2812,2840,2868,2896,2908,2936,2964,2992,3004,3032,3060,3088,3128,3156,3184,3212,3240,3268,3296,3308,3336,3364,3392,3404,3432,3460,3488,3528,3556,3584,3612,3640,3668,3696,3708,3736,3764,3792,3804,3832,3860,3888,3928,3956,3984
And this is means that most optimized method will be:
//Works only with 1-4000 years range
public int CountWeeksInYearOptimized(int year)
{
return (_yearsWith54Weeks.IndexOf(year) == -1) ? 53 : 54;
}
private List<int> _yearsWith54Weeks = new List<int> { 12, 40, 68, 96, 108, 136, 164, 192,
204, 232, 260, 288, 328, 356, 384, 412, 440, 468, 496, 508, 536, 564,
592, 604, 632, 660, 688, 728, 756, 784, 812, 840, 868, 896, 908, 936,
964, 992, 1004, 1032, 1060, 1088, 1128, 1156, 1184, 1212, 1240, 1268,
1296, 1308, 1336, 1364, 1392, 1404, 1432, 1460, 1488, 1528, 1556, 1584,
1612, 1640, 1668, 1696, 1708, 1736, 1764, 1792, 1804, 1832, 1860, 1888,
1928, 1956, 1984, 2012, 2040, 2068, 2096, 2108, 2136, 2164, 2192, 2204,
2468, 2496, 2508, 2536, 2564, 2592, 2604, 2632, 2660, 2688, 2728, 2756,
2784, 2812, 2840, 2868, 2896, 2908, 2936, 2964, 2992, 3004, 3032, 3060,
3088, 3128, 3156, 3184, 3212, 3240, 3268, 3296, 3308, 3336, 3364, 3392,
3668, 3696, 3708, 3736, 3764, 3792, 3804, 3832, 3860, 3888, 3928, 3956,
3984 };
or if you don't want to pre-calculated data:
DateTimeFormatInfo dfi = DateTimeFormatInfo.CurrentInfo;
Calendar calendar = DateTimeFormatInfo.CurrentInfo.Calendar;
private int CountWeeksInYear(int year)
{
DateTime date = new DateTime(year, 12, 31);
return calendar.GetWeekOfYear(date, dfi.CalendarWeekRule, dfi.FirstDayOfWeek);
}
UPD: BUT! Looks like this is incorrect way.
I don't know why so, but looks like Calendar saying incorrect number. And correct count of weeks is always on less on 1 week. You can check it manually:
Let's calc days in the following years with Calendar:
2011+2012+2013:
53+54+53=160 weeks.
But stop!
(365+366+365)/7 = 157.
So best way will be to do -1 to the value that will be shown by calendar
Or to use the following fastest method:
//Works only with 1-4000 years range
public int CountWeeksInYearOptimized(int year)
{
return (_yearsWith54Weeks.IndexOf(year) == -1) ? 52 : 53;
}
private List<int> _yearsWith54Weeks = new List<int> { 12, 40, 68, 96, 108, 136, 164, 192,
204, 232, 260, 288, 328, 356, 384, 412, 440, 468, 496, 508, 536, 564,
592, 604, 632, 660, 688, 728, 756, 784, 812, 840, 868, 896, 908, 936,
964, 992, 1004, 1032, 1060, 1088, 1128, 1156, 1184, 1212, 1240, 1268,
1296, 1308, 1336, 1364, 1392, 1404, 1432, 1460, 1488, 1528, 1556, 1584,
1612, 1640, 1668, 1696, 1708, 1736, 1764, 1792, 1804, 1832, 1860, 1888,
1928, 1956, 1984, 2012, 2040, 2068, 2096, 2108, 2136, 2164, 2192, 2204,
2468, 2496, 2508, 2536, 2564, 2592, 2604, 2632, 2660, 2688, 2728, 2756,
2784, 2812, 2840, 2868, 2896, 2908, 2936, 2964, 2992, 3004, 3032, 3060,
3088, 3128, 3156, 3184, 3212, 3240, 3268, 3296, 3308, 3336, 3364, 3392,
3668, 3696, 3708, 3736, 3764, 3792, 3804, 3832, 3860, 3888, 3928, 3956,
3984 };
//For ISO Calender(First Day Of Week : Monday)
DateTime start = new DateTime(2020,1,1);
int total_weeks=0;
//If a year starts on thursday or a leap year starts on wednesday then the year has 53 weeks
if((DateTime.IsLeapYear(start.Year) && start.ToString("dddd")=="Wednesday")||(start.ToString("dddd")=="Thursday"))
{
total_weeks=53;
}
else
{
total_week=52;
}
Console.WriteLine(total_weeks.ToString());
Hi I have a Start Date and End Date per record in a db.
I need to check to see where the time period falls in a 2 year period broken into two lots of quarters then display what quarters each record falls into.
Quarter 1 includes June 09, Jul 09, Aug 09
Quarter 2 includes Sept 09, Oct 09, Nov 09
Quarter 3 includes Dec 09, Jan 10, Feb 10
Quarter 4 includes Mar 10, Apr 10, May 10
Quaretr 5 includes Jun 10, Jul 10...
e.g. 01/10/09 - 01/06/10 would fall into quarters 2, 3, 4 & 5
I am very new to .NET so any examples would be much appreciated.
This should work for you also.
class Range
{
public DateTime Begin { get; private set; }
public DateTime End { get; private set; }
public Range(DateTime begin, DateTime end)
{
Begin = begin;
End = end;
}
public bool Contains(Range range)
{
return range.Begin >= Begin && range.End <= End;
}
}
and then to use it
List<Range> ranges = new List<Range>();
ranges.Add(new Range(DateTime.Now, DateTime.Now.AddMonths(3)));
ranges.Add(new Range(DateTime.Now.AddMonths(3), DateTime.Now.AddMonths(6)));
Range test = new Range(DateTime.Now.AddMonths(1), DateTime.Now.AddMonths(2));
var hits = ranges.Where(range => range.Contains(test));
MessageBox.Show(hits.Count().ToString());
You would call IntervalInQuarters as follows:
IntervalInQuarters(new DateTime(2007, 10, 10), new DateTime(2009, 10, 11));
The function returns a list of quarter start dates. Note that the range of quarters searched is defined within the function itself. Please edit as appropriate for your situation. They key point is to make sure the interval/quarter intersection logic is right.
private List<DateTime> IntervalInQuarters(DateTime myStartDate, DateTime myEndDate)
{
DateTime quarterStart = new DateTime(2006, 06, 01);
DateTime nextQuarterStart = new DateTime(2006, 09, 01);
DateTime finalDate = new DateTime(2011, 01, 01);
List<DateTime> foundQuarters = new List<DateTime>();
while (quarterStart < finalDate)
{
// quarter intersects interval if:
// its start/end date is within our interval
// our start/end date is within quarter interval
DateTime quarterEnd = nextQuarterStart.AddDays(-1);
if (DateInInterval(myStartDate, quarterStart, quarterEnd) ||
DateInInterval(myEndDate, quarterStart, quarterEnd) ||
DateInInterval(quarterStart, myStartDate, myEndDate) ||
DateInInterval(quarterEnd, myStartDate, myEndDate))
{
foundQuarters.Add(quarterStart);
}
quarterStart = nextQuarterStart;
nextQuarterStart = nextQuarterStart.AddMonths(3);
}
return foundQuarters;
}
private bool DateInInterval(DateTime myDate, DateTime intStart, DateTime intEnd)
{
return ((intStart <= myDate) && (myDate <= intEnd));
}
private void Form1_Load(object sender, EventArgs e)
{
DateTime[,] ranges = new DateTime[3,2];
//Range 1 - Jan to March
ranges[0, 0] = new DateTime(2010, 1, 1);
ranges[0, 1] = new DateTime(2010, 3, 1);
//Range 2 - April to July
ranges[1, 0] = new DateTime(2010, 4, 1);
ranges[1, 1] = new DateTime(2010, 7, 1);
//Range 3 - March to June
ranges[2, 0] = new DateTime(2010, 3, 1);
ranges[2, 1] = new DateTime(2010, 6, 1);
DateTime checkDate = new DateTime(2010, 4, 1);
string validRanges = string.Empty;
for (int i = 0; i < ranges.GetLength(0); i++)
{
if (DateWithin(ranges[i,0], ranges[i,1], checkDate))
{
validRanges += i.ToString() + " ";
}
}
MessageBox.Show(validRanges);
}
private bool DateWithin(DateTime dateStart, DateTime dateEnd, DateTime checkDate)
{
if (checkDate.CompareTo(dateStart) < 0 || checkDate.CompareTo(dateEnd) > 0)
{
return false;
}
return true;
}
You may have to take a look at: http://msdn.microsoft.com/en-us/library/03ybds8y(v=VS.100).aspx
This may start you up
FindQuarter(DateTime startDate, DateTime endDate) // 01-10-09, 01-06-10
{
startDateQuarter = GetQuarter(startDate.Month); // 2
endDateQuarter = GetQuarter(endDate.Month); // 1
endDateQuarter += (endDate.Year - startDate.Year) * 4; // 5
// fill up startDateQuarter to endDateQuarter into a list
// and return it // 2,3,4,5
}
GetQuarter(int month) // 6
{
int quarter;
// check the month value and accordingly assign one of the basic quarters
// using if-else construct ie, if(month>=6 && month<=8){ quarter = 1 };
return quarter; // 1
}
Instead of GetQuarter() method, you can also use a dictionary to store your month to quarter mappings
Dictionary<int, int> quarter = new Dictionary<int, int>();
quarter.Add(1,1); //of the format Add(month,quarter)
quarter.Add(2,1);
...
Now instead of GetQuarter(someDate.Month); you can use quarter[someDate.Month];
If you want to compare two dates you should find out the first day of the quarter corresponds every of this dates, then you can compare this two dates:
using System;
namespace DataTime {
class Program {
static int GetQuarter (DateTime dt) {
int Month = dt.Month; // from 1 to 12
return Month / 3 + 1;
}
static DateTime GetQuarterFirstDay (DateTime dt) {
int monthsOfTheFirstDayOfQuarter = (GetQuarter (dt) - 1) * 3 + 1;
return new DateTime(dt.Year, monthsOfTheFirstDayOfQuarter, 1);
// it can be changed to
// return new DateTime(dt.Year, (dt.Month/3)*3 + 1, 1);
}
static void Main (string[] args) {
DateTime dt1 = new DateTime (2009, 6, 9),
dt2 = new DateTime (2009, 7, 9),
dt3 = new DateTime (2009, 8, 9),
dt4 = new DateTime (2009, 8, 9);
Console.WriteLine ("dt1={0}", dt1.AddMonths (1));
Console.WriteLine ("dt2={0}", dt2.AddMonths (1));
Console.WriteLine ("dt3={0}", dt3.AddMonths (1));
DateTime startDate = DateTime.Now,
endDate1 = startDate.AddMonths(24).AddDays(1),
endDate2 = startDate.AddMonths(24).AddDays(-1),
endDate3 = startDate.AddMonths(28);
Console.WriteLine ("Now we have={0}", startDate);
Console.WriteLine ("endDate1={0}", endDate1);
Console.WriteLine ("endDate2={0}", endDate2);
Console.WriteLine ("endDate3={0}", endDate3);
Console.WriteLine ("GetQuarterFirstDay(startDate)={0}", GetQuarterFirstDay (startDate));
Console.WriteLine ("GetQuarterFirstDay(endDate1)={0}", GetQuarterFirstDay (endDate1));
Console.WriteLine ("GetQuarterFirstDay(endDate2)={0}", GetQuarterFirstDay (endDate2));
Console.WriteLine ("GetQuarterFirstDay(endDate3)={0}", GetQuarterFirstDay (endDate3));
if (DateTime.Compare (GetQuarterFirstDay (endDate2), GetQuarterFirstDay (startDate).AddMonths (24)) > 0)
Console.WriteLine ("> 2 Yeas");
else
Console.WriteLine ("<= 2 Yeas");
if (DateTime.Compare (GetQuarterFirstDay (endDate3), GetQuarterFirstDay (startDate).AddMonths (24)) > 0)
Console.WriteLine ("> 2 Yeas");
else
Console.WriteLine ("<= 2 Yeas");
}
}
}
produce
dt1=09.07.2009 00:00:00
dt2=09.08.2009 00:00:00
dt3=09.09.2009 00:00:00
Now we have=22.04.2010 11:21:45
endDate1=23.04.2012 11:21:45
endDate2=21.04.2012 11:21:45
endDate3=22.08.2012 11:21:45
GetQuarterFirstDay(startDate)=01.04.2010 00:00:00
GetQuarterFirstDay(endDate1)=01.04.2012 00:00:00
GetQuarterFirstDay(endDate2)=01.04.2012 00:00:00
GetQuarterFirstDay(endDate3)=01.07.2012 00:00:00
<= 2 Yeas
> 2 Yeas
EDITED: I fixed an error from the first version. Now it should works correct.