EmilySamantha80

ISO 8601 Date/Time and Week Date utility class

Aug 4th, 2016
320
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.93 KB | None | 0 0
  1. // Title:  ISO 8601 Date/Time and Week Date utility class
  2. // Author: Emily Heiner
  3. // Date:   2016-08-04
  4. // This code is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported license.
  5. // You are free to share and adapt this code for any purposes, commerical and non-commercial,
  6. // as long as appropriate credit is given, you indicate if changes were made, and you share your
  7. // modified code. License details can be found at https://creativecommons.org/licenses/by-sa/3.0/
  8.  
  9. using System;
  10. using System.Globalization;
  11. using NodaTime; // NodaTime is used for Time Zone conversion, and can be downloaded at http://nodatime.org or using NuGet.
  12.  
  13. namespace ESH.Utility
  14. {
  15.     public class Iso8601
  16.     {
  17.         /// <summary>
  18.         /// Specifies an ISO 8601 day of the week
  19.         /// </summary>
  20.         public enum DayOfWeek
  21.         {
  22.             Monday = 1,
  23.             Tuesday = 2,
  24.             Wednesday = 3,
  25.             Thursday = 4,
  26.             Friday = 5,
  27.             Saturday = 6,
  28.             Sunday = 7
  29.         }
  30.  
  31.         /// <summary>
  32.         /// Get an ISO 8601 Date/Time string from a Gregorian Calendar date. Note: This function relies on NodaTime, which can be downloaded at http://nodatime.org
  33.         /// <param name="date">Gregorian Calendar Date to generate the ISO 8601 Date/Time string from</param>
  34.         /// <param name="displayAsZulu">Convert the date/time to UTC and add 'Z' to the string. Note: If this is true, the 'convertToUtc' parameter and 'showTimeZone' parameter will be ignored.</param>
  35.         /// <param name="convertToUtc">Convert the date/time to UTC before creating the string</param>
  36.         /// <param name="showTimeZone">Add the time zone to the string in +HH:MM/-HH:MM format.</param>
  37.         /// <param name="dtz">NodaTime.DateTimeZone for the input DateTime object</param>
  38.         /// </summary>
  39.         public static string ToIso8601String(DateTime input, bool displayAsZulu = false, bool convertToUtc = false, bool showTimeZone = false, NodaTime.DateTimeZone dtz = null)
  40.         {
  41.             // Set our ISO 8601 Date/Time format string
  42.             string iso8601format = "yyyy-MM-ddTHH:mm:ss";
  43.             // The time zone specifier to be added to the ISO 8601 Date/Time string, if requested.
  44.             string timeZoneSpecifier = string.Empty;
  45.             // The output Date/Time value (will be adjusted for UTC if necessary)
  46.             DateTime output;
  47.  
  48.             // Get the NodaTime Date/Time Zone Provider
  49.             NodaTime.IDateTimeZoneProvider timeZoneProvider = NodaTime.DateTimeZoneProviders.Tzdb;
  50.             if (dtz == null)
  51.             {
  52.                 // If the NodaTime Date/Time Zone wasn't specified, use the system default
  53.                 dtz = timeZoneProvider.GetSystemDefault();
  54.             }
  55.  
  56.             // Create a NodaTime Zoned Date/Time object from the input Date/Time
  57.             NodaTime.ZonedDateTime zonedDateTime = dtz.AtLeniently(NodaTime.LocalDateTime.FromDateTime(input));
  58.  
  59.             //Convert to UTC if necessary
  60.             if (convertToUtc || displayAsZulu)
  61.                 output = zonedDateTime.ToDateTimeUtc();
  62.             else
  63.                 output = zonedDateTime.ToDateTimeUnspecified();
  64.  
  65.             if (displayAsZulu)
  66.             {
  67.                 // If we're displaying as Zulu, add a "Z" to the end of the ISO 8601 Date/Time string
  68.                 timeZoneSpecifier = "Z";
  69.             }
  70.             else if (showTimeZone)
  71.             {
  72.                 if (convertToUtc)
  73.                 {
  74.                     // If we are outputting as UTC, we know the time zone offset
  75.                     timeZoneSpecifier = "+00:00";
  76.                 }
  77.                 else
  78.                 {
  79.                     // Set the time zone specifier to the proper offset
  80.                     timeZoneSpecifier = zonedDateTime.Offset.ToString("+HH:mm", CultureInfo.InvariantCulture);
  81.                 }
  82.             }
  83.  
  84.             // Return our final ISO 8601 Date/Time representation
  85.             return string.Concat(output.ToString(iso8601format), timeZoneSpecifier);
  86.         }
  87.  
  88.         /// <summary>
  89.         /// ISO 8601 Week Date representation of a Gregorian Calendar Date
  90.         /// Adapted from: https://blogs.msdn.microsoft.com/shawnste/2006/01/24/iso-8601-week-of-year-format-in-microsoft-net/
  91.         /// </summary>
  92.         public class WeekDate
  93.         {
  94.             /// <summary>
  95.             /// Gregorian Calendar Date
  96.             /// </summary>
  97.             private readonly DateTime _Date;
  98.             /// <summary>
  99.             /// Gregorian Calendar Date
  100.             /// </summary>
  101.             public DateTime Date
  102.             {
  103.                 get { return this._Date; }
  104.             }
  105.  
  106.             /// <summary>
  107.             /// ISO 8601 Week Date 'Year' part
  108.             /// </summary>
  109.             private readonly int _Year;
  110.             /// <summary>
  111.             /// ISO 8601 Week Date 'Year' part
  112.             /// </summary>
  113.             public int Year
  114.             {
  115.                 get { return this._Year; }
  116.             }
  117.  
  118.             /// <summary>
  119.             /// ISO 8601 Week Date 'Week' part
  120.             /// </summary>
  121.             private readonly int _Week;
  122.             /// <summary>
  123.             /// ISO 8601 Week Date 'Week' part
  124.             /// </summary>
  125.             public int Week
  126.             {
  127.                 get { return this._Week; }
  128.             }
  129.  
  130.             /// <summary>
  131.             /// ISO 8601 Week Date 'Day' part
  132.             /// </summary>
  133.             private readonly int _Day;
  134.             /// <summary>
  135.             /// ISO 8601 Week Date 'Day' part
  136.             /// </summary>
  137.             public int Day
  138.             {
  139.                 get { return this._Day; }
  140.             }
  141.  
  142.             public DayOfWeek DayOfWeek
  143.             {
  144.                 get
  145.                 {
  146.                     return (DayOfWeek)this.Day;
  147.                 }
  148.             }
  149.  
  150.             /// <summary>
  151.             /// ISO 8601 Week Date string representation
  152.             /// </summary>
  153.             private readonly string _WeekDate;
  154.  
  155.             /// <summary>
  156.             /// Get an ISO 8601 Week Date from a Gregorian Calendar Date
  157.             /// <param name="date">Gregorian Calendar Date to generate the ISO 8601 Week Date from</param>
  158.             /// </summary>
  159.             public WeekDate(DateTime date)
  160.             {
  161.                 //We only care about the date, not the time
  162.                 this._Date = date.Date;
  163.  
  164.                 // Get the ISO 8601 Week Number for the given year
  165.                 this._Week = GetIso8601WeekOfYear(this.Date);
  166.  
  167.                 // Compensate for ISO 8601 Week Date Year part being a different year in some instances.
  168.                 if (this.Week == 53 && this.Date.Month == 1)
  169.                     this._Year = this.Date.Year - 1;
  170.                 else if (this.Week == 1 && this.Date.Month == 12)
  171.                     this._Year = this.Date.Year + 1;
  172.                 else
  173.                     this._Year = date.Year;
  174.  
  175.                 // Get the day of the week, starting with Monday
  176.                 this._Day = (((int)this.Date.DayOfWeek + 6) % 7) + 1;
  177.  
  178.                 // Set the week date in the ISO 8601 Week Date Format
  179.                 this._WeekDate = string.Format("{0:0000}-W{1:00}-{2}", this.Year, this.Week, this.Day);
  180.             }
  181.  
  182.             /// <summary>
  183.             /// Get an ISO 8601 'Week' part from a Gregorian Calendar Date
  184.             /// <param name="date">Gregorian Calendar Date to generate the ISO 8601 'Week' part from</param>
  185.             /// </summary>
  186.             public static int GetIso8601WeekOfYear(DateTime date)
  187.             {
  188.                 // Need a calendar.  Culture’s irrelevent since we specify start day of week
  189.                 Calendar cal = CultureInfo.InvariantCulture.Calendar;
  190.  
  191.                 // Seriously cheat.  If its Monday, Tuesday or Wednesday, then it’ll
  192.                 // be the same week# as whatever Thursday, Friday or Saturday are,
  193.                 // and we always get those right
  194.                 System.DayOfWeek day = cal.GetDayOfWeek(date);
  195.                 if (day >= System.DayOfWeek.Monday && day <= System.DayOfWeek.Wednesday)
  196.                 {
  197.                     date = date.AddDays(3);
  198.                 }
  199.  
  200.                 // Return the week of our adjusted day
  201.                 return cal.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek, System.DayOfWeek.Monday);
  202.             }
  203.  
  204.             /// <summary>
  205.             /// Returns a DateTime object representing the first day of the week
  206.             /// </summary>
  207.             public DateTime FirstDayOfWeek()
  208.             {
  209.                 return this.Date.AddDays((-1 * this.Day) + 1);
  210.             }
  211.  
  212.             /// <summary>
  213.             /// Returns the ISO 8601 Week Date string representation
  214.             /// </summary>
  215.             public override string ToString()
  216.             {
  217.                 return this._WeekDate;
  218.             }
  219.         }
  220.     }
  221. }
Advertisement
Add Comment
Please, Sign In to add comment