Example #1
0
 public void CanRoundTrip()
 {
     Assert.AreEqual("[1667,1668,1670..1672]", ExtendedDateTimePossibilityCollection.Parse("[1667,1668,1670..1672]").ToString());
     Assert.AreEqual("[..1760-12-03]", ExtendedDateTimePossibilityCollection.Parse("[..1760-12-03]").ToString());
     Assert.AreEqual("[1760-12..]", ExtendedDateTimePossibilityCollection.Parse("[1760-12..]").ToString());
     Assert.AreEqual("[1760-01,1760-02,1760-12..]", ExtendedDateTimePossibilityCollection.Parse("[1760-01,1760-02,1760-12..]").ToString());
     Assert.AreEqual("[1667,1760-12]", ExtendedDateTimePossibilityCollection.Parse("[1667,1760-12]").ToString());
 }
Example #2
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(ExtendedDateTimePossibilityCollection.Parse(source));
            }

            return(base.ConvertFrom(context, culture, value));
        }
Example #3
0
        internal static string Serialize(ExtendedDateTimePossibilityCollection extendedDateTimePossibilityCollection)
        {
            var stringBuilder = new StringBuilder();

            stringBuilder.Append('[');

            for (int i = 0; i < extendedDateTimePossibilityCollection.Count; i++)
            {
                stringBuilder.Append(extendedDateTimePossibilityCollection[i].ToString());

                if (i != extendedDateTimePossibilityCollection.Count - 1)                              // Don't put comma after last element.
                {
                    stringBuilder.Append(",");
                }
            }

            stringBuilder.Append(']');

            return(stringBuilder.ToString());
        }
Example #4
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);
        }
        internal static ExtendedDateTimePossibilityCollection Parse(string extendedDateTimePossibilityCollectionString, ExtendedDateTimePossibilityCollection possibilityCollection = null)
        {
            if (string.IsNullOrWhiteSpace(extendedDateTimePossibilityCollectionString))
            {
                return(null);
            }

            var hasStartBrace = extendedDateTimePossibilityCollectionString[0] == '[';
            var hasEndBrace   = extendedDateTimePossibilityCollectionString[extendedDateTimePossibilityCollectionString.Length - 1] == ']';

            if (!hasStartBrace || !hasEndBrace)
            {
                throw new ParseException("A possibility collection string must be surrounded by square brackets.", extendedDateTimePossibilityCollectionString);
            }

            var contentsString   = extendedDateTimePossibilityCollectionString.Substring(1, extendedDateTimePossibilityCollectionString.Length - 2);
            var closingChar      = (char?)null;
            var setRanges        = new Dictionary <int, int>();     // A dictionary of indexes where sets begin and end within the contents string.
            var setStartingIndex = (int?)null;

            for (int i = 0; i < contentsString.Length; i++)         // Locate nested sets.
            {
                if (contentsString[i] == '{' && setStartingIndex == null)
                {
                    closingChar = '}';

                    setStartingIndex = i;
                }
                else if (contentsString[i] == '[' && setStartingIndex == null)
                {
                    closingChar = ']';

                    setStartingIndex = i;
                }
                else if (contentsString[i] == closingChar && setStartingIndex != null)
                {
                    setRanges.Add(setStartingIndex.Value, i);

                    setStartingIndex = null;
                }
            }

            var currentSetRangeIndex = 0;
            var remainingChars       = new List <char>();

            if (possibilityCollection == null)
            {
                possibilityCollection = new ExtendedDateTimePossibilityCollection();
            }

            for (int i = 0; i < contentsString.Length; i++)                                     // Add set contents, including nested sets.
            {
                if (setRanges.Count > currentSetRangeIndex && i == setRanges.Keys.ElementAt(currentSetRangeIndex))
                {
                    var preceedingElementsString = new string(remainingChars.ToArray());        // Add elements preceeding the nested set.

                    var preceedingElementStrings = preceedingElementsString.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (var preceedingElementString in preceedingElementStrings)
                    {
                        if (preceedingElementString.Contains(".."))
                        {
                            possibilityCollection.Add((IExtendedDateTimeCollectionChild)ExtendedDateTimeRangeParser.Parse(preceedingElementString));
                        }
                        else
                        {
                            possibilityCollection.Add((IExtendedDateTimeCollectionChild)ExtendedDateTimeParser.Parse(preceedingElementString));
                        }
                    }

                    remainingChars.Clear();

                    var setString = contentsString.Substring(i, setRanges[i] - i);      // Add nested set.

                    if (setString[0] == '{')
                    {
                        possibilityCollection.Add((IExtendedDateTimeCollectionChild)ExtendedDateTimeCollectionParser.Parse(setString));
                    }
                    else
                    {
                        possibilityCollection.Add((IExtendedDateTimeCollectionChild)ExtendedDateTimePossibilityCollectionParser.Parse(setString));
                    }

                    i = setRanges[i];
                    currentSetRangeIndex++;
                }
                else
                {
                    remainingChars.Add(contentsString[i]);
                }
            }

            var remainingElementsString = new string(remainingChars.ToArray());        // Add all elements that remain.

            var remainingElementStrings = remainingElementsString.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var remainingElementString in remainingElementStrings)
            {
                if (remainingElementString.Contains(".."))
                {
                    possibilityCollection.Add((IExtendedDateTimeCollectionChild)ExtendedDateTimeRangeParser.Parse(remainingElementString));
                }
                else
                {
                    possibilityCollection.Add((IExtendedDateTimeCollectionChild)ExtendedDateTimeParser.Parse(remainingElementString));
                }
            }

            return(possibilityCollection);
        }
Example #6
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);
        }