|
Introduction
In .NET the DateTime class is implemented using Gregorian calendar.
Sometimes, we need to extend the capabilities of this DateClass class.
For example, if we wanted to know the ISO 8601 week number of the year, we need to
create a new class for this implementation, as we can't extend the DateTime
class. The following class DateEx written in C# is used to convert
a date from Gregorian Calendar to ISO formatted date.
ISO-8601 defines the week as starting with Monday and ending with Sunday,
i.e., Monday is weekday 1 and Sunday is weekday 7. The first week of a year
is the week, which contains the first Thursday of the Gregorian year;
and the week containing January 4th. Week numbers in ISO 8601 are integers
from 1 to 52 or 53; parts of week 1 may be in the previous calendar year;
parts of week 52 may be in the following calendar year; and if a year has
a week 53, parts of it must be in the following calendar year.
The correct way to represent a week in ISO 8601 format is YYYY-WW.
For example, in the year 2002, the ISO week 1 began on Monday December 31st,
2001; and the last ISO week (week 53) ended on Sunday January 2nd, 2003.
Therefore, December 31st, 2001, is in the ISO week 2002-01; and January 2nd,
2003, is in the ISO week 2002-53.
Following is the code for DateEx. It contains four static
functions; ISOWeekNumber, WeekDay, IsLeapYear, DisplayISODate.
using System;
public class DateEx {
public static bool IsLeapYear(int yyyy) {
if ((yyyy % 4 == 0 && yyyy % 100 != 0) || (yyyy % 400 == 0))
return true;
else
return false;
}
public static int ISOWeekNumber(DateTime dt) {
int yyyy=dt.Year;
int mm=dt.Month;
int dd=dt.Day;
int DayOfYearNumber;
int Jan1WeekDay;
int WeekNumber=0, WeekDay;
int i,j,k,l,m,n;
int[] Mnth = new int[12] {0,31,59,90,120,151,181,212,243,273,304,334};
int YearNumber;
DayOfYearNumber = dd + Mnth[mm-1];
if ((IsLeapYear(yyyy) == true) && (mm == 2))
DayOfYearNumber += 1;
i = (yyyy - 1) % 100;
j = (yyyy - 1) - i;
k = i + i/4;
Jan1WeekDay = 1 + (((((j / 100) % 4) * 5) + k) % 7);
l= DayOfYearNumber + (Jan1WeekDay - 1);
WeekDay = 1 + ((l - 1) % 7);
if ((DayOfYearNumber <= (8 - Jan1WeekDay)) && (Jan1WeekDay > 4))
{
YearNumber = yyyy - 1;
if ((Jan1WeekDay == 5) || ((Jan1WeekDay == 6) && (Jan1WeekDay > 4)))
WeekNumber = 53;
else
WeekNumber = 52;
}
else
YearNumber = yyyy;
if (YearNumber == yyyy)
{
if (IsLeapYear(yyyy)==true)
m = 366;
else
m = 365;
if ((m - DayOfYearNumber) < (4-WeekDay))
{
YearNumber = yyyy + 1;
WeekNumber = 1;
}
}
if (YearNumber==yyyy) {
n=DayOfYearNumber + (7 - WeekDay) + (Jan1WeekDay -1);
WeekNumber = n / 7;
if (Jan1WeekDay > 4)
WeekNumber -= 1;
}
return (WeekNumber);
}
public static int WeekDay(DateTime dt) {
int yyyy=dt.Year;
int mm=dt.Month;
int dd=dt.Day;
int DayOfYearNumber;
int Jan1WeekDay;
int WeekDay;
int i,j,k,l;
int[] Mnth = new int[12] {0,31,59,90,120,151,181,212,243,273,304,334};
DayOfYearNumber = dd + Mnth[mm-1];
if ((IsLeapYear(yyyy) == true) && (mm == 2))
DayOfYearNumber += 1;
i = (yyyy - 1) % 100;
j = (yyyy - 1) - i;
k = i + i/4;
Jan1WeekDay = 1 + (((((j / 100) % 4) * 5) + k) % 7);
l= DayOfYearNumber + (Jan1WeekDay - 1);
WeekDay = 1 + ((l - 1) % 7);
return WeekDay;
}
public static string DisplayISODate(DateTime dt) {
string str;
int year,weekday,weeknumber;
year=dt.Year;
weeknumber = ISOWeek(dt);
weekday = WeekDay(dt);
str = year.ToString("d0") + "-" + weeknumber.ToString("d0")
+ "-" + weekday.ToString("d0");
return str;
}
}
Now converting Gregorian Date to ISO Date is very easy.
using System;
using System.Globalization;
public class DateImpl {
public static void Main() {
try {
DateTime dt=new DateTime(2002,12,1);
Console.WriteLine("Gregorian Date : {0}",
dt.ToString("d", DateTimeFormatInfo.InvariantInfo));
Console.WriteLine("ISO Date : {0}",DateEx.DisplayISODate(dt));
}
catch(Exception e) {
Console.WriteLine("Error \n\n {0}", e.ToString());
}
}
}
This class can be easily extended to handle needs for other calendars such as
Julian, Indian Civil Calendar etc.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 8 of 8 (Total in Forum: 8) (Refresh) | FirstPrevNext |
|
|
 |
|
|
Hi,
This is a very good practice, but you can do the same thing with System.Globalization.Calendar plus a great deal of features... please take a look because is really awesome.
Bye!
http://msdn2.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear.aspx
Francisco Trigo Martínez
MCAD
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Like this..
System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("sv-SE", false); int week = culture.Calendar.GetWeekOfYear(DateTime.Now, System.Globalization.CalendarWeekRule.FirstFourDayWeek, System.DayOfWeek.Monday);
/Mattias
|
| Sign In·View Thread·PermaLink | 4.00/5 (3 votes) |
|
|
|
 |
|
|
How does the following piece of code correctly determine the 1st day of the year? <code> // Find the Jan1WeekDay for year i = (yyyy - 1) % 100; j = (yyyy - 1) - i; k = i + i/4; Jan1WeekDay = 1 + (((((j / 100) % 4) * 5) + k) % 7); </code>
Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
After seeing this article, I wrote my own that fixes the bugs in this one:
http://www.boyet.com/Articles/PublishedArticles/CalculatingtheISOweeknumb.html
Cheers, Julian Program Manager, C#
This posting is provided "AS IS" with no warranties, and confers no rights.
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
I think that weekday is wrong when it comes to leap year : In the following code : // Increase of Dayof Year Number by 1, if year is leapyear and month is february if ((IsLeapYear(yyyy) == true) && (mm == 2)) DayOfYearNumber += 1;
DayOfYearNumber should be increased by 1 only if (mm>2)giving
// Increase of Dayof Year Number by 1, if year is leapyear and month is february if ((IsLeapYear(yyyy) == true) && (mm > 2)) DayOfYearNumber += 1;
Regards
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The code posted above has bugs, I've reconstructed DateEx using info off: http://personal.ecu.edu/mccartyr/ISOwdALG.txt
You can see where the bugs are by pasting in the following to a webpage. As the first person wrote, the above script has trouble with the beginning and end of years. Also some major problems dealing with leap years.
If anyone sees errors in the "new" version, please let us all know here.
<%@ Page Language="C#" %>
<script language="C#" runat="server">
void Page_Load() { for( int i = 0; i < 2000; i++ ) { DateTime dt = DateTime.Now.AddDays( i ); DateEx2 dex = new DateEx2( dt ); string s1 = DateEx.DisplayISODate( dt ); string s2 = dex.IsoYearNumber + "-" + dex.IsoWeekNumber + "-" + dex.IsoWeekDayNumber; if( s1 != s2 ) Response.Write( "<font color=red>" ); Response.Write( s1 + ":" + s2 + "<br>" ); if( s1 != s2 ) Response.Write( "</font>" ); } }
public class DateEx2 { /********************************************************************* * For the logic, refer to: * http://personal.ecu.edu/mccartyr/ISOwdALG.txt ********************************************************************/
/********************************************************************* * Member Variables ********************************************************************/
private int isoYearNumber; private int isoWeekNumber; private int isoWeekDayNumber;
/********************************************************************* * Properties ********************************************************************/
public int IsoYearNumber { get{ return isoYearNumber; } }
public int IsoWeekNumber { get{ return isoWeekNumber; } }
public int IsoWeekDayNumber { get{ return isoWeekDayNumber; } }
/********************************************************************* * Constructor ********************************************************************/
public DateEx2( DateTime dt ) { // Split DateTime int y = dt.Year; int m = dt.Month; int d = dt.Day;
// Months int [] Months = new int [12] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
// Get Day of Year int dayOfYear = d + Months[ m - 1 ]; if( IsLeapYear( dt ) && ( m > 2 )) dayOfYear++;
// Find Jan 1 isoWeekDayNumber for Y (Monday = 1, Sunday = 7) int yy = ( y - 1 ) % 100; int c = ( y - 1 ) - yy; int g = yy + yy / 4; int jan1WeekDay = 1 + ((((( c / 100 ) % 4 ) * 5 ) + g ) % 7 );
// Get the isoWeekDayNumber for YMD int h = dayOfYear + ( jan1WeekDay - 1 ); isoWeekDayNumber = 1 + (( h - 1 ) % 7 );
// Find if YMD falls in isoYearNumber Y - 1, isoWeekNumber 52 or 53 if( dayOfYear <= ( 8 - jan1WeekDay ) && jan1WeekDay > 4 ) { isoYearNumber = y - 1; isoWeekNumber = 52; if(( jan1WeekDay == 5 ) || (( jan1WeekDay == 6 ) && IsLeapYear( dt.AddYears( -1 )))) isoWeekNumber++; } else isoYearNumber = y;
// Find if YMD falls in isoYearNumber y + 1, isoWeekNumber 1 int i; if( isoYearNumber == y ) { if( IsLeapYear( dt )) i = 366; else i = 365;
if(( i - dayOfYear ) < ( 4 - isoWeekDayNumber )) { isoYearNumber = y + 1; isoWeekNumber = 1; } }
// Find if YMD falls in isoYearNumber y, isoWeekNumber 1 - 53 int j; if( isoYearNumber == y ) { j = dayOfYear + ( 7 - isoWeekDayNumber ) + ( jan1WeekDay - 1 ); isoWeekNumber = j / 7; if( jan1WeekDay > 4 ) isoWeekNumber--; } }
/********************************************************************* * Public Static Methods ********************************************************************/
// Return whether or not a Leap Year public static bool IsLeapYear( DateTime dt ) { int year = dt.Year; return ((( year % 4 == 0 ) && ( year % 100 != 0 )) || ( year % 400 == 0 )); }
// Return ISO Week Number (1-53) for a given Date public static int ISOWeekNumber( DateTime dt ) { DateEx2 dex = new DateEx2( dt ); return dex.IsoWeekNumber; }
// Return ISO format Week Day (Monday = 1, Sunday = 7) public static int WeekDay( DateTime dt ) { DateEx2 dex = new DateEx2( dt ); return dex.IsoWeekDayNumber; }
// Return ISO format Date ([Year]-[WeekNumber]-[WeekDay]) public static string DisplayISODate( DateTime dt ) { DateEx2 dex = new DateEx2( dt ); return dex.IsoYearNumber + "-W" + ( dex.IsoWeekNumber < 10 ? "0" : "" ) + dex.IsoWeekNumber + "-" + dex.IsoWeekDayNumber; } }
public class DateEx {
// Static Method to check Leap Year public static bool IsLeapYear(int yyyy) {
if ((yyyy % 4 == 0 && yyyy % 100 != 0) || (yyyy % 400 == 0)) return true; else return false; }
// Static Method to return ISO WeekNumber (1-53) for a given year public static int ISOWeekNumber(DateTime dt) {
// Set Year int yyyy=dt.Year;
// Set Month int mm=dt.Month;
// Set Day int dd=dt.Day;
// Declare other required variables int DayOfYearNumber; int Jan1WeekDay; int WeekNumber=0, WeekDay;
int i,j,k,l,m,n; int[] Mnth = new int[12] {0,31,59,90,120,151,181,212,243,273,304,334};
int YearNumber;
// Set DayofYear Number for yyyy mm dd DayOfYearNumber = dd + Mnth[mm-1];
// Increase of Dayof Year Number by 1, if year is leapyear and month is february if ((IsLeapYear(yyyy) == true) && (mm == 2)) DayOfYearNumber += 1;
// Find the Jan1WeekDay for year i = (yyyy - 1) % 100; j = (yyyy - 1) - i; k = i + i/4; Jan1WeekDay = 1 + (((((j / 100) % 4) * 5) + k) % 7);
// Calcuate the WeekDay for the given date l= DayOfYearNumber + (Jan1WeekDay - 1); WeekDay = 1 + ((l - 1) % 7);
// Find if the date falls in YearNumber set WeekNumber to 52 or 53 if ((DayOfYearNumber <= (8 - Jan1WeekDay)) && (Jan1WeekDay > 4)) { YearNumber = yyyy - 1; if ((Jan1WeekDay == 5) || ((Jan1WeekDay == 6) && (Jan1WeekDay > 4))) WeekNumber = 53; else WeekNumber = 52; } else YearNumber = yyyy;
// Set WeekNumber to 1 to 53 if date falls in YearNumber if (YearNumber == yyyy) { if (IsLeapYear(yyyy)==true) m = 366; else m = 365; if ((m - DayOfYearNumber) < (4-WeekDay)) { YearNumber = yyyy + 1; WeekNumber = 1; } }
if (YearNumber==yyyy) { n=DayOfYearNumber + (7 - WeekDay) + (Jan1WeekDay -1); WeekNumber = n / 7; if (Jan1WeekDay > 4) WeekNumber -= 1; }
return (WeekNumber); }
// Static Method to Calculate WeekDay (Monday=1...Sunday=7) public static int WeekDay(DateTime dt) {
// Set Year int yyyy=dt.Year;
// Set Month int mm=dt.Month;
// Set Day int dd=dt.Day;
// Declare other required variables int DayOfYearNumber; int Jan1WeekDay; int WeekDay;
int i,j,k,l; int[] Mnth = new int[12] {0,31,59,90,120,151,181,212,243,273,304,334};
// Set DayofYear Number for yyyy mm dd DayOfYearNumber = dd + Mnth[mm-1];
// Increase of Dayof Year Number by 1, if year is leapyear and month is february if ((IsLeapYear(yyyy) == true) && (mm == 2)) DayOfYearNumber += 1;
// Find the Jan1WeekDay for year i = (yyyy - 1) % 100; j = (yyyy - 1) - i; k = i + i/4; Jan1WeekDay = 1 + (((((j / 100) % 4) * 5) + k) % 7);
// Calcuate the WeekDay for the given date l= DayOfYearNumber + (Jan1WeekDay - 1); WeekDay = 1 + ((l - 1) % 7);
return WeekDay; }
// Static Method to Display date in ISO Format (Year - WeekNumber - WeekDay) public static string DisplayISODate(DateTime dt) { string str; int year,weekday,weeknumber;
year=dt.Year; weeknumber = ISOWeekNumber(dt); weekday = WeekDay(dt);
str = year.ToString("d0") +"-" + weeknumber.ToString("d0") + "-" + weekday.ToString("d0"); return str; } }
</script>
|
| Sign In·View Thread·PermaLink | 4.00/5 (1 vote) |
|
|
|
 |
|
|
... DateTime dt=new DateTime(2000,1,1); Console.WriteLine("ISO Date : {0}",DateEx.DisplayISODate(dt));
should result in 1999-53-6 not 2000-53-6
year -1
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
You can't extend DateTime but you can extend System.Globalization.Calendar which is an abstract class used to interpret information from DateTime.
This may or may not be a better route to take as I have not used this class before; but it seems like it would provide a more seamless integration with DateTime.
James
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|