Пример #1
0
        /// <summary>
        /// Multiplies the duration by a fixed number.
        /// </summary>
        /// <param name="duration">The duration to be multiplied.</param>
        /// <param name="multiplier">The fixed number to multiply the duration.</param>
        /// <returns>The resulting <see cref="GedcomxDateDuration"/> after multiplying the specified duration by the fixed number.</returns>
        /// <exception cref="Gedcomx.Date.GedcomxDateException">
        /// Thrown if the duration is null
        /// or
        /// Thrown if the multiplier is negative or zero.
        /// </exception>
        public static GedcomxDateDuration MultiplyDuration(GedcomxDateDuration duration, int multiplier)
        {
            if (duration == null)
            {
                throw new GedcomxDateException("Invalid Duration");
            }

            if (multiplier <= 0)
            {
                throw new GedcomxDateException("Invalid Multiplier");
            }

            StringBuilder newDuration = new StringBuilder("P");

            if (duration.Years != null)
            {
                newDuration.Append(duration.Years * multiplier).Append('Y');
            }

            if (duration.Months != null)
            {
                newDuration.Append(duration.Months * multiplier).Append('M');
            }

            if (duration.Days != null)
            {
                newDuration.Append(duration.Days * multiplier).Append('D');
            }

            if (duration.Hours != null || duration.Minutes != null || duration.Seconds != null)
            {
                newDuration.Append('T');

                if (duration.Hours != null)
                {
                    newDuration.Append(duration.Hours * multiplier).Append('H');
                }

                if (duration.Minutes != null)
                {
                    newDuration.Append(duration.Minutes * multiplier).Append('M');
                }

                if (duration.Seconds != null)
                {
                    newDuration.Append(duration.Seconds * multiplier).Append('S');
                }
            }

            return(new GedcomxDateDuration(newDuration.ToString()));
        }
Пример #2
0
        /// <summary>
        /// Gets the nth instance of this recurring date.
        /// </summary>
        /// <param name="count">The nth instance to retrieve.</param>
        /// <returns>The simple date of the nth instance.</returns>
        public GedcomxDateSimple GetNth(Int32 count)
        {
            GedcomxDateDuration duration = GedcomxDateUtil.MultiplyDuration(range.Duration, count);

            return(GedcomxDateUtil.AddDuration(range.Start, duration));
        }
Пример #3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="GedcomxDateRange"/> class.
        /// </summary>
        /// <param name="date">The formal date string that describes a GEDCOM X date range.</param>
        /// <exception cref="Gedcomx.Date.GedcomxDateException">
        /// Thrown if the formal date is null, empty, or does not meet the expected format.
        /// </exception>
        public GedcomxDateRange(String date)
        {

            if (date == null || date.Length < 1)
            {
                throw new GedcomxDateException("Invalid Range");
            }

            String range = date;

            // If range starts with A it is recurring
            if (date[0] == 'A')
            {
                approximate = true;
                range = date.Substring(1);
            }

            // / is required
            if (!date.Contains("/"))
            {
                throw new GedcomxDateException("Invalid Range: / is required");
            }

            /*
             * range -> parts
             * / -> []
             * +1000/ -> ["+1000"]
             * /+1000 -> ["","+1000"]
             * +1000/+2000 -> ["+1000","+2000"]
             */
            String[] parts = range.Split('/');

            if (parts.Length < 1 || parts.Length > 2)
            {
                throw new GedcomxDateException("Invalid Range: One or two parts are required");
            }

            if (!parts[0].Equals(""))
            {
                try
                {
                    start = new GedcomxDateSimple(parts[0]);
                }
                catch (GedcomxDateException e)
                {
                    throw new GedcomxDateException(e.Message + " in Range Start Date");
                }
            }

            if (parts.Length == 2)
            {
                if (parts[1][0] == 'P')
                {
                    if (start == null)
                    {
                        throw new GedcomxDateException("Invalid Range: A range may not end with a duration if missing a start date");
                    }
                    try
                    {
                        duration = new GedcomxDateDuration(parts[1]);
                    }
                    catch (GedcomxDateException e)
                    {
                        throw new GedcomxDateException(e.Message + " in Range End Duration");
                    }
                    // Use the duration to calculate the end date
                    end = GedcomxDateUtil.AddDuration(start, duration);
                }
                else
                {
                    try
                    {
                        end = new GedcomxDateSimple(parts[1]);
                    }
                    catch (GedcomxDateException e)
                    {
                        throw new GedcomxDateException(e.Message + " in Range End Date");
                    }
                    if (start != null)
                    {
                        duration = GedcomxDateUtil.GetDuration(start, end);
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="GedcomxDateRange"/> class.
        /// </summary>
        /// <param name="date">The formal date string that describes a GEDCOM X date range.</param>
        /// <exception cref="Gedcomx.Date.GedcomxDateException">
        /// Thrown if the formal date is null, empty, or does not meet the expected format.
        /// </exception>
        public GedcomxDateRange(String date)
        {
            if (date == null || date.Length < 1)
            {
                throw new GedcomxDateException("Invalid Range");
            }

            String range = date;

            // If range starts with A it is recurring
            if (date[0] == 'A')
            {
                approximate = true;
                range       = date.Substring(1);
            }

            // / is required
            if (!date.Contains("/"))
            {
                throw new GedcomxDateException("Invalid Range: / is required");
            }

            /*
             * range -> parts
             * / -> []
             * +1000/ -> ["+1000"]
             * /+1000 -> ["","+1000"]
             * +1000/+2000 -> ["+1000","+2000"]
             */
            String[] parts = range.Split('/');

            if (parts.Length < 1 || parts.Length > 2)
            {
                throw new GedcomxDateException("Invalid Range: One or two parts are required");
            }

            if (!parts[0].Equals(""))
            {
                try
                {
                    start = new GedcomxDateSimple(parts[0]);
                }
                catch (GedcomxDateException e)
                {
                    throw new GedcomxDateException(e.Message + " in Range Start Date");
                }
            }

            if (parts.Length == 2)
            {
                if (parts[1][0] == 'P')
                {
                    if (start == null)
                    {
                        throw new GedcomxDateException("Invalid Range: A range may not end with a duration if missing a start date");
                    }
                    try
                    {
                        duration = new GedcomxDateDuration(parts[1]);
                    }
                    catch (GedcomxDateException e)
                    {
                        throw new GedcomxDateException(e.Message + " in Range End Duration");
                    }
                    // Use the duration to calculate the end date
                    end = GedcomxDateUtil.AddDuration(start, duration);
                }
                else
                {
                    try
                    {
                        end = new GedcomxDateSimple(parts[1]);
                    }
                    catch (GedcomxDateException e)
                    {
                        throw new GedcomxDateException(e.Message + " in Range End Date");
                    }
                    if (start != null)
                    {
                        duration = GedcomxDateUtil.GetDuration(start, end);
                    }
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Ensures the specified date has matching attributes based off the duration attributes. See remarks for more information.
        /// </summary>
        /// <param name="date">The date to evaluate.</param>
        /// <param name="duration">The duration to use for evaluation.</param>
        /// <remarks>
        /// If the specified duration has minutes and the specified date does not, this will initialize the minutes on
        /// the specified date.
        /// 
        /// Furthermore, for the level of granularity specified in the duration (e.g., down to the minute but not second),
        /// this method ensures the specified date has the same level of granularity and greater. So if the specified duration
        /// has minutes set, but the specified date does not have minutes or some greater unit not set, this will initialize
        /// the minutes on the specified date and all other levels of granularity greater than minutes. Thus hours would be set
        /// if not already, and so on. It's important to note, however, that just like <see cref="ZipDates"/>, this method will
        /// not initialize any unit for which a value is already set.
        /// 
        /// Note: This method only writes to the specified date, and only reads the duration.
        /// </remarks>
        protected static void ZipDuration(Date date, GedcomxDateDuration duration)
        {
            bool seconds = false;
            bool minutes = false;
            bool hours = false;
            bool days = false;
            bool months = false;

            if (duration.Seconds != null)
            {
                seconds = true;
                minutes = true;
                hours = true;
                days = true;
                months = true;
            }
            else if (duration.Minutes != null)
            {
                minutes = true;
                hours = true;
                days = true;
                months = true;
            }
            else if (duration.Hours != null)
            {
                hours = true;
                days = true;
                months = true;
            }
            else if (duration.Days != null)
            {
                days = true;
                months = true;
            }
            else if (duration.Months != null)
            {
                months = true;
            }
            else
            {
                return;
            }

            if (seconds && date.seconds == null)
            {
                date.seconds = 0;
            }

            if (minutes && date.minutes == null)
            {
                date.minutes = 0;
            }

            if (hours && date.hours == null)
            {
                date.hours = 0;
            }

            if (days && date.day == null)
            {
                date.day = 1;
            }

            if (months && date.month == null)
            {
                date.month = 1;
            }
        }
Пример #6
0
        /// <summary>
        /// Multiplies the duration by a fixed number.
        /// </summary>
        /// <param name="duration">The duration to be multiplied.</param>
        /// <param name="multiplier">The fixed number to multiply the duration.</param>
        /// <returns>The resulting <see cref="GedcomxDateDuration"/> after multiplying the specified duration by the fixed number.</returns>
        /// <exception cref="Gedcomx.Date.GedcomxDateException">
        /// Thrown if the duration is null
        /// or
        /// Thrown if the multiplier is negative or zero.
        /// </exception>
        public static GedcomxDateDuration MultiplyDuration(GedcomxDateDuration duration, int multiplier)
        {

            if (duration == null)
            {
                throw new GedcomxDateException("Invalid Duration");
            }

            if (multiplier <= 0)
            {
                throw new GedcomxDateException("Invalid Multiplier");
            }

            StringBuilder newDuration = new StringBuilder("P");

            if (duration.Years != null)
            {
                newDuration.Append(duration.Years * multiplier).Append('Y');
            }

            if (duration.Months != null)
            {
                newDuration.Append(duration.Months * multiplier).Append('M');
            }

            if (duration.Days != null)
            {
                newDuration.Append(duration.Days * multiplier).Append('D');
            }

            if (duration.Hours != null || duration.Minutes != null || duration.Seconds != null)
            {
                newDuration.Append('T');

                if (duration.Hours != null)
                {
                    newDuration.Append(duration.Hours * multiplier).Append('H');
                }

                if (duration.Minutes != null)
                {
                    newDuration.Append(duration.Minutes * multiplier).Append('M');
                }

                if (duration.Seconds != null)
                {
                    newDuration.Append(duration.Seconds * multiplier).Append('S');
                }

            }

            return new GedcomxDateDuration(newDuration.ToString());
        }
Пример #7
0
        /// <summary>
        /// Adds a duration to the specified simple date and returns the resulting simple date.
        /// </summary>
        /// <param name="startDate">The start date that will have the specified duration added.</param>
        /// <param name="duration">The duration to add to the specified simple date.</param>
        /// <returns>The <see cref="GedcomxDateSimple"/> date resulting from adding the duration to the specified date. </returns>
        /// <exception cref="Gedcomx.Date.GedcomxDateException">
        /// Throw if the start date is null
        /// or
        /// Thrown if the duration is null
        /// or
        /// Thrown if the resulting end year is beyond 9999.
        /// </exception>
        public static GedcomxDateSimple AddDuration(GedcomxDateSimple startDate, GedcomxDateDuration duration)
        {

            if (startDate == null)
            {
                throw new GedcomxDateException("Invalid Start Date");
            }

            if (duration == null)
            {
                throw new GedcomxDateException("Invalid Duration");
            }

            Date end = new Date(startDate, false);
            StringBuilder endString = new StringBuilder();

            // Initialize all the values we need in end based on the duration
            ZipDuration(end, duration);

            // Add Timezone offset to endString
            if (startDate.TzHours != null)
            {
                endString.Append(startDate.TzHours >= 0 ? "+" : "-").Append(String.Format("{0:00}", Math.Abs(startDate.TzHours.Value)));
                endString.Append(":").Append(String.Format("{0:00}", startDate.TzMinutes));
            }

            if (end.seconds != null)
            {
                if (duration.Seconds != null)
                {
                    end.seconds += duration.Seconds;
                }
                while (end.seconds >= 60)
                {
                    end.seconds -= 60;
                    end.minutes += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.seconds)).Insert(0, ":");
            }

            if (end.minutes != null)
            {
                if (duration.Minutes != null)
                {
                    end.minutes += duration.Minutes;
                }
                while (end.minutes >= 60)
                {
                    end.minutes -= 60;
                    end.hours += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.minutes)).Insert(0, ":");
            }

            if (end.hours != null)
            {
                if (duration.Hours != null)
                {
                    end.hours += duration.Hours;
                }
                while (end.hours >= 24)
                {
                    end.hours -= 24;
                    end.day += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.hours)).Insert(0, "T");
            }

            if (end.day != null)
            {
                if (duration.Days != null)
                {
                    end.day += duration.Days;
                }
                while (end.day >= DateTime.DaysInMonth(end.year.Value, end.month.Value))
                {
                    end.month += 1;
                    if (end.month > 12)
                    {
                        end.month -= 12;
                        end.year += 1;
                    }
                    end.day -= DateTime.DaysInMonth(end.year.Value, end.month.Value);
                }
                endString.Insert(0, String.Format("{0:00}", end.day)).Insert(0, "-");
            }

            if (end.month != null)
            {
                if (duration.Months != null)
                {
                    end.month += duration.Months;
                }
                while (end.month > 12)
                {
                    end.month -= 12;
                    end.year += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.month)).Insert(0, "-");
            }

            if (duration.Years != null)
            {
                end.year += duration.Years;
            }

            // After adding months to this year we could have bumped into or out of a non leap year
            // TODO fix this

            if (end.year > 9999)
            {
                throw new GedcomxDateException("New date out of range");
            }

            if (end.year != null)
            {
                endString.Insert(0, String.Format("%04d", Math.Abs(end.year.Value))).Insert(0, end.year >= 0 ? "+" : "-");
            }

            return new GedcomxDateSimple(endString.ToString());
        }
Пример #8
0
        /// <summary>
        /// Ensures the specified date has matching attributes based off the duration attributes. See remarks for more information.
        /// </summary>
        /// <param name="date">The date to evaluate.</param>
        /// <param name="duration">The duration to use for evaluation.</param>
        /// <remarks>
        /// If the specified duration has minutes and the specified date does not, this will initialize the minutes on
        /// the specified date.
        ///
        /// Furthermore, for the level of granularity specified in the duration (e.g., down to the minute but not second),
        /// this method ensures the specified date has the same level of granularity and greater. So if the specified duration
        /// has minutes set, but the specified date does not have minutes or some greater unit not set, this will initialize
        /// the minutes on the specified date and all other levels of granularity greater than minutes. Thus hours would be set
        /// if not already, and so on. It's important to note, however, that just like <see cref="ZipDates"/>, this method will
        /// not initialize any unit for which a value is already set.
        ///
        /// Note: This method only writes to the specified date, and only reads the duration.
        /// </remarks>
        protected static void ZipDuration(Date date, GedcomxDateDuration duration)
        {
            bool seconds = false;
            bool minutes = false;
            bool hours   = false;
            bool days    = false;
            bool months  = false;

            if (duration.Seconds != null)
            {
                seconds = true;
                minutes = true;
                hours   = true;
                days    = true;
                months  = true;
            }
            else if (duration.Minutes != null)
            {
                minutes = true;
                hours   = true;
                days    = true;
                months  = true;
            }
            else if (duration.Hours != null)
            {
                hours  = true;
                days   = true;
                months = true;
            }
            else if (duration.Days != null)
            {
                days   = true;
                months = true;
            }
            else if (duration.Months != null)
            {
                months = true;
            }
            else
            {
                return;
            }

            if (seconds && date.seconds == null)
            {
                date.seconds = 0;
            }

            if (minutes && date.minutes == null)
            {
                date.minutes = 0;
            }

            if (hours && date.hours == null)
            {
                date.hours = 0;
            }

            if (days && date.day == null)
            {
                date.day = 1;
            }

            if (months && date.month == null)
            {
                date.month = 1;
            }
        }
Пример #9
0
        /// <summary>
        /// Adds a duration to the specified simple date and returns the resulting simple date.
        /// </summary>
        /// <param name="startDate">The start date that will have the specified duration added.</param>
        /// <param name="duration">The duration to add to the specified simple date.</param>
        /// <returns>The <see cref="GedcomxDateSimple"/> date resulting from adding the duration to the specified date. </returns>
        /// <exception cref="Gedcomx.Date.GedcomxDateException">
        /// Throw if the start date is null
        /// or
        /// Thrown if the duration is null
        /// or
        /// Thrown if the resulting end year is beyond 9999.
        /// </exception>
        public static GedcomxDateSimple AddDuration(GedcomxDateSimple startDate, GedcomxDateDuration duration)
        {
            if (startDate == null)
            {
                throw new GedcomxDateException("Invalid Start Date");
            }

            if (duration == null)
            {
                throw new GedcomxDateException("Invalid Duration");
            }

            Date          end       = new Date(startDate, false);
            StringBuilder endString = new StringBuilder();

            // Initialize all the values we need in end based on the duration
            ZipDuration(end, duration);

            // Add Timezone offset to endString
            if (startDate.TzHours != null)
            {
                endString.Append(startDate.TzHours >= 0 ? "+" : "-").Append(String.Format("{0:00}", Math.Abs(startDate.TzHours.Value)));
                endString.Append(":").Append(String.Format("{0:00}", startDate.TzMinutes));
            }

            if (end.seconds != null)
            {
                if (duration.Seconds != null)
                {
                    end.seconds += duration.Seconds;
                }
                while (end.seconds >= 60)
                {
                    end.seconds -= 60;
                    end.minutes += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.seconds)).Insert(0, ":");
            }

            if (end.minutes != null)
            {
                if (duration.Minutes != null)
                {
                    end.minutes += duration.Minutes;
                }
                while (end.minutes >= 60)
                {
                    end.minutes -= 60;
                    end.hours   += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.minutes)).Insert(0, ":");
            }

            if (end.hours != null)
            {
                if (duration.Hours != null)
                {
                    end.hours += duration.Hours;
                }
                while (end.hours >= 24)
                {
                    end.hours -= 24;
                    end.day   += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.hours)).Insert(0, "T");
            }

            if (end.day != null)
            {
                if (duration.Days != null)
                {
                    end.day += duration.Days;
                }
                while (end.day >= DateTime.DaysInMonth(end.year.Value, end.month.Value))
                {
                    end.month += 1;
                    if (end.month > 12)
                    {
                        end.month -= 12;
                        end.year  += 1;
                    }
                    end.day -= DateTime.DaysInMonth(end.year.Value, end.month.Value);
                }
                endString.Insert(0, String.Format("{0:00}", end.day)).Insert(0, "-");
            }

            if (end.month != null)
            {
                if (duration.Months != null)
                {
                    end.month += duration.Months;
                }
                while (end.month > 12)
                {
                    end.month -= 12;
                    end.year  += 1;
                }
                endString.Insert(0, String.Format("{0:00}", end.month)).Insert(0, "-");
            }

            if (duration.Years != null)
            {
                end.year += duration.Years;
            }

            // After adding months to this year we could have bumped into or out of a non leap year
            // TODO fix this

            if (end.year > 9999)
            {
                throw new GedcomxDateException("New date out of range");
            }

            if (end.year != null)
            {
                endString.Insert(0, String.Format("%04d", Math.Abs(end.year.Value))).Insert(0, end.year >= 0 ? "+" : "-");
            }

            return(new GedcomxDateSimple(endString.ToString()));
        }