I have following code to get the weeknumber of the year given in the DateTime object Time
public static int WeeksInYear(DateTime date)
{
GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
return cal.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
}
I give the function the date 1/1/2012 which should return week 1, but it is returning week 52. And I can't seem to figure out why. Anyone have an idea why?
The algorithm is doing exactly what you have instructed it to do. You have the CalanderWeekRule set to FirstFourDayWeek. The 1st of January 2012 was not part of the first four day week, so you have instructed the calander to start counting from January 2nd.
Calculate date from week number
public static int WeeksInYear(DateTime date)
{
GregorianCalendar cal = new GregorianCalendar(GregorianCalendarTypes.Localized);
return cal.GetWeekOfYear(date, CalendarWeekRule.FirstDay, DayOfWeek.Monday);
I think if change CalendarWeekRule.FirstFourDayWeek to CalendarWeekRule.FirstDay then this will work fine.
I changed this then its working fine.
The weeknumber was correctly calculated. You should have a read on how weeknumbers are actually calculated/counted (Wikipedia?!).
Attention: The built-in calculation of week-number-calculation is buggy. Microsoft describes the problem in the KnowledgeBase-Article 200299. It has problems with ISO-8601.
You can use the class Week of the Time Period Library for .NET which supports supports the ISO 8601 week numbering:
TimeCalendar calendar = new TimeCalendar(
new TimeCalendarConfig { YearWeekType = YearWeekType.Iso8601 } );
Week week = new Week( new DateTime( 2012, 01, 01 ), calendar );
Console.WriteLine( "week #: ", week.WeekOfYear );
I assume that because 1/1/2012 was a Sunday and GetWeekOfYear says it returns the week which includes the date, it's returning the last week of 2011 rather than the first week of 2012.
Have a look at the CalendarRule for clarification.
1/1/2012 it was sunday. I believe that's why you get 52, because it was last day of the last year week. For the 2nd of january you should get the right result.
Related
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
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
I am using Calender Extender Control in the AjaxControlToolkit. There are basically 2 controls of date : Start Date and End date (both associated with calender extender). Based on start Date selected, I populate date in the end date field like adding no of months or days. But like I have been able to add months, but also wants to set a particular day of that month which I am unable to do.
Example:
Today date is 18 Dec 2012. Something like 1st of every three months, So I add 3 months the month comes out to be Feb 2013. But I want to set Day 1st Feb 2013. I am unable to do it. Kindly help.
You can set whatever day of month by add month.
DateTime todayDate = DateTime.Now;
DateTime after3MonthDate = todayDate.AddMonths(3);
//Set First Day of Month
after3MonthDate = new DateTime(after3MonthDate.Year, after3MonthDate.Month, 1);
This code can be used for existing date time variable to set the day part to the first day of the month:
if(myDate.Day > 1)
{
myDate = myDate.AddDays(-(myDate.Day - 1));
}
Try this:
// Here is the simple wrapper method to get the first day of the month:
public DateTime FirstDayOfMonthFromDateTime(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, 1);
}
// Set the due date...
DueDate.Text = (FirstDayOfMonthFromDateTime(DateTime.Parse(StartDate.Text).AddMonths(N))).ToShortDateString();
You can also modify the wrapper method to get any day of the month:
public DateTime DayOfMonthFromDateTime(DateTime dateTime, int day)
{
return new DateTime(dateTime.Year, dateTime.Month, day);
}
So I have an application that needs to get a date focus so it can run appropriately. Given a particular date to focus on it needs to know what week it is in. I'm calculating weeks based on Monday dates. And I'm wondering if my focus on Mondays is excessive.
public static DateTime PreviousMonday(this DateTime dt)
{
var dateDayOfWeek = (int)dt.DayOfWeek;
if (dateDayOfWeek==0)
{
dateDayOfWeek = dateDayOfWeek + 7;
}
var alterNumber = dateDayOfWeek - ((dateDayOfWeek*2)-1);
return dt.AddDays(alterNumber);
}
/// <summary>
/// Personal tax week starts on the first Monday after the week with 6th April in unless 6th April is a Monday in
/// which case that starts the first week. In a leap year this means you can have a week 53 which due to the mod 4 approach of calculating
/// flexi week means you get a 5 week flexi period.
/// As such this method forces the weeks into the range 1 - 52 by finding the week number for the week containing 6th April and
/// the number for the current week. Treating the 6th April week as week 1 and using the difference to calculate the tax week.
/// </summary>
public static int GetTaxWeek(this DateTime dt)
{
var startTaxYear = GetActualWeekNumber(new DateTime(DateTime.Now.Year, 4, 6));
var thisWeekNumber = GetActualWeekNumber(dt);
var difference = thisWeekNumber - startTaxYear;
return difference < 0 ? 53 + difference : difference + 1;
}
private static int GetActualWeekNumber(DateTime dt)
{
var ci = System.Threading.Thread.CurrentThread.CurrentCulture;
var cal = ci.Calendar;
var calWeekRule = ci.DateTimeFormat.CalendarWeekRule;
var fDoW = ci.DateTimeFormat.FirstDayOfWeek;
return cal.GetWeekOfYear(dt, calWeekRule, fDoW);
}
public static int PeriodWeek(this DateTime dt)
{
var rawPeriodWeek = GetTaxWeek(dt) % 4;
return rawPeriodWeek == 3 ? 1 : rawPeriodWeek + 2;
}
}
The system runs a rolling 4 week schedule starting in the first tax week and needs to behave differently depending on where in the schedule it is. So you can see...
Get a date from a user (say userDate)
Call userDate=userDate.PreviousMonday();
to get to the Monday of the week
given - where Sunday is the week end
Call userDate.PeriodWeek(); and get
the Period you are in from 1 to 4.
GetTaxWeek is public because it is used elsewhere... I also replace the date as it is used more than once and I don't want to have to remember to change it more than once.
Can I see the wood for the trees? Or is there a more error free way of doing this.
I think you can greatly simplify your code using the GregorianCalendar inside System.Globalization. Here you can get the week number for a given date like this:
GregorianCalendar gc = new GregorianCalendar();
int weekno = gc.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
You see here that you can give the rules for how to caclulate the week number according to your local rules. Like here in Norway, we have Monday as our first week day, and the first week of the year is the first week that has four or more days. Set this to your culture specific rules to get the correct week numbers.
Some of your specific handling you still ahve to do by hand, but some of the clutter can be removed using this at least :)
why are you not using a DateTimePicker control? it will tell you the day for the user selected date. Then you can simply subtract no. of days from it to get date for monday. For example:
I'm using a DateTimePicker control and named it dtpTemp. the event used is
dtpTemp_ValueChanged()
dtpTemp.Value.DayOfWeek - will give you the day: tuesday, wednesday, thursday etc.
then you can use following code with switch case accordingly:
dtpTemp.Value.AddDays(num); to get date for monday
here num will have -ve values which will depend on day calculated above. Values: -1 for tuesday, -2 for wednesday, -3 for thursday and so on.
plus, using a datetimepicker will also have a positive impact on the UI itself.
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.