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()); }
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)); }
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()); }
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); }
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); }