Click here to Skip to main content
15,886,110 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.4K   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 
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 
Sorry but how is this an improvement on my seven (yes 7) lines of code?

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.