Ejemplo n.º 1
0
 public bool Equals(DateTag obj)
 {
     if (obj == null)
     {
         return(false);
     }
     return(m_dateTicks == obj.m_dateTicks && TimeZone.Equals(obj.TimeZone) && Precision == obj.Precision);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Parses a metadata date tag into a <see cref="DateTag"/> including <see cref="DateTime"/>, <see cref="TimeZoneTag"/>, and significant digits.
        /// </summary>
        /// <param name="dateTag">The value to be parsed in <see cref="https://www.w3.org/TR/NOTE-datetime">W3CDTF</see> format.</param>
        /// <param name="result">The result of the parsing.</param>
        /// <returns>True if successful, else false.</returns>
        /// <remarks>
        /// <para>The <see cref="https://www.w3.org/TR/NOTE-datetime">W3CDTF</see> format has date and timezone portions.
        /// This method parses both.</para>
        /// <para>If the timezone portion is not included in the input string then the resulting <paramref name="timezone"/>
        /// will have <see cref="Kind"/> set to <see cref="TimeZoneKind.ForceLocal"/>.
        /// </para>
        /// <para>If the timezone portion is set to "Z" indicating UTC, then the resulting <paramref name="timezone"/>
        /// will have <see cref="Kind"/> set to <see cref="TimeZoneKind.ForceUtc"/> and the <see cref="UtcOffset"/>
        /// will be zero.
        /// </para>
        /// <para>The W2CDTF format permits partial date-time values. For example "2018" is just a year with no
        /// other information. The <paramref name="precision"/> value indicates how much detail is included
        /// as follows: 4 = year, 6 = month, 8 = day, 10 = hour, 12 = minute, 14 = second, 17 = millisecond, 20 = microsecond,
        /// 21 = tick (100 nanoseconds).
        /// </para>
        /// </remarks>
        public static bool TryParse(string dateTag, out DateTag result)
        {
            // Init values for failure case
            result = new DateTag(ZeroDate, TimeZoneTag.Zero, 0);

            // Init parts
            int  year   = 0;
            int  month  = 1;
            int  day    = 1;
            int  hour   = 12; // Noon
            int  minute = 0;
            int  second = 0;
            long ticks  = 0;

            // Track position
            int pos = 0;

            if (dateTag.Length < 4)
            {
                return(false);
            }

            if (!int.TryParse(dateTag.Substring(0, 4), out year) ||
                year < 1 || year > 9999)
            {
                return(false);
            }
            int precision = PrecisionYear;

            pos = 4;
            if (dateTag.Length > 5 && dateTag[4] == '-')
            {
                if (!int.TryParse(dateTag.Substring(5, 2), out month) ||
                    month < 1 || month > 12)
                {
                    return(false);
                }
                precision = PrecisionMonth;
                pos       = 7;
                if (dateTag.Length > 8 && dateTag[7] == '-')
                {
                    if (!int.TryParse(dateTag.Substring(8, 2), out day) ||
                        day < 1 || day > DateTime.DaysInMonth(year, month))
                    {
                        return(false);
                    }
                    precision = PrecisionDay;
                    pos       = 10;
                    if (dateTag.Length > 11 && (dateTag[10] == 'T' || dateTag[10] == ' ')) // Even though W3CDTF and ISO 8601 specify 'T' separating date and time, tolerate a space as an alternative.
                    {
                        if (!int.TryParse(dateTag.Substring(11, 2), out hour) ||
                            hour < 0 || hour > 23)
                        {
                            return(false);
                        }
                        precision = PrecisionHour;
                        pos       = 13;
                        if (dateTag.Length > 14 && dateTag[13] == ':')
                        {
                            if (!int.TryParse(dateTag.Substring(14, 2), out minute) ||
                                minute < 0 || minute > 59)
                            {
                                return(false);
                            }
                            precision = PrecisionMinute;
                            pos       = 16;
                            if (dateTag.Length > 17 && dateTag[16] == ':')
                            {
                                if (!int.TryParse(dateTag.Substring(17, 2), out second) ||
                                    second < 0 || second > 59)
                                {
                                    return(false);
                                }
                                precision = PrecisionSecond;
                                pos       = 19;
                                if (dateTag.Length > 20 && dateTag[19] == '.')
                                {
                                    ++pos;
                                    int anchor = pos;
                                    while (pos < dateTag.Length && char.IsDigit(dateTag[pos]))
                                    {
                                        ++pos;
                                    }

                                    precision = PrecisionSecond + (pos - anchor);
                                    if (precision > PrecisionMax)
                                    {
                                        precision = PrecisionMax;
                                    }

                                    double d;
                                    if (!double.TryParse(dateTag.Substring(anchor, pos - anchor), out d))
                                    {
                                        return(false);
                                    }
                                    ticks = (long)(d * Math.Pow(10.0, 7.0 - (pos - anchor)));
                                }
                            }
                        }
                    }
                }
            }

            // Attempt to parse the timezone
            TimeZoneTag  timezone;
            DateTimeKind dtk = DateTimeKind.Unspecified;

            if (pos < dateTag.Length)
            {
                if (!TimeZoneTag.TryParse(dateTag.Substring(pos), out timezone))
                {
                    return(false);
                }
                dtk = (timezone.Kind == TimeZoneKind.ForceUtc) ? DateTimeKind.Utc : DateTimeKind.Local;
            }
            else
            {
                timezone = TimeZoneTag.ForceLocal;
                dtk      = DateTimeKind.Local;
            }

            result = new DateTag(new DateTime(year, month, day, hour, minute, second, dtk).AddTicks(ticks),
                                 timezone, precision);
            return(true);
        }