Click here to Skip to main content
15,881,588 members
Articles / Programming Languages / Java
Alternative
Tip/Trick

Week numbers according to ISO8601

Rate me:
Please Sign up or sign in to vote.
3.75/5 (4 votes)
30 Jul 2010CPOL 14.3K   2   4
/// /// Stuct for the ISO 8601 week date/// /// /// See:/// See:/// Algorithm:<see...
<pre lang="xml">/// <summary>
/// Stuct for the ISO 8601 week date
/// </summary>
/// <remarks>
/// See:<see cref="http://en.wikipedia.org/wiki/ISO_8601"/>
/// See:<see cref="http://en.wikipedia.org/wiki/ISO_week_date"/>
/// Algorithm:<see cref="http://www.boyet.com/Articles/PublishedArticles/CalculatingtheISOweeknumb.html"/>
/// </remarks>
public struct t_IsoWeek
{
  //-------------------------------------------------------------------------
  static readonly string d_WeekRangeError =
    string.Format("Week number must be between {0} and {1}", d_MinWeek, d_MaxWeek);
  static readonly string d_YearRangeError =
    string.Format("Year number must be between {0} and {1}", d_MinYear, d_MaxYear);
  //-------------------------------------------------------------------------
  const int d_MinWeek = 1;
  const int d_MaxWeek = 53;
  const int d_MinYear = 0;
  const int d_MaxYear = 9999;
  //-------------------------------------------------------------------------
  int m_Year;
  int m_Week;
  //-------------------------------------------------------------------------
  /// <summary>
  /// Create a ISO week form a year and a ISO week
  /// </summary>
  /// <param name="p_Year">Year</param>
  /// <param name="p_Week">ISO Week</param>
  public t_IsoWeek(int p_Year, int p_Week)
  {
    m_Year = d_MinYear;
    m_Week = d_MinYear;
    Year = p_Year;
    Week = p_Week;
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Create a ISO week form a DateTime
  /// </summary>
  /// <param name="p_Date">Date</param>
  public t_IsoWeek(DateTime p_Date)
  {
    m_Year = d_MinYear;
    m_Week = d_MinYear;
    this = GetIsoWeek(p_Date);
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Gets the ISO week number
  /// </summary>
  public int Week
  {
    get { return m_Week; }
    private set
    {
      if (value < d_MinWeek || value > d_MaxWeek)
      {
        throw new ArgumentOutOfRangeException("Week", value, d_WeekRangeError);
      }
      m_Week = value;
    }
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Gets the year number
  /// </summary>
  public int Year
  {
    get { return m_Year; }
    private set
    {
      if (value < d_MinYear || value > d_MaxYear)
      {
        throw new ArgumentOutOfRangeException("Year", value, d_YearRangeError);
      }
      m_Year = value;
    }
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Gets the last day (sunday) of the current week
  /// </summary>
  public DateTime EndOfOfWeek
  {
    get
    {
      return StartOfWeek.AddDays(6);
    }
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Gets the first day (monday) of the current week
  /// </summary>
  public DateTime StartOfWeek
  {
    get
    {
      return GetIsoWeekOne(m_Year).AddDays((m_Week - 1) * 7);
    }
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Returns true if the week consists of days in two different years.
  /// Example: 2008-12-29 is written "2009-W01-1" and
  /// 2010-01-03 is written "2009-W53-7"
  /// </summary>
  public bool SpreadsTwoYears
  {
    get
    {
      return StartOfWeek.Year != EndOfOfWeek.Year;
    }
  }
  //-------------------------------------------------------------------------
  /// <summary>
  ///  ISO week notation
  /// </summary>
  /// <returns>{year}-W{week}</returns>
  public override string ToString()
  {
    return string.Format("{0:####}-W{1:##}", m_Year, m_Week);
  }
  //-------------------------------------------------------------------------
  #region Static
  //-------------------------------------------------------------------------
  public static t_IsoWeek GetIsoWeek(DateTime p_Date)
  {
    DateTime l_WeekOne;
    int l_Year = p_Date.Year;
    if (p_Date >= new DateTime(l_Year, 12, 29))
    {
      l_WeekOne = GetIsoWeekOne(l_Year + 1);
      if (p_Date < l_WeekOne)
      {
        l_WeekOne = GetIsoWeekOne(l_Year);
      }
      else
      {
        l_Year++;
      }
    }
    else
    {
      l_WeekOne = GetIsoWeekOne(l_Year);
      if (p_Date < l_WeekOne)
      {
        l_WeekOne = GetIsoWeekOne(--l_Year);
      }
    }
    int l_Week = (p_Date - l_WeekOne).Days / 7 + 1;
    return new t_IsoWeek(l_Year, l_Week);
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Returns the monday of ISO week 01.
  /// Note that this can be the in the year before the given year.
  /// </summary>
  /// <param name="p_Year">Year</param>
  /// <returns>Monday of ISO week 01</returns>
  private static DateTime GetIsoWeekOne(int p_Year)
  {
    // get the date for the 4-Jan for this year
    DateTime l_Date4Jan = new DateTime(p_Year, 1, 4);
    // get the ISO day number for this date 1==Monday, 7==Sunday
    int l_ISODay = GetIsoDayOfWeek(l_Date4Jan);
    // return the date of the Monday that is less than or equal
    // to this date
    return l_Date4Jan.AddDays(1 - l_ISODay);
  }
  //-------------------------------------------------------------------------
  /// <summary>
  /// Returns the day of week as an integer like ISO:
  /// Monday = 1, Sunday = 7
  /// This to comensate the System.DayOfWeek enumeration that starts at 0 (sunday)
  /// </summary>
  /// <param name="p_Date">Date</param>
  /// <returns>1 to 7</returns>
  public static int GetIsoDayOfWeek(DateTime p_Date)
  {
    switch (p_Date.DayOfWeek)
    {
      case DayOfWeek.Monday:
        return 1;
      case DayOfWeek.Tuesday:
        return 2;
      case DayOfWeek.Wednesday:
        return 3;
      case DayOfWeek.Thursday:
        return 4;
      case DayOfWeek.Friday:
        return 5;
      case DayOfWeek.Saturday:
        return 6;
      case DayOfWeek.Sunday:
        return 7;
      default:
        throw new NotImplementedException("DayOfWeek");
    }
  }
  //-------------------------------------------------------------------------
  #endregion
}




License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralReason for my vote of 2 "Much Ado About Nothing" Pin
Toli Cuturicu5-Aug-10 21:31
Toli Cuturicu5-Aug-10 21:31 
Reason for my vote of 2
"Much Ado About Nothing"
GeneralReason for my vote of 3 yes it's an alternate but Luc Pattyn... Pin
johannesnestler3-Aug-10 22:02
johannesnestler3-Aug-10 22:02 
GeneralIt's not an "improvement" on your code, It's a user-friendly... Pin
jasper.mandos1-Aug-10 7:02
jasper.mandos1-Aug-10 7:02 
GeneralSorry but how is this an improvement on my seven (yes 7) lin... Pin
Richard MacCutchan30-Jul-10 9:26
mveRichard MacCutchan30-Jul-10 9:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.