internal static ExtendedDateTime Add(ExtendedDateTime e, TimeSpan t)
        {
            var extendedDateTime = TimeSpanToExtendedDateTime((e - new ExtendedDateTime(1, 1, 1)) + t, e.UtcOffset);

            extendedDateTime.YearFlags  = e.YearFlags;
            extendedDateTime.MonthFlags = e.MonthFlags;
            extendedDateTime.DayFlags   = e.DayFlags;
            extendedDateTime.Precision  = e.Precision;

            return(extendedDateTime);
        }
        internal static DayOfWeek DayOfWeek(ExtendedDateTime e) // http://www.stoimen.com/blog/2012/04/24/computer-algorithms-how-to-determine-the-day-of-the-week/
        {
            var yearOfCentury = YearOfCentury(e.Year);
            var centuryOfYear = CenturyOfYear(e.Year);

            var monthKey   = IsLeapYear(e.Year) ? DayOfWeekMonthKeys366[e.Month] : DayOfWeekMonthKeys365[e.Month];
            var centuryKey = DayOfWeekCenturyKeys[centuryOfYear % 4 + centuryOfYear < 0 ? 4 : 0];

            var dayOfWeek = (e.Day + monthKey + yearOfCentury + yearOfCentury / 4 + centuryKey) % 7;

            return((DayOfWeek)dayOfWeek);
        }
示例#3
0
        public void CanRoundTrip()
        {
            // Date
            Assert.AreEqual("2001-02-03", ExtendedDateTime.Parse("2001-02-03").ToString());
            Assert.AreEqual("2008-12", ExtendedDateTime.Parse("2008-12").ToString());
            Assert.AreEqual("2008", ExtendedDateTime.Parse("2008").ToString());
            Assert.AreEqual("-0999", ExtendedDateTime.Parse("-0999").ToString());
            Assert.AreEqual("0000", ExtendedDateTime.Parse("0000").ToString());

            // Date and Time
            Assert.AreEqual("2001-02-03T09:30:01-08", ExtendedDateTime.Parse("2001-02-03T09:30:01-08").ToString());
            Assert.AreEqual("2004-01-01T10:10:10Z", ExtendedDateTime.Parse("2004-01-01T10:10:10Z").ToString());
            Assert.AreEqual("2004-01-01T10:10:10+05", ExtendedDateTime.Parse("2004-01-01T10:10:10+05").ToString());

            // Uncertain and Approximate
            Assert.AreEqual("1984?", ExtendedDateTime.Parse("1984?").ToString());
            Assert.AreEqual("2004-06?", ExtendedDateTime.Parse("2004-06?").ToString());
            Assert.AreEqual("2004-06-11?", ExtendedDateTime.Parse("2004-06-11?").ToString());
            Assert.AreEqual("1984~", ExtendedDateTime.Parse("1984~").ToString());
            Assert.AreEqual("1984?~", ExtendedDateTime.Parse("1984?~").ToString());

            // Years Exceeding Four Digits
            Assert.AreEqual("y170000002", ExtendedDateTime.Parse("y170000002").ToString());
            Assert.AreEqual("y-170000002", ExtendedDateTime.Parse("y-170000002").ToString());

            // Season
            Assert.AreEqual("2001-21", ExtendedDateTime.Parse("2001-21").ToString());
            Assert.AreEqual("2001-22", ExtendedDateTime.Parse("2001-22").ToString());
            Assert.AreEqual("2001-23", ExtendedDateTime.Parse("2001-23").ToString());
            Assert.AreEqual("2001-24", ExtendedDateTime.Parse("2001-24").ToString());

            // Partial Uncertain or Approximate
            Assert.AreEqual("2004?-06-11", ExtendedDateTime.Parse("2004?-06-11").ToString());
            Assert.AreEqual("2004-06~-11", ExtendedDateTime.Parse("2004-06~-11").ToString());
            Assert.AreEqual("2004-(06)?-11", ExtendedDateTime.Parse("2004-(06)?-11").ToString());
            Assert.AreEqual("2004-06-(11)~", ExtendedDateTime.Parse("2004-06-(11)~").ToString());
            Assert.AreEqual("2004-(06)?~", ExtendedDateTime.Parse("2004-(06)?~").ToString());
            Assert.AreEqual("2004?-06-(11)~", ExtendedDateTime.Parse("2004?-06-(11)~").ToString());
            Assert.AreEqual("2004?-(06)?~", ExtendedDateTime.Parse("2004?-(06)?~").ToString());
            Assert.AreEqual("(2004)?-06-04~", ExtendedDateTime.Parse("(2004)?-06-04~").ToString());
            Assert.AreEqual("(2011)-06-04~", ExtendedDateTime.Parse("(2011)-06-04~").ToString());
            Assert.AreEqual("2011-23~", ExtendedDateTime.Parse("2011-23~").ToString());

            // Exponential Form of Years Exceeding Four Digits
            Assert.AreEqual("y17e7", ExtendedDateTime.Parse("y17e7").ToString());
            Assert.AreEqual("y-17e7", ExtendedDateTime.Parse("y-17e7").ToString());
            Assert.AreEqual("y17101e4p3", ExtendedDateTime.Parse("y17101e4p3").ToString());
        }
示例#4
0
        public override object ConvertFrom(ITypeDescriptorContext context, Globalization.CultureInfo culture, object value)
        {
            if (value == null)
            {
                throw GetConvertFromException(value);
            }

            var source = value as string;

            if (source != null)
            {
                return(ExtendedDateTime.Parse(source));
            }

            return(base.ConvertFrom(context, culture, value));
        }
        internal static ExtendedDateTime AddYears(ExtendedDateTime e, int count)
        {
            if (e.Month == 2 && e.Day == 29 && IsLeapYear(e.Year) && !IsLeapYear(e.Year + count))
            {
                throw new InvalidOperationException("Years cannot be added to a leap day unless the resulting year also has a leap day.");
            }

            var extendedDateTime = new ExtendedDateTime(e.Year + count, e.Month, e.Day, e.Hour, e.Minute, e.Second, e.UtcOffset.Hours, e.UtcOffset.Minutes);

            extendedDateTime.YearFlags  = e.YearFlags;
            extendedDateTime.MonthFlags = e.MonthFlags;
            extendedDateTime.DayFlags   = e.DayFlags;
            extendedDateTime.Precision  = e.Precision;

            return(extendedDateTime);
        }
        internal static ExtendedDateTime SubtractYears(ExtendedDateTime e, int count)
        {
            if (e.Month == 2 && e.Day == 29 && IsLeapYear(e.Year) && !IsLeapYear(e.Year - count))
            {
                throw new InvalidOperationException("The years subtracted from a leap day must result in another leap day.");
            }

            var extendedDateTime = new ExtendedDateTime(e.Year - count, e.Month, e.Day, e.Hour, e.Minute, e.Second, e.UtcOffset.Hours, e.UtcOffset.Minutes);

            extendedDateTime.YearFlags  = e.YearFlags;
            extendedDateTime.MonthFlags = e.MonthFlags;
            extendedDateTime.DayFlags   = e.DayFlags;
            extendedDateTime.Precision  = e.Precision;

            return(extendedDateTime);
        }
 public void CalculatesCorrectDifference()
 {
     Assert.AreEqual(TimeSpan.Zero, (ExtendedDateTime.Parse("2012") - ExtendedDateTime.Parse("2012")));
     Assert.AreEqual(TimeSpan.FromDays(1096), (ExtendedDateTime.Parse("2015") - ExtendedDateTime.Parse("2012")));       // 366 for 2012 (leap year) + 365 for 2013 + 365 for 2014 = 1096 days
     Assert.AreEqual(TimeSpan.Zero, (ExtendedDateTime.Parse("2012-01") - ExtendedDateTime.Parse("2012-01")));
     Assert.AreEqual(TimeSpan.FromDays(31), (ExtendedDateTime.Parse("2012-02") - ExtendedDateTime.Parse("2012-01")));
     Assert.AreEqual(TimeSpan.FromDays(365), (ExtendedDateTime.Parse("2013-03") - ExtendedDateTime.Parse("2012-03")));                                     // 31 days for 3/2012 + 30 days for 4/2012 + 31 days for 5/2012 + 30 days for 6/2012 + 31 days for 7/2012 + 31 days for 8/2012 + 30 days for 9/2012 + 31 days for 10/2012 + 30 days for 11/2012 + 31 days for 12/2012 + 31 days for 1/2013 + 28 days for 2/2013 = 365 days
     Assert.AreEqual(TimeSpan.Zero, (ExtendedDateTime.Parse("2012-02-02") - ExtendedDateTime.Parse("2012-02-02")));
     Assert.AreEqual(TimeSpan.FromDays(292), (ExtendedDateTime.Parse("2012-11-20") - ExtendedDateTime.Parse("2012-02-02")));                               // 28 days remaining in of February + 31 days in March + 30 days in April + 31 days in May + 30 days in June + 31 days in July + 31 days in August + 30 days in September + 31 days in October + 19 days passed into November = 292 days
     Assert.AreEqual(TimeSpan.Zero, (ExtendedDateTime.Parse("2012-03-03T03Z") - ExtendedDateTime.Parse("2012-03-03T03Z")));
     Assert.AreEqual(new TimeSpan(292, 18, 0, 0), (ExtendedDateTime.Parse("2012-11-20T20Z") - ExtendedDateTime.Parse("2012-02-02T02Z")));                  // 20 additional hours passed after the end day - 2 hours in to the beginning day = 18 additional hours
     Assert.AreEqual(TimeSpan.Zero, (ExtendedDateTime.Parse("2012-03-03T03:03Z") - ExtendedDateTime.Parse("2012-03-03T03:03Z")));
     Assert.AreEqual(new TimeSpan(292, 18, 18, 0), (ExtendedDateTime.Parse("2012-11-20T20:20Z") - ExtendedDateTime.Parse("2012-02-02T02:02Z")));           // 20 additional minutes passed after the end hour - 2 minutes in to the beginning hour = 18 additional minutes
     Assert.AreEqual(TimeSpan.Zero, (ExtendedDateTime.Parse("2012-03-03T03:03:03Z") - ExtendedDateTime.Parse("2012-03-03T03:03:03Z")));
     Assert.AreEqual(new TimeSpan(292, 18, 18, 18), (ExtendedDateTime.Parse("2012-11-20T20:20:20Z") - ExtendedDateTime.Parse("2012-02-02T02:02:02Z")));    // 20 additional seconds passed after the end minute - 2 seconds in to the beginning minute = 18 additional seconds
     Assert.AreEqual(new TimeSpan(291, 16, 0, 0), (ExtendedDateTime.Parse("2012-11-20T00:00:00-08:00") - ExtendedDateTime.Parse("2012-02-02T00:00:00Z"))); // 28 days remaining in of February + 31 days in March + 30 days in April + 31 days in May + 30 days in June + 31 days in July + 31 days in August + 30 days in September + 31 days in October + 19 days passed into November - 8 hours behind = 291.16 days
 }
        public static ExtendedDateTime AddMonths(ExtendedDateTime e, int monthsToAdd, DayExceedsDaysInMonthStrategy dayExceedsDaysInMonthStrategy)
        {
            var monthTotal = e.Month + monthsToAdd;
            var month      = monthTotal % 12;

            if (month == 0)
            {
                month = 12;
            }

            var year = e.Year + (monthTotal - 1) / 12;
            var day  = e.Day;

            if (day > DaysInMonth(year, month))
            {
                switch (dayExceedsDaysInMonthStrategy)
                {
                case DayExceedsDaysInMonthStrategy.RoundDown:
                    day = DaysInMonth(year, month);
                    break;

                case DayExceedsDaysInMonthStrategy.Overflow:
                    day        = day - DaysInMonth(year, month);
                    monthTotal = month + 1;
                    month      = monthTotal % 12;

                    if (month == 0)
                    {
                        month = 12;
                    }

                    year = e.Year + (monthTotal - 1) / 12;
                    break;
                }
            }

            var extendedDateTime = new ExtendedDateTime(year, month, e.Day, e.Hour, e.Minute, e.Second, e.UtcOffset.Hours, e.UtcOffset.Minutes);

            extendedDateTime.YearFlags  = e.YearFlags;
            extendedDateTime.MonthFlags = e.MonthFlags;
            extendedDateTime.DayFlags   = e.DayFlags;
            extendedDateTime.Precision  = e.Precision;

            return(extendedDateTime);
        }
        internal static ExtendedDateTime SubtractMonths(ExtendedDateTime e, int count)
        {
            var month = e.Month - count % 12;
            var year  = e.Year - count / 12;

            if (e.Day > DaysInMonth(year, month))
            {
                throw new InvalidOperationException("The day is greater than the number of days in the resulting month.");
            }

            var extendedDateTime = new ExtendedDateTime(year, month, e.Day, e.Hour, e.Minute, e.Second, e.UtcOffset.Hours, e.UtcOffset.Minutes);

            extendedDateTime.YearFlags  = e.YearFlags;
            extendedDateTime.MonthFlags = e.MonthFlags;
            extendedDateTime.DayFlags   = e.DayFlags;
            extendedDateTime.Precision  = e.Precision;

            return(extendedDateTime);
        }
 internal static TimeSpan Subtract(ExtendedDateTime later, ExtendedDateTime earlier)
 {
     return(TimeSpan.FromDays(
                (later.Year - earlier.Year) * 365
                + (later.Year - 1) / 4 - (earlier.Year - 1) / 4
                - (later.Year - 1) / 100 + (earlier.Year - 1) / 100
                + (later.Year - 1) / 400 - (earlier.Year - 1) / 400
                + DaysToMonth(later.Year, later.Month)
                - DaysToMonth(earlier.Year, earlier.Month)
                + later.Day
                - earlier.Day)
            + TimeSpan.FromHours(
                later.Hour - earlier.Hour
                + later.UtcOffset.Hours - earlier.UtcOffset.Hours)
            + TimeSpan.FromMinutes(
                later.Minute - earlier.Minute
                + later.UtcOffset.Minutes - earlier.UtcOffset.Minutes)
            + TimeSpan.FromSeconds(later.Second - earlier.Second));
 }
示例#11
0
        public double ToPixels(ExtendedDateTime start, ExtendedDateTime end)
        {
            switch (TimeRulerUnit)
            {
                case TimeRulerUnit.Day:
                    return (end - start).TotalDays * TimeUnitWidth;

                case TimeRulerUnit.Hour:
                    return (end - start).TotalHours * TimeUnitWidth;

                case TimeRulerUnit.Minute:
                    return (end - start).TotalMinutes * TimeUnitWidth;

                case TimeRulerUnit.Second:
                    return (end - start).TotalSeconds * TimeUnitWidth;

                default:
                    return double.NaN;
            }
        }
示例#12
0
        internal static ExtendedDateTimePossibilityCollection Parse(string extendedDateTimeMaskedPrecisionString)
        {
            if (extendedDateTimeMaskedPrecisionString.Length != 4)
            {
                throw new ParseException("A masked precision string must be four characters long.", extendedDateTimeMaskedPrecisionString);
            }

            if (extendedDateTimeMaskedPrecisionString.StartsWith("xx") || extendedDateTimeMaskedPrecisionString[0] == 'x' || extendedDateTimeMaskedPrecisionString[1] == 'x')
            {
                throw new ParseException("Masked precision can only apply to the tens or ones place of the year.", extendedDateTimeMaskedPrecisionString);
            }

            var extendedDateTimeRange = new ExtendedDateTimeRange();

            var start = new ExtendedDateTime();
            var end   = new ExtendedDateTime();

            if (extendedDateTimeMaskedPrecisionString[2] == 'x')
            {
                start.Year = int.Parse(string.Format("{0}{1}00", extendedDateTimeMaskedPrecisionString[0], extendedDateTimeMaskedPrecisionString[1]));
                end.Year   = int.Parse(string.Format("{0}{1}99", extendedDateTimeMaskedPrecisionString[0], extendedDateTimeMaskedPrecisionString[1]));
            }
            else
            {
                start.Year = int.Parse(string.Format("{0}{1}{2}0", extendedDateTimeMaskedPrecisionString[0], extendedDateTimeMaskedPrecisionString[1], extendedDateTimeMaskedPrecisionString[2]));
                end.Year   = int.Parse(string.Format("{0}{1}{2}9", extendedDateTimeMaskedPrecisionString[0], extendedDateTimeMaskedPrecisionString[1], extendedDateTimeMaskedPrecisionString[2]));
            }

            extendedDateTimeRange.Start = start;
            extendedDateTimeRange.End   = end;

            var possibilityCollection = new ExtendedDateTimePossibilityCollection();

            possibilityCollection.Add(extendedDateTimeRange);

            return(possibilityCollection);
        }
        private static void CommitDateComponent(ref int dateComponentIndex, ref bool hasSeasonComponent, int flags, List <char> componentBuffer, ref ExtendedDateTime extendedDateTime)
        {
            if (componentBuffer.Count == 0)
            {
                return;
            }

            var componentString = new string(componentBuffer.ToArray());

            if (dateComponentIndex == 0)                                                           // We expect a year to appear first.
            {
                var isLongFormYear = false;
                var isExponent     = false;
                var isPrecision    = false;
                var digits         = new List <char>();

                for (int i = 0; i < componentString.Length; i++)
                {
                    if (i == 0 && componentString[i] == 'y')                                      // Component is long-form year.
                    {
                        isLongFormYear = true;
                    }
                    else if (char.IsDigit(componentString[i]) || componentString[i] == '-')       // Character is year digit or negative sign.
                    {
                        digits.Add(componentString[i]);
                    }
                    else if (isLongFormYear && componentString[i] == 'e')                         // Component indicates exponent.
                    {
                        extendedDateTime.Year = int.Parse(new string(digits.ToArray()));

                        digits.Clear();

                        isExponent = true;
                    }
                    else if (componentString[i] == 'p' && isExponent)                            // Component indicates precision.
                    {
                        extendedDateTime.YearExponent = int.Parse(new string(digits.ToArray()));

                        digits.Clear();

                        isPrecision = true;
                        isExponent  = false;
                    }
                    else
                    {
                        throw new ParseException("The year is invalid.", componentString);
                    }
                }

                if (isExponent)
                {
                    extendedDateTime.YearExponent = int.Parse(new string(digits.ToArray()));
                }
                else if (isPrecision)
                {
                    extendedDateTime.YearPrecision = int.Parse(new string(digits.ToArray()));
                }
                else
                {
                    if (digits.Count == 0 || (digits.Count == 1 && digits[0] == '-'))
                    {
                        throw new ParseException("The year must have more than zero digits.", componentString);
                    }

                    var year = int.Parse(new string(digits.ToArray()));

                    if (isLongFormYear)
                    {
                        if (isExponent && year == 0)
                        {
                            throw new ParseException("The significand of a long year cannot be zero.", componentString);
                        }
                        else if (digits.Count < 4 || (digits[0] == '-' && digits.Count < 5))
                        {
                            throw new ParseException("The long year must have at least four digits.", componentString);
                        }
                    }
                    else if (digits.Count < 4 || (digits[0] == '-' && digits.Count < 5) || year < -9999 || year > 9999)
                    {
                        throw new ParseException("The year must have four digits.", componentString);
                    }

                    extendedDateTime.Year = year;
                }

                extendedDateTime.YearFlags = (YearFlags)flags;

                dateComponentIndex++;
            }
            else if (dateComponentIndex == 1)                                                 // We expect either a month or a season to appear second.
            {
                if (componentString[0] == '2')                                                // The component is a season.
                {
                    if (componentString.Contains('^'))                                        // Check for season qualifier.
                    {
                        var seasonComponentStrings = componentString.Split('^');

                        extendedDateTime.SeasonQualifier = seasonComponentStrings[1];

                        componentString = seasonComponentStrings[0];
                    }

                    if (componentString.Length != 2)
                    {
                        throw new ParseException("The season must have two digits (excluding the qualifier).", componentString);
                    }
                    else if (componentString.Any(c => !char.IsDigit(c)))
                    {
                        throw new ParseException("The season must be a number (excluding the qualifier).", componentString);
                    }

                    var seasonInteger = int.Parse(componentString);

                    if (seasonInteger < 21 || seasonInteger > 24)
                    {
                        throw new ParseException("The season must be between 21 and 24.", componentString);
                    }

                    extendedDateTime.Season = (Season)seasonInteger;

                    extendedDateTime.SeasonFlags = (SeasonFlags)flags;

                    hasSeasonComponent = true;
                }
                else                                                                       // The component is a month
                {
                    if (componentString.Length != 2)
                    {
                        throw new ParseException("The month must have two digits.", componentString);
                    }

                    if (componentString.Any(c => !char.IsDigit(c)))
                    {
                        throw new ParseException("The month must be a number.", componentString);
                    }

                    var monthInteger = int.Parse(componentString);

                    if (monthInteger < 1 || monthInteger > 12)
                    {
                        throw new ParseException("The month must be between 1 and 12.", componentString);
                    }

                    extendedDateTime.Month = monthInteger;

                    extendedDateTime.Precision++;

                    extendedDateTime.MonthFlags = (MonthFlags)flags;
                }

                dateComponentIndex++;
            }
            else if (dateComponentIndex == 2)                                                   // We expect a day.
            {
                if (hasSeasonComponent)
                {
                    throw new ParseException("A season and day cannot coexist.", componentString);
                }

                if (componentString.Length != 2)
                {
                    throw new ParseException("The day must have two digits.", componentString);
                }

                if (componentString.Any(c => !char.IsDigit(c)))
                {
                    throw new ParseException("The day must be a number.", componentString);
                }

                var dayInteger = int.Parse(componentString);

                if (dayInteger < 1 || dayInteger > 31)
                {
                    throw new ParseException("The day must be between 1 and 31.", componentString);
                }

                var daysInMonth = ExtendedDateTimeCalculator.DaysInMonth(extendedDateTime.Year, extendedDateTime.Month);

                if (dayInteger > daysInMonth)
                {
                    throw new ParseException("The month " + extendedDateTime.Month + " in the year " + extendedDateTime.Year + " has only " + daysInMonth + " days.", componentString);
                }

                extendedDateTime.Day = dayInteger;

                extendedDateTime.Precision++;

                extendedDateTime.DayFlags = (DayFlags)flags;

                dateComponentIndex++;
            }
            else if (dateComponentIndex > 2)
            {
                throw new ParseException("The date can have at most three components.", componentString);
            }

            componentBuffer.Clear();
        }
示例#14
0
        internal static ExtendedDateTimePossibilityCollection ToPossibilityCollection(UnspecifiedExtendedDateTime unspecifiedExtendedDateTime)
        {
            var extendedDateTimePossibilityCollection = new ExtendedDateTimePossibilityCollection();
            var extendedDateTimeRange = new ExtendedDateTimeRange();
            var startExtendedDateTime = new ExtendedDateTime();
            var endExtendedDateTime   = new ExtendedDateTime();

            extendedDateTimeRange.Start = startExtendedDateTime;
            extendedDateTimeRange.End   = endExtendedDateTime;

            extendedDateTimePossibilityCollection.Add(extendedDateTimeRange);

            if (unspecifiedExtendedDateTime.Year.Length != 4)                                 // Year
            {
                throw new ConversionException("An UnspecifiedExtendedDateTime year must be four characters long.");
            }

            var yearStartBuffer = new List <char>();
            var yearEndBuffer   = new List <char>();

            for (int i = 0; i < 4; i++)
            {
                if (unspecifiedExtendedDateTime.Year[0] == 'u')
                {
                    if (i == 0)
                    {
                        yearStartBuffer.Add('-');
                    }

                    yearStartBuffer.Add('9');
                    yearEndBuffer.Add('9');
                }
                else if (unspecifiedExtendedDateTime.Year[i] == 'u')
                {
                    yearStartBuffer.Add('0');
                    yearEndBuffer.Add('9');
                }
                else
                {
                    yearStartBuffer.Add(unspecifiedExtendedDateTime.Year[i]);
                    yearEndBuffer.Add(unspecifiedExtendedDateTime.Year[i]);
                }
            }

            var yearStart = int.Parse(new string(yearStartBuffer.ToArray()));
            var yearEnd   = int.Parse(new string(yearEndBuffer.ToArray()));

            if (unspecifiedExtendedDateTime.Month == null)                                    // Month
            {
                startExtendedDateTime.Year = yearStart;
                endExtendedDateTime.Year   = yearEnd;

                return(extendedDateTimePossibilityCollection);
            }

            if (unspecifiedExtendedDateTime.Month.Length != 2)
            {
                throw new ConversionException("A month must be two characters long.");
            }

            var monthStartBuffer = new List <char>();
            var monthEndBuffer   = new List <char>();

            var isFirstMonthDigitUnspecified = false;

            if (unspecifiedExtendedDateTime.Month[0] == 'u')
            {
                monthStartBuffer.Add('0');
                monthEndBuffer.Add('1');

                isFirstMonthDigitUnspecified = true;
            }
            else
            {
                monthStartBuffer.Add(unspecifiedExtendedDateTime.Month[0]);
                monthEndBuffer.Add(unspecifiedExtendedDateTime.Month[0]);
            }

            if (unspecifiedExtendedDateTime.Month[1] == 'u')
            {
                if (isFirstMonthDigitUnspecified)
                {
                    monthStartBuffer.Add('1');
                    monthEndBuffer.Add('2');
                }
                else
                {
                    var firstDigit = int.Parse(unspecifiedExtendedDateTime.Month[0].ToString());

                    if (firstDigit == 0)
                    {
                        monthStartBuffer.Add('1');
                        monthEndBuffer.Add('9');
                    }
                    else if (firstDigit == 1)
                    {
                        monthStartBuffer.Add('0');
                        monthEndBuffer.Add('2');
                    }
                    else
                    {
                        throw new ConversionException("A month must be between 1 and 12.");
                    }
                }
            }
            else
            {
                if (isFirstMonthDigitUnspecified)
                {
                    var secondDigit = int.Parse(unspecifiedExtendedDateTime.Month[1].ToString());

                    if (secondDigit > 2)                                                                // Month must be in the range of 01 to 09
                    {
                        monthEndBuffer[0] = '0';
                    }
                }

                monthStartBuffer.Add(unspecifiedExtendedDateTime.Month[1]);
                monthEndBuffer.Add(unspecifiedExtendedDateTime.Month[1]);
            }

            var monthStart = int.Parse(new string(monthStartBuffer.ToArray()));
            var monthEnd   = int.Parse(new string(monthEndBuffer.ToArray()));

            if (unspecifiedExtendedDateTime.Day == null)                                              // Day
            {
                startExtendedDateTime.Year  = yearStart;
                startExtendedDateTime.Month = monthStart;
                endExtendedDateTime.Year    = yearEnd;
                endExtendedDateTime.Month   = monthEnd;

                return(extendedDateTimePossibilityCollection);
            }

            if (unspecifiedExtendedDateTime.Day.Length != 2)
            {
                throw new ConversionException("A day must be two characters long.");
            }

            var dayStartBuffer = new List <char>();
            var dayEndBuffer   = new List <char>();

            var daysInEndMonth = ExtendedDateTimeCalculator.DaysInMonth(yearEnd, monthEnd);

            var isFirstDayDigitUnspecified = false;

            if (unspecifiedExtendedDateTime.Day[0] == 'u')
            {
                dayStartBuffer.Add('0');
                dayEndBuffer.Add(daysInEndMonth.ToString()[0]);

                isFirstDayDigitUnspecified = true;
            }
            else
            {
                dayStartBuffer.Add(unspecifiedExtendedDateTime.Day[0]);
                dayEndBuffer.Add(unspecifiedExtendedDateTime.Day[0]);
            }

            if (unspecifiedExtendedDateTime.Day[1] == 'u')
            {
                if (isFirstDayDigitUnspecified)
                {
                    dayStartBuffer.Add('1');
                    dayEndBuffer.Add(daysInEndMonth.ToString()[1]);
                }
                else
                {
                    var firstDigit = int.Parse(unspecifiedExtendedDateTime.Day[0].ToString());

                    if (firstDigit == 0)                   // Day is 01 to 09
                    {
                        dayStartBuffer.Add('1');
                        dayEndBuffer.Add('9');
                    }
                    else if (firstDigit == 1)              // Day is 10 to 19
                    {
                        dayStartBuffer.Add('0');
                        dayEndBuffer.Add('9');
                    }
                    else if (firstDigit == 2)              // Day is 20 to 28 (if end month is February in a non-leap year) or 29
                    {
                        dayStartBuffer.Add('0');

                        if (daysInEndMonth == 28)
                        {
                            dayEndBuffer.Add('8');
                        }
                        else
                        {
                            dayEndBuffer.Add('9');
                        }
                    }
                    else if (firstDigit == 3)              // Day is 30 to 30 or 31 (depending on end month)
                    {
                        dayStartBuffer.Add('0');

                        if (daysInEndMonth == 30)
                        {
                            dayEndBuffer.Add('0');
                        }
                        else
                        {
                            dayEndBuffer.Add('1');
                        }
                    }
                    else
                    {
                        throw new ConversionException("A day must be between 1 and either 28, 29, 30, or 31 depending on the month.");
                    }
                }
            }
            else
            {
                if (isFirstDayDigitUnspecified)
                {
                    var secondDigit = int.Parse(unspecifiedExtendedDateTime.Day[1].ToString());

                    if (secondDigit > daysInEndMonth.ToString()[1])                                                // Decrement the first digit of the end day.
                    {
                        dayEndBuffer[0] = (int.Parse(dayEndBuffer[0].ToString()) - 1).ToString()[0];
                    }
                }

                dayStartBuffer.Add(unspecifiedExtendedDateTime.Day[1]);
                dayEndBuffer.Add(unspecifiedExtendedDateTime.Day[1]);
            }

            var dayStart = int.Parse(new string(dayStartBuffer.ToArray()));
            var dayEnd   = int.Parse(new string(dayEndBuffer.ToArray()));

            var rangeBuffer = new List <ExtendedDateTime>();                            // Collects consecutive dates, which are then converted into an ExtendedDateTimeRange.

            extendedDateTimePossibilityCollection.Clear();

            for (var year = yearStart; year <= yearEnd; year++)
            {
                for (var month = monthStart; month <= monthEnd; month++)
                {
                    for (var day = dayStart; day <= dayEnd; day++)
                    {
                        if (day > ExtendedDateTimeCalculator.DaysInMonth(year, month))
                        {
                            if (rangeBuffer.Count == 1)
                            {
                                extendedDateTimePossibilityCollection.Add(new ExtendedDateTime(year, month, day));

                                rangeBuffer.Clear();
                            }
                            else if (rangeBuffer.Count > 0)
                            {
                                extendedDateTimePossibilityCollection.Add(new ExtendedDateTimeRange(rangeBuffer.First(), rangeBuffer.Last()));

                                rangeBuffer.Clear();
                            }
                        }
                        else
                        {
                            rangeBuffer.Add(new ExtendedDateTime(year, month, day));
                        }

                        if (day == dayEnd)
                        {
                            if (rangeBuffer.Count == 1)
                            {
                                extendedDateTimePossibilityCollection.Add(new ExtendedDateTime(year, month, day));

                                rangeBuffer.Clear();
                            }
                            else if (rangeBuffer.Count > 0)
                            {
                                extendedDateTimePossibilityCollection.Add(new ExtendedDateTimeRange(rangeBuffer.First(), rangeBuffer.Last()));

                                rangeBuffer.Clear();
                            }
                        }
                    }
                }
            }

            return(extendedDateTimePossibilityCollection);
        }
示例#15
0
        private static void InsertFlags(ExtendedDateTime extendedDateTime, StringBuilder stringBuilder)      // Combinations generated from http://www.mathsisfun.com/combinatorics/combinations-permutations-calculator.html
        {
            var da = extendedDateTime.DayFlags.HasFlag(DayFlags.Approximate);
            var du = extendedDateTime.DayFlags.HasFlag(DayFlags.Uncertain);
            var ma = extendedDateTime.MonthFlags.HasFlag(MonthFlags.Approximate);
            var mu = extendedDateTime.MonthFlags.HasFlag(MonthFlags.Uncertain);
            var sa = extendedDateTime.SeasonFlags.HasFlag(SeasonFlags.Approximate);
            var su = extendedDateTime.SeasonFlags.HasFlag(SeasonFlags.Uncertain);
            var ya = extendedDateTime.YearFlags.HasFlag(YearFlags.Approximate);
            var yu = extendedDateTime.YearFlags.HasFlag(YearFlags.Uncertain);

            var de = string.Empty;
            var ds = string.Empty;
            var me = string.Empty;
            var ms = string.Empty;
            var se = string.Empty;
            var ss = string.Empty;
            var ye = string.Empty;
            var ys = string.Empty;

            if (yu && ya && mu && ma && du && da)
            {
                de = "?~";
            }
            else if (yu && ya && mu && ma && du)
            {
                me = "~";
                de = "?";
            }
            else if (yu && ya && mu && ma && da)
            {
                me = "?";
                de = "~";
            }
            else if (yu && ya && mu && du && da)
            {
                ms = "(";
                me = ")?";
                de = "?~";
            }
            else if (yu && ya && ma && du && da)
            {
                ms = "(";
                me = ")~";
                de = "?~";
            }
            else if (yu && mu && ma && du && da)
            {
                ys = "(";
                ye = ")?";
                de = "?~";
            }
            else if (ya && mu && ma && du && da)
            {
                ys = "(";
                ye = ")~";
                de = "?~";
            }
            else if (yu && ya && mu && ma)
            {
                me = "?~";
            }
            else if (yu && ya && ma && da)
            {
                ye = "?";
                de = "~";
            }
            else if (yu && mu && du && da)
            {
                ys = "(";
                ds = "(";
                de = ")~)?";
            }
            else if (ya && mu && du && da)
            {
                ye = ")";
                ms = "(";
                ds = "(";
                de = ")~)?";
            }
            else if (yu && ya && mu && du)
            {
                ye = "~";
                de = "?";
            }
            else if (yu && ya && du && da)
            {
                de = "?~";
                ms = "(";
                me = ")";
            }
            else if (yu && ma && du && da)
            {
                ye = "?";
                ms = "(";
                ds = "(";
                de = ")?)~";
            }
            else if (ya && mu && du && da)
            {
                ye = "~";
                ms = "(";
                me = ")?";
                ds = "(";
                de = ")?~";
            }
            else if (yu && ya && mu && da)
            {
                ye = "?";
                ms = "(";
                me = ")?";
                de = "?";
            }
            else if (yu && mu && ma && du)
            {
                ys = "(";
                ms = "(";
                me = ")~";
                de = ")?";
            }
            else if (mu && ma && du && da)
            {
                ys = "(";
                ye = ")";
            }
            else if (yu && ya && ma && du)
            {
                ye = "?";
                me = "~";
                ds = "(";
                de = ")?";
            }
            else if (yu && mu && ma && da)
            {
                ye = "?";
                ms = "(";
                me = "?";
                de = ")~";
            }
            else if (ya && mu && ma && da)
            {
                ys = "(";
                ms = "(";
                me = ")?";
                de = ")~";
            }
            else if (yu && ya && su && sa)
            {
                se = "?~";
            }
            else if (yu && ya && mu)
            {
                ye = "~";
                me = "?";
            }
            else if (yu && mu && du)
            {
                de = "?";
            }
            else if (ya && mu && ma)
            {
                ys = "(";
                ye = ")~";
                me = "?~";
            }
            else if (ya && du && da)
            {
                ys = "(";
                ye = ")~";
                ds = "(";
                de = ")?~";
            }
            else if (yu && ya && ma)
            {
                ye = "?";
                me = "~";
            }
            else if (yu && mu && da)
            {
                me = "?";
                ds = "(";
                de = ")~";
            }
            else if (ya && mu && du)
            {
                ys = "(";
                ye = ")~";
                de = "?";
            }
            else if (mu && ma && du)
            {
                ms = "(";
                me = "~";
                de = ")?";
            }
            else if (yu && ya && du)
            {
                ye = "~";
                ms = "(";
                me = ")";
                de = "?";
            }
            else if (yu && ma && du)
            {
                ms = "(";
                me = ")~";
                de = "?";
            }
            else if (ya && mu && da)
            {
                ms = "(";
                me = ")?";
                de = "~";
            }
            else if (mu && ma && da)
            {
                ms = "(";
                me = "?";
                de = ")~";
            }
            else if (yu && ya && da)
            {
                ye = "?";
                ms = "(";
                me = ")";
                de = "~";
            }
            else if (yu && ma && da)
            {
                ys = "(";
                ye = ")?";
                de = "~";
            }
            else if (ya && ma && du)
            {
                me = "~";
                ds = "(";
                de = ")?";
            }
            else if (mu && du && da)
            {
                ms = "(";
                me = ")?";
                ds = "(";
                de = ")?~";
            }
            else if (yu && mu && ma)
            {
                ye = "?";
                ms = "(";
                me = ")?~";
            }
            else if (yu && du && da)
            {
                ye = "?";
                ds = "(";
                de = ")?~";
            }
            else if (ya && ma && da)
            {
                de = "~";
            }
            else if (ma && du && da)
            {
                ms = ")";
                me = ")~";
                ds = "(";
                de = ")?~";
            }
            else if (yu && ya && su)
            {
                ye = "~";
                se = "?";
            }
            else if (yu && ya && sa)
            {
                ye = "?";
                se = "~";
            }
            else if (yu && su && sa)
            {
                ye = "?";
                ss = "(";
                se = ")?~";
            }
            else if (ya && sa && su)
            {
                ye = "~";
                ss = "(";
                se = ")?~";
            }
            else if (yu && ya)
            {
                ye = "?~";
            }
            else if (yu && mu)
            {
                me = "?";
            }
            else if (yu && ma)
            {
                ye = "?";
                ms = "(";
                me = ")~";
            }
            else if (yu && du)
            {
                ms = "(";
                me = ")";
                de = "?";
            }
            else if (yu && da)
            {
                ye = "?";
                ds = "(";
                de = ")~";
            }
            else if (ya && mu)
            {
                ye = "~";
                ms = "(";
                me = ")?";
            }
            else if (ya && ma)
            {
                me = "~";
            }
            else if (ya && du)
            {
                ye = "~";
                ds = "(";
                de = ")?";
            }
            else if (ya && da)
            {
                ms = "(";
                me = ")";
                de = "~";
            }
            else if (mu && ma)
            {
                ms = "(";
                me = ")?~";
            }
            else if (mu && du)
            {
                ys = "(";
                ye = ")";
                de = "?";
            }
            else if (mu && da)
            {
                ms = "(";
                me = ")?";
                ds = "(";
                de = ")~";
            }
            else if (ma && du)
            {
                ms = "(";
                me = ")~";
                ds = "(";
                de = ")?";
            }
            else if (ma && da)
            {
                ys = "(";
                ye = ")";
                de = "~";
            }
            else if (du && da)
            {
                ds = "(";
                de = ")?~";
            }
            else if (yu && su)
            {
                se = "?";
            }
            else if (yu && sa)
            {
                ye = "?";
                ss = "(";
                se = ")~";
            }
            else if (ya && su)
            {
                ye = "~";
                ss = "(";
                se = ")?";
            }
            else if (ya && sa)
            {
                se = "~";
            }
            else if (su && sa)
            {
                ss = "(";
                se = ")?~";
            }
            else if (yu)
            {
                ye = "?";
            }
            else if (ya)
            {
                ye = "~";
            }
            else if (su)
            {
                ss = "(";
                se = ")?";
            }
            else if (sa)
            {
                ss = "(";
                se = ")~";
            }
            else if (mu)
            {
                ms = "(";
                me = ")?";
            }
            else if (ma)
            {
                ms = "(";
                me = ")~";
            }
            else if (du)
            {
                ds = "(";
                de = ")?";
            }
            else if (da)
            {
                ds = "(";
                de = ")~";
            }

            stringBuilder
            .Replace("{ds}", ds)
            .Replace("{de}", de)
            .Replace("{ms}", ms)
            .Replace("{me}", me)
            .Replace("{ss}", ss)
            .Replace("{se}", se)
            .Replace("{ys}", ys)
            .Replace("{ye}", ye);
        }
示例#16
0
        internal static string Serialize(ExtendedDateTime extendedDateTime)
        {
            if (extendedDateTime.IsUnknown)
            {
                return("unknown");
            }

            if (extendedDateTime.IsOpen)
            {
                return("open");
            }

            var stringBuilder = new StringBuilder();

            stringBuilder.Append("{ys}");

            if (extendedDateTime.Year > 9999 || extendedDateTime.Year < -9999 || extendedDateTime.YearExponent.HasValue)       // The year must be in long form.
            {
                stringBuilder.Append('y');
            }

            if (extendedDateTime.YearExponent.HasValue)
            {
                stringBuilder.Append(extendedDateTime.Year);
            }
            else
            {
                stringBuilder.AppendFormat("{0:D4}", extendedDateTime.Year);
            }

            stringBuilder.Append("{ye}");

            if (extendedDateTime.YearExponent.HasValue)
            {
                stringBuilder.Append('e').Append(extendedDateTime.YearExponent);
            }

            if (extendedDateTime.YearPrecision.HasValue)
            {
                stringBuilder.Append('p').Append(extendedDateTime.YearPrecision);
            }

            if (extendedDateTime.Month != 1 || extendedDateTime.Precision > ExtendedDateTimePrecision.Year)
            {
                stringBuilder.Append("-{ms}").AppendFormat("{0:D2}", extendedDateTime.Month).Append("{me}");
            }

            if (extendedDateTime.Season != Season.Undefined)
            {
                stringBuilder.Append("-{ss}").Append((int)extendedDateTime.Season);

                if (extendedDateTime.SeasonQualifier != null)
                {
                    stringBuilder.Append('^').Append(extendedDateTime.SeasonQualifier);
                }

                stringBuilder.Append("{se}");
            }

            if (extendedDateTime.Day != 1 || extendedDateTime.Precision > ExtendedDateTimePrecision.Month)
            {
                stringBuilder.Append("-{ds}").AppendFormat("{0:D2}", extendedDateTime.Day);
            }

            stringBuilder.Append("{de}");

            InsertFlags(extendedDateTime, stringBuilder);

            if (extendedDateTime.Hour != 0 || extendedDateTime.Precision > ExtendedDateTimePrecision.Day)
            {
                stringBuilder.AppendFormat("T{0:D2}", extendedDateTime.Hour);
            }

            if (extendedDateTime.Minute != 0 || extendedDateTime.Precision > ExtendedDateTimePrecision.Hour)
            {
                stringBuilder.AppendFormat(":{0:D2}", extendedDateTime.Minute);
            }

            if (extendedDateTime.Second != 0 || extendedDateTime.Precision > ExtendedDateTimePrecision.Minute)
            {
                stringBuilder.AppendFormat(":{0:D2}", extendedDateTime.Second);
            }

            if (extendedDateTime.Precision > ExtendedDateTimePrecision.Day)
            {
                if (extendedDateTime.UtcOffset.Hours == 0 && extendedDateTime.UtcOffset.Minutes == 0)
                {
                    stringBuilder.Append('Z');
                }
                else
                {
                    if (extendedDateTime.UtcOffset.Hours < 0)
                    {
                        stringBuilder.Append('-');
                    }
                    else
                    {
                        stringBuilder.Append('+');
                    }

                    stringBuilder.AppendFormat("{0:D2}", Math.Abs(extendedDateTime.UtcOffset.Hours));
                }

                if (extendedDateTime.UtcOffset.Minutes != 0)
                {
                    stringBuilder.AppendFormat(":{0:D2}", extendedDateTime.UtcOffset.Minutes);
                }
            }

            return(stringBuilder.ToString());
        }
示例#17
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (_hasViewChanged)
            {
                // In determining the labels to display, it must be kept in mind that the spacings between
                // the labels might be variable depending on the current time unit. For instance, if the
                // timeline is measured in months, then the labels will not be equally spaced apart because
                // a month is anywhere from 28 to 31 days. The solution is to produce labels one at a time
                // while the total accumulated width is less than the viewport width.
                //
                // 1. First we first convert the current horizontal offset into a TimeSpan, and add
                // that to the timeline's start time to get the time of the viewport's left edge. This
                // time may be more precise than the timeline's current unit of measurement. For
                // example, the viewport left time may be defined down to the second, but the timeline's
                // unit is an hour. Therefore, we must round up to the nearest unit.
                //
                // 2. The difference between the rounded date and the precise date is the time between
                // the start of the viewport and the initial label. Converting this TimeSpan into pixels
                // will yield the x position of the initial label relative to the viewport's left edge.
                // We can store this value along with the label number for use during the arranging process.
                //
                // 3. Now we can create a label, add it to the panel, and measure it.
                //
                // 4. Next we increment the rounded date by whatever is set as the timeline's unit.
                //
                // 5. Repeat steps 2 to 4 until the rounded date is equal to or exceeds the date of the
                // viewport's right edge.

                Children.Clear();

                if (_labelOffsets == null)
                {
                    _labelOffsets = new Dictionary<int, double>();
                }
                else
                {
                    _labelOffsets.Clear();
                }

                ExtendedDateTime viewportLeftTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset);
                ExtendedDateTime viewportRightTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset + availableSize.Width);
                ExtendedDateTime labelTime = null;
                int labelIndex = 0;

                switch (Resolution)
                {
                    case TimeResolution.Century:
                        labelTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 100);
                        break;

                    case TimeResolution.Decade:
                        labelTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 10);
                        break;

                    case TimeResolution.Year:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Year);
                        break;

                    case TimeResolution.Month:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Month, false);
                        break;

                    case TimeResolution.Day:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Day, false);
                        break;

                    case TimeResolution.Hour:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Hour, false);
                        break;

                    case TimeResolution.Minute:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Minute, false);
                        break;

                    case TimeResolution.Second:
                        labelTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Second, false);
                        break;

                    default:
                        break;
                }

                while (labelTime < viewportRightTime)
                {
                    var label = new TextBlock();
                    label.Text = labelTime.ToString();
                    label.FontFamily = FontFamily;
                    label.FontSize = FontSize;
                    label.Foreground = Foreground;

                    switch (Resolution)
                    {
                        case TimeResolution.Century:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddYears(100);
                            break;

                        case TimeResolution.Decade:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddYears(10);
                            break;

                        case TimeResolution.Year:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddYears(1);
                            break;

                        case TimeResolution.Month:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime.AddMonths(1);
                            break;

                        case TimeResolution.Day:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromDays(1);
                            break;

                        case TimeResolution.Hour:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromHours(1);
                            break;

                        case TimeResolution.Minute:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromMinutes(1);
                            break;

                        case TimeResolution.Second:
                            _labelOffsets.Add(labelIndex, Ruler.ToPixels(viewportLeftTime, labelTime) + LabelOffset);
                            labelTime = labelTime + TimeSpan.FromSeconds(1);
                            break;

                        default:
                            break;
                    }

                    Children.Add(label);
                    label.Measure(availableSize);

                    labelIndex++;
                }

                _hasViewChanged = false;

                return availableSize;
            }

            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
            }

            return availableSize;
        }
        internal static ExtendedDateTime ToRoundedPrecision(ExtendedDateTime e, ExtendedDateTimePrecision p, bool roundUp = false)
        {
            var year   = e.Year;
            var month  = e.Month;
            var day    = e.Day;
            var hour   = e.Hour;
            var minute = e.Minute;
            var second = e.Second;

            if (p < ExtendedDateTimePrecision.Second)
            {
                second = 0;
            }

            if (p < ExtendedDateTimePrecision.Minute)
            {
                minute = 0;
            }

            if (p < ExtendedDateTimePrecision.Hour)
            {
                hour = 0;
            }

            if (p < ExtendedDateTimePrecision.Day)
            {
                day = 1;
            }

            if (p < ExtendedDateTimePrecision.Month)
            {
                month = 1;
            }

            if (roundUp)
            {
                switch (p)
                {
                case ExtendedDateTimePrecision.Year:

                    if (e.Month > 1)
                    {
                        year++;
                    }

                    break;

                case ExtendedDateTimePrecision.Month:

                    if (e.Day > 1)
                    {
                        month++;
                    }

                    break;

                case ExtendedDateTimePrecision.Day:

                    if (e.Hour > 0)
                    {
                        day++;
                    }

                    break;

                case ExtendedDateTimePrecision.Hour:

                    if (e.Minute > 0)
                    {
                        hour++;
                    }

                    break;

                case ExtendedDateTimePrecision.Minute:

                    if (e.Second > 0)
                    {
                        minute++;
                    }

                    break;

                case ExtendedDateTimePrecision.Second:

                    break;
                }

                if (second > 59)
                {
                    second = 0;
                    minute++;
                }

                if (minute > 59)
                {
                    minute = 0;
                    hour++;
                }

                if (hour > 23)
                {
                    hour = 0;
                    day++;
                }

                if (day > DaysInMonth(year, month == 13 ? 1 : month))
                {
                    day = 1;
                    month++;
                }

                if (month > 12)
                {
                    month = 1;
                    year++;
                }
            }

            var extendedDateTime = new ExtendedDateTime(year, month, day, hour, minute, second, e.UtcOffset.Hours, e.UtcOffset.Minutes);

            extendedDateTime.YearFlags  = e.YearFlags;
            extendedDateTime.MonthFlags = e.MonthFlags;
            extendedDateTime.DayFlags   = e.DayFlags;
            extendedDateTime.Precision  = p;

            return(extendedDateTime);
        }
        private static void CommitTimeComponent(ref int timeComponentIndex, bool timeZonePart, List <char> componentBuffer, ref ExtendedDateTime extendedDateTime)
        {
            if (componentBuffer.Count == 0)
            {
                return;
            }

            var componentString = new string(componentBuffer.ToArray());

            if (timeComponentIndex == 0 && !timeZonePart)                                                               // We expect hours to appear first.
            {
                if (componentString.Any(c => !char.IsDigit(c)))
                {
                    throw new ParseException("The hour must be a number.", componentString);
                }
                else if (componentString.Length != 2 && !(componentString.Length == 3 && componentString.StartsWith("-")))
                {
                    throw new ParseException("The hour must be two digits long.", componentString);
                }

                extendedDateTime.Hour = int.Parse(componentString);

                extendedDateTime.Precision++;

                timeComponentIndex++;
            }
            else if (timeComponentIndex == 1 && !timeZonePart)                                                         // We expect minutes to appear second.
            {
                if (componentString.Any(c => !char.IsDigit(c)))
                {
                    throw new ParseException("The minute must be a number.", componentString);
                }
                else if (componentString.Length != 2)
                {
                    throw new ParseException("The minute must be two digits long.", componentString);
                }

                extendedDateTime.Minute = int.Parse(componentString);

                extendedDateTime.Precision++;

                timeComponentIndex++;
            }
            else if (timeComponentIndex == 2 && !timeZonePart)                                                        // We expect seconds to appear third.
            {
                if (componentString.Any(c => !char.IsDigit(c)))
                {
                    throw new ParseException("The second must be a number.", componentString);
                }
                else if (componentString.Length != 2)
                {
                    throw new ParseException("The second must be two digits long.", componentString);
                }

                extendedDateTime.Second = int.Parse(componentString);

                extendedDateTime.Precision++;

                timeComponentIndex++;
            }
            else if (timeZonePart)
            {
                if (componentString.StartsWith("Z"))
                {
                    extendedDateTime.UtcOffset = TimeSpan.Zero;
                }
                else if (componentString.StartsWith("+") || componentString.StartsWith("-"))         // It must be a non-UTC time zone offset.
                {
                    var timeZoneOffsetComponentStrings = componentString.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);

                    if (timeZoneOffsetComponentStrings.Length == 0)
                    {
                        throw new ParseException("The time zone offset must have at least two digits.", componentString);
                    }

                    var hourOffsetString = timeZoneOffsetComponentStrings[0];                        // Time zone hours offset.

                    if (hourOffsetString.Any(c => !char.IsDigit(c) && c != '+' && c != '-'))
                    {
                        throw new ParseException("The time zone hour offset must be a number.", hourOffsetString);
                    }

                    if (hourOffsetString.StartsWith("+") || hourOffsetString.StartsWith("-"))
                    {
                        if (hourOffsetString.Length != 3)
                        {
                            throw new ParseException("The time zone hour offset must have exactly two digits.", hourOffsetString);
                        }
                    }
                    else if (hourOffsetString.Length != 2)
                    {
                        throw new ParseException("The time zone hour offset must have exactly two digits.", hourOffsetString);
                    }

                    extendedDateTime.UtcOffset = TimeSpan.FromHours(double.Parse(hourOffsetString));

                    if (timeZoneOffsetComponentStrings.Length == 2)                                  // Optional time zone minutes offset.
                    {
                        var minuteOffsetString = timeZoneOffsetComponentStrings[1];

                        if (minuteOffsetString.Any(c => !char.IsDigit(c)))
                        {
                            throw new ParseException("The time zone minute offset must be a number.", minuteOffsetString);
                        }
                        else if (minuteOffsetString.Length != 2)
                        {
                            throw new ParseException("The time zone minute offset must have exactly two digits.", minuteOffsetString);
                        }

                        extendedDateTime.UtcOffset += TimeSpan.FromMinutes(double.Parse(minuteOffsetString));
                    }

                    if (timeZoneOffsetComponentStrings.Length > 2)
                    {
                        throw new ParseException("The time zone offset can have at most two components: hours and minutes.", componentString);
                    }
                }
            }
            else
            {
                throw new ParseException("The time can have at most three components excluding the time zone.", componentString);
            }

            componentBuffer.Clear();
        }
        internal static ExtendedDateTime Parse(string extendedDateTimeString, ExtendedDateTime extendedDateTime = null)
        {
            if (string.IsNullOrWhiteSpace(extendedDateTimeString))
            {
                throw new ArgumentNullException("extendedDateTimeString");
            }

            if (extendedDateTime == null)
            {
                extendedDateTime = new ExtendedDateTime();
            }

            InsertArtificialScopes(ref extendedDateTimeString);                                                        // e.g. 1995-11?-12~ => {{1995-11}?-12}~

            var componentBuffer = new List <char>();

            var isDatePart            = true;
            var isTimeZonePart        = false;
            var isSeasonQualifierPart = false;

            var currentDateComponent = 0;
            var currentTimeComponent = 0;

            var hasSeasonComponent = false;

            if (string.IsNullOrEmpty(extendedDateTimeString))
            {
                throw new ParseException("The input string cannot be empty.", extendedDateTimeString);
            }

            for (int i = 0; i < extendedDateTimeString.Length; i++)
            {
                var character = extendedDateTimeString[i];

                if (isDatePart)                                                                                        // Parsing date portion of extended date time.
                {
                    if (character == '(' || character == '{')                                                          // Scope increment for natural and artificial scopes.
                    {
                        CommitDateComponent(ref currentDateComponent, ref hasSeasonComponent, GetScopeFlags(i - 1, extendedDateTimeString), componentBuffer, ref extendedDateTime);
                    }
                    else if (character == ')' || character == '}')                                                     // Scope decrement for natural and artificial scopes.
                    {
                        CommitDateComponent(ref currentDateComponent, ref hasSeasonComponent, GetScopeFlags(i - 1, extendedDateTimeString), componentBuffer, ref extendedDateTime);

                        if (i + 1 < extendedDateTimeString.Length && GetFlag(extendedDateTimeString[i + 1]) != 0)
                        {
                            i++;                                                                                       // Skip past first flag if exists.

                            if (i + 1 < extendedDateTimeString.Length && GetFlag(extendedDateTimeString[i + 1]) != 0)
                            {
                                i++;                                                                                   // Skip past second flag if exists.
                            }
                        }
                    }
                    else if (char.IsDigit(character) || character == 'y' || character == 'e' || character == 'p')
                    {
                        componentBuffer.Add(character);
                    }
                    else if (character == '^')                                                                         // Add season qualifier indicator to component buffer.
                    {
                        componentBuffer.Add(character);

                        isSeasonQualifierPart = true;
                    }
                    else if (character == '-')
                    {
                        if (i == 0 || (i > 0 && extendedDateTimeString[i - 1] == 'y'))                                 // Hyphen is a negative sign.
                        {
                            componentBuffer.Add(character);
                        }
                        else                                                                                           // Hyphen is a component separator.
                        {
                            CommitDateComponent(ref currentDateComponent, ref hasSeasonComponent, GetScopeFlags(i - 1, extendedDateTimeString), componentBuffer, ref extendedDateTime);
                        }
                    }
                    else if (character == 'T')
                    {
                        CommitDateComponent(ref currentDateComponent, ref hasSeasonComponent, GetScopeFlags(i - 1, extendedDateTimeString), componentBuffer, ref extendedDateTime);

                        isDatePart = false;
                    }
                    else if (isSeasonQualifierPart)
                    {
                        if (char.IsWhiteSpace(character))
                        {
                            throw new ParseException("Season qualifiers cannot contain whitespace.", new string(componentBuffer.ToArray()));
                        }

                        componentBuffer.Add(character);
                    }
                    else
                    {
                        throw new ParseException("The character \'" + character + "\' could not be recognized.", new string(componentBuffer.ToArray()));
                    }
                }
                else                                                                                                           // Parsing time portion of extended date time.
                {
                    if (char.IsDigit(character) || (character == ':' && isTimeZonePart))                                       // Add digit to component buffer.
                    {
                        componentBuffer.Add(character);
                    }
                    else if (character == ':' && !isTimeZonePart)
                    {
                        CommitTimeComponent(ref currentTimeComponent, isTimeZonePart, componentBuffer, ref extendedDateTime);
                    }
                    else if (character == 'Z' || character == '+' || character == '-')                                         // Time zone component
                    {
                        CommitTimeComponent(ref currentTimeComponent, isTimeZonePart, componentBuffer, ref extendedDateTime);

                        componentBuffer.Add(character);

                        isTimeZonePart = true;
                    }
                    else
                    {
                        throw new ParseException("The character \'" + character + "\' could not be recognized.", new string(componentBuffer.ToArray()));
                    }
                }
            }

            if (isDatePart)
            {
                CommitDateComponent(ref currentDateComponent, ref hasSeasonComponent, GetScopeFlags(extendedDateTimeString.Length - 1, extendedDateTimeString), componentBuffer, ref extendedDateTime);
            }
            else
            {
                CommitTimeComponent(ref currentTimeComponent, isTimeZonePart, componentBuffer, ref extendedDateTime);
            }

            return(extendedDateTime);
        }
示例#21
0
        protected override Size MeasureOverride(Size availableSize)
        {
            if (_hasViewChanged)
            {
                // In determining the number of guidelines to display, it must be kept in mind that
                // the spacings between the lines might be variable depending on the
                // current time unit. For instance, if the timeline is measured in months, then the
                // lines will not be equally spaced apart because a month is anywhere from 28 to 31 days.
                // The solution is to produce lines one at a time while the total accumulated width is
                // less than the viewport width.
                //
                // 1. First we first convert the current horizontal offset into a TimeSpan, and add
                // that to the timeline's start time to get the time of the viewport's left edge. This
                // time may be more precise than the timeline's current unit of measurement. For
                // example, the viewport left time may be defined down to the second, but the timeline's
                // unit is an hour. Therefore, we must round up to the nearest unit.
                //
                // 2. The difference between the rounded date and the precise date is the time between
                // the start of the viewport and the initial line. Converting this TimeSpan into pixels
                // will yield the x position of the initial line relative to the viewport's left edge.
                // We can store this value along with the line number for use during the arranging process.
                //
                // 3. Now we can create a guideline, add it to the panel, and measure it.
                //
                // 4. Next we increment the rounded date by whatever is set as the timeline's unit.
                //
                // 5. Repeat steps 2 to 4 until the rounded date is equal to or exceeds the date of the
                // viewport's right edge.

                Children.Clear();

                if (_lineOffsets == null)
                {
                    _lineOffsets = new Dictionary<int, double>();
                }
                else
                {
                    _lineOffsets.Clear();
                }

                ExtendedDateTime viewportLeftTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset);
                ExtendedDateTime viewportRightTime = Dates.Earliest() + Ruler.ToTimeSpan(_horizontalOffset + availableSize.Width);
                ExtendedDateTime guidelineTime = null;
                int guidelineIndex = 0;

                switch (Resolution)
                {
                    case TimeResolution.Century:
                        guidelineTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 100 + 100);
                        break;

                    case TimeResolution.Decade:
                        guidelineTime = new ExtendedDateTime(viewportLeftTime.Year - viewportLeftTime.Year % 10 + 10);
                        break;

                    case TimeResolution.Year:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Year, true);
                        break;

                    case TimeResolution.Month:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Month, true);
                        break;

                    case TimeResolution.Day:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Day, true);
                        break;

                    case TimeResolution.Hour:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Hour, true);
                        break;

                    case TimeResolution.Minute:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Minute, true);
                        break;

                    case TimeResolution.Second:
                        guidelineTime = viewportLeftTime.ToRoundedPrecision(ExtendedDateTimePrecision.Second, true);
                        break;

                    default:
                        break;
                }

                while (guidelineTime < viewportRightTime)
                {
                    var guideline = new Line();
                    guideline.Y2 = availableSize.Height;
                    guideline.StrokeThickness = 1;
                    guideline.UseLayoutRounding = true;
                    guideline.SnapsToDevicePixels = true;

                    switch (Resolution)
                    {
                        case TimeResolution.Century:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Year % (100 * MajorFrequency) == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime.AddYears(100);
                            break;

                        case TimeResolution.Decade:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Year % (10 * MajorFrequency) == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime.AddYears(10);
                            break;

                        case TimeResolution.Year:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Year % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime.AddYears(1);
                            break;

                        case TimeResolution.Month:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Month % MajorFrequency == 0 ? MajorBrush : MinorBrush;

                            try
                            {
                                guidelineTime = guidelineTime.AddMonths(1);
                            }
                            catch (Exception)
                            {
                                var month = guidelineTime.Month + 1;
                                var year = guidelineTime.Year;

                                if (month > 12)
                                {
                                    month -= 12;
                                    year++;
                                }

                                var day = ExtendedDateTimeCalculator.DaysInMonth(year, month);

                                guidelineTime = new ExtendedDateTime(year, month, day, guidelineTime.Hour, guidelineTime.Minute, guidelineTime.Second, guidelineTime.UtcOffset.Hours, guidelineTime.UtcOffset.Minutes);
                            }

                            break;

                        case TimeResolution.Day:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Day % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromDays(1);
                            break;

                        case TimeResolution.Hour:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Hour % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromHours(1);
                            break;

                        case TimeResolution.Minute:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Minute % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromMinutes(1);
                            break;

                        case TimeResolution.Second:
                            _lineOffsets.Add(guidelineIndex, Ruler.ToPixels(viewportLeftTime, guidelineTime));
                            guideline.Stroke = guidelineTime.Second % MajorFrequency == 0 ? MajorBrush : MinorBrush;
                            guidelineTime = guidelineTime + TimeSpan.FromSeconds(1);
                            break;

                        default:
                            break;
                    }

                    Children.Add(guideline);
                    guideline.Measure(availableSize);

                    guidelineIndex++;
                }

                _hasViewChanged = false;

                return availableSize;
            }

            foreach (UIElement child in Children)
            {
                child.Measure(availableSize);
            }

            return availableSize;
        }