Пример #1
0
        /// <summary>
        /// This method is used to calculate the date on which a floating day occurs (for example, the 4th
        /// Thursday in November).
        /// </summary>
        /// <param name="year">The year in which the day occurs.</param>
        /// <param name="month">The month in which the day occurs.</param>
        /// <param name="occur">The occurrence of the day of the week on which the day falls.</param>
        /// <param name="dowDay">The day of the week on which the day occurs.</param>
        /// <param name="offset">The number of days before or after the calculated date on which the day actually
        /// falls.</param>
        /// <returns>Returns a <see cref="DateTime" /> object that represents the date calculated from the
        /// settings.</returns>
        /// <remarks><para>Use a positive value for the <c>nOffset</c> parameter for a number of days after the
        /// calculated date or a negative number for a number of days before the calculated date.</para>
        ///
        /// <para>Normally, this value will be zero so that the calculated date is the actual date returned.
        /// However, in cases where a date is calculated in terms of the number of days before or after a given
        /// date, this can be set to the offset to adjust the calculated date.</para>
        ///
        /// <para>For example, to calculate the day after Thanksgiving, the value of this parameter would be set
        /// to 1 (one day after Thanksgiving, which is the 4th Thursday in November). You cannot use the 4th
        /// Friday to calculate the date because if the month starts on a Friday, the calculated date would be a
        /// week too early. As such, the <c>nOffset</c> parameter is used instead.</para></remarks>
        /// <example>
        /// <code language="cs">
        /// // Returns 11/28/2002 (Thanksgiving)
        /// dtThanksgiving = DateUtils.CalculateFloatingDate(2002, 11,
        ///     DayOccurrence.Fourth, DayOfWeek.Thursday, 0);
        ///
        /// // Returns 11/29/2002 (Day after Thanksgiving)
        /// dtDayAfterTG = DateUtils.CalculateFloatingDate(2002, 11,
        ///     DayOccurrence.Fourth, DayOfWeek.Thursday, 1);
        ///
        /// // Returns 11/22/2002 (Fourth Friday isn't after the fourth
        /// // Thursday in 2002 hence the use of the nOffset parameter
        /// // in the call above).
        /// dtFourthFri = DateUtils.CalculateFloatingDate(2002, 11,
        ///     DayOccurrence.Fourth, DayOfWeek.Friday, 0);
        /// </code>
        /// <code language="vbnet">
        /// ' Returns 11/28/2002 (Thanksgiving)
        /// dtThanksgiving = DateUtils.CalculateFloatingDate(2002, 11,
        ///     DayOccurrence.Fourth, DayOfWeek.Thursday, 0)
        ///
        /// ' Returns 11/29/2002 (Day after Thanksgiving)
        /// dtDayAfterTG = DateUtils.CalculateFloatingDate(2002, 11,
        ///     DayOccurrence.Fourth, DayOfWeek.Thursday, 1)
        ///
        /// ' Returns 11/22/2002 (Fourth Friday isn't after the fourth
        /// ' Thursday in 2002 hence the use of the nOffset parameter
        /// ' in the call above).
        /// dtFourthFri = DateUtils.CalculateFloatingDate(2002, 11,
        ///     DayOccurrence.Fourth, DayOfWeek.Friday, 0)
        /// </code>
        /// </example>
        /// <exception cref="ArgumentException">This is thrown if <c>None</c> is passed for the <c>DayOccurrence</c>
        /// parameter.</exception>
        public static DateTime CalculateFloatingDate(int year, int month, DayOccurrence occur,
                                                     System.DayOfWeek dowDay, int offset)
        {
            DateTime dtDate;

            if (occur == DayOccurrence.None)
            {
                throw new ArgumentException(LR.GetString("ExDUOccurIsNone"), nameof(occur));
            }

            // Calculating a specific occurrence or the last one?
            if (occur != DayOccurrence.Last)
            {
                // Specific occurrence
                dtDate = new DateTime(year, month, 1);
                dtDate = dtDate.AddDays((((int)dowDay + 7 - (int)dtDate.DayOfWeek) % 7) + (((int)occur - 1) * 7));
            }
            else
            {
                // Get the last occurrence of the month
                dtDate = new DateTime(year, month, DateTime.DaysInMonth(year, month));
                dtDate = dtDate.AddDays(0 - (((int)dtDate.DayOfWeek + 7 - (int)dowDay) % 7));
            }

            // Return the date plus any additional offset
            return(dtDate.AddDays(offset));
        }
Пример #2
0
        /// <summary>
        /// Insert an integer into the collection
        /// </summary>
        /// <param name="index">The index at which to insert the integer</param>
        /// <param name="item">The integer to insert</param>
        /// <remarks>If the integer already exists in the collection, it will be moved to the new position</remarks>
        /// <exception cref="ArgumentOutOfRangeException">This is thrown if the value is less than
        /// <see cref="MinimumValue"/> or greater than <see cref="MaximumValue"/>.</exception>
        /// <exception cref="ArgumentException">This is thrown if the value is zero and zeros are not allowed in
        /// the collection.</exception>
        protected override void InsertItem(int index, int item)
        {
            if (item < this.MinimumValue || item > this.MaximumValue)
            {
                throw new ArgumentOutOfRangeException(nameof(item), item, LR.GetString("ExUICValueOutOfRange"));
            }

            if (item == 0 && !this.AllowZero)
            {
                throw new ArgumentException(LR.GetString("ExUICZerosNotAllowed"), nameof(item));
            }

            int curIdx = base.IndexOf(item);

            if (curIdx == -1)
            {
                base.InsertItem(index, item);
            }
            else
            if (index != curIdx)
            {
                base.RemoveAt(curIdx);

                if (index > base.Count)
                {
                    base.InsertItem(base.Count, item);
                }
                else
                {
                    base.InsertItem(index, item);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Construct a period from a string in ISO 8601 period format
        /// </summary>
        /// <param name="period">The ISO 8601 formatted period to parse</param>
        /// <remarks>This parses a string in the form <c>[dateTime]/[dateTime]</c> or <c>[dateTime]/[duration]</c>
        /// to create a period.  The <c>[dateTime]</c> part(s) should be ISO 8601 formatted date/time values (see
        /// <see cref="DateUtils.FromISO8601String"/>).  The <c>[duration]</c> part should be an ISO 8601
        /// formatted duration value (see <see cref="PDI.Duration"/>).  The period format is set based on the
        /// format of the string received.</remarks>
        /// <exception cref="ArgumentException">This is thrown if the specified period string or any of its parts
        /// are not valid.</exception>
        public Period(string period)
        {
            if (String.IsNullOrEmpty(period))
            {
                this.StartDateTime = DateTime.MinValue;
                this.Duration      = Duration.Zero;
                this.Format        = PeriodFormat.StartDuration;
                return;
            }

            string[] parts = period.Split('/');

            if (parts.Length != 2)
            {
                throw new ArgumentException(LR.GetString("ExPeriodInvalidISOFormat"), "period");
            }

            this.StartDateTime = DateUtils.FromISO8601String(parts[0], true);

            if (!Char.IsDigit(parts[1][0]))
            {
                this.Duration = new Duration(parts[1]);
                this.Format   = PeriodFormat.StartDuration;
            }
            else
            {
                this.EndDateTime = DateUtils.FromISO8601String(parts[1], true);
                this.Format      = PeriodFormat.StartEnd;
            }
        }
Пример #4
0
        /// <summary>
        /// Insert an integer into the collection
        /// </summary>
        /// <param name="index">The index at which to insert the integer</param>
        /// <param name="item">The integer to insert</param>
        /// <remarks>If the integer already exists in the collection, it will be moved to the new position</remarks>
        /// <exception cref="ArgumentOutOfRangeException">This is thrown if the value is less than
        /// <see cref="MinimumValue"/> or greater than <see cref="MaximumValue"/>.</exception>
        /// <exception cref="ArgumentException">This is thrown if the value is zero and zeros are not allowed in
        /// the collection.</exception>
        protected override void InsertItem(int index, int item)
        {
            if (item < minValue || item > maxValue)
            {
                throw new ArgumentOutOfRangeException("item", item, LR.GetString("ExUICValueOutOfRange"));
            }

            if (item == 0 && !allowZero)
            {
                throw new ArgumentException(LR.GetString("ExUICZerosNotAllowed"), "item");
            }

            int curIdx = base.IndexOf(item);

            if (curIdx == -1)
            {
                base.InsertItem(index, item);
            }
            else
            if (index != curIdx)
            {
                base.RemoveAt(curIdx);

                if (index > base.Count)
                {
                    base.InsertItem(base.Count, item);
                }
                else
                {
                    base.InsertItem(index, item);
                }
            }
        }
Пример #5
0
        //=====================================================================

        /// <summary>
        /// Compares this instance to a specified object and returns an indication of their relative values
        /// </summary>
        /// <param name="obj">A Duration object to compare</param>
        /// <returns>Returns -1 if this instance is less than the value, 0 if they are equal, or 1 if this
        /// instance is greater than the value or the value is null.</returns>
        /// <exception cref="ArgumentException">This is thrown if the object to be compared is not a Duration</exception>
        public int CompareTo(object obj)
        {
            if (!(obj is Duration))
            {
                throw new ArgumentException(LR.GetString("ExDurBadCompareObject"));
            }

            return(Duration.Compare(this, (Duration)obj));
        }
Пример #6
0
        /// <summary>
        /// Convert the instance to a <see cref="System.DateTime"/> object
        /// </summary>
        /// <returns>Returns the instance as a date/time</returns>
        /// <exception cref="InvalidOperationException">This is thrown if the date is not valid</exception>
        public DateTime ToDateTime()
        {
            if (!this.IsValidDate())
            {
                throw new InvalidOperationException(LR.GetString("ExRDTInvalidDateTime"));
            }

            return(new DateTime(year, month + 1, day, hour, minute, second));
        }
Пример #7
0
        //=====================================================================

        /// <summary>
        /// Compares this instance to a specified object and returns an indication of their relative values
        /// </summary>
        /// <param name="obj">An object to compare or null</param>
        /// <returns>Returns -1 if this instance is less than the value, 0 if they are equal, or 1 if this
        /// instance is greater than the value or the value is null.</returns>
        /// <exception cref="ArgumentException">This is thrown if the object to be compared is not a
        /// <c>Period</c>.</exception>
        public int CompareTo(object obj)
        {
            Period p = obj as Period;

            if (p == null)
            {
                throw new ArgumentException(LR.GetString("ExPeriodBadCompareObject"));
            }

            return(Period.Compare(this, p));
        }
Пример #8
0
        //=====================================================================

        /// <summary>
        /// Compares this instance to a specified object and returns an indication of their relative values
        /// </summary>
        /// <param name="obj">An object to compare or null</param>
        /// <returns>Returns -1 if this instance is less than the value, 0 if they are equal, or 1 if this
        /// instance is greater than the value or the value is null.</returns>
        /// <exception cref="ArgumentException">This is thrown if the object to be compared is not a
        /// <c>RecurDateTime</c>.</exception>
        public int CompareTo(object obj)
        {
            RecurDateTime rd = obj as RecurDateTime;

            if (rd == null)
            {
                throw new ArgumentException(LR.GetString("ExRDTBadCompareObject"));
            }

            return(RecurDateTime.Compare(this, rd));
        }
Пример #9
0
        /// <summary>
        /// This method returns a date calculated from a year, a week number, and the day on which weeks start
        /// </summary>
        /// <param name="year">The year containing the week</param>
        /// <param name="week">The week of the year</param>
        /// <param name="dow">The day on which a week starts</param>
        /// <param name="offset">An additional offset in days to add to the week start date</param>
        /// <returns>Returns the calculated date.</returns>
        /// <remarks><para>A week is defined as a seven day period starting on the specified day of the week.
        /// The first week of the year is defined as the one starting on the specified day of the week and
        /// containing at least four days of the year.</para>
        ///
        /// <para>If the year starts on a day of the week later than the one specified, this may return a date a
        /// few days earlier than January 1st of the specified year for week 1.</para>
        ///
        /// <para>Not all years will have a 53rd week.  For example, assuming a Monday week start, week 53 can
        /// only occur when Thursday is January 1st or if it is a leap year and Wednesday is January 1st.  It is
        /// up to the caller to determine this and discard the date.  <see cref="WeeksInYear"/> can be used to
        /// determine this condition.</para></remarks>
        /// <exception cref="ArgumentOutOfRangeException">An exception is thrown if the week value is not between
        /// 1 and 53.</exception>
        /// <example>
        /// <code language="cs">
        /// // Returns Monday 12/29/1997 because 01/01/1998 falls on a Thursday
        /// dtDate = DateUtils.DateFromWeek(1998, 1, DayOfWeek.Monday, 0);
        ///
        /// // Returns 08/27/2003
        /// dtDate = DateUtils.DateFromWeek(2003, 35, DayOfWeek.Wednesday, 0);
        /// </code>
        /// <code language="vbnet">
        /// ' Returns Monday 12/29/1997 because 01/01/1998 falls on a Thursday
        /// dtDate = DateUtils.DateFromWeek(1998, 1, DayOfWeek.Monday, 0)
        ///
        /// ' Returns 08/27/2003
        /// dtDate = DateUtils.DateFromWeek(2003, 35, DayOfWeek.Wednesday, 0)
        /// </code>
        /// </example>
        /// <seealso cref="WeeksInYear"/>
        /// <seealso cref="WeekFromDate"/>
        public static DateTime DateFromWeek(int year, int week, DayOfWeek dow, int offset)
        {
            DateTime dt;
            int      weekOffset;

            // Validate week number
            if (week < 1 || week > 53)
            {
                throw new ArgumentOutOfRangeException(nameof(week), week, LR.GetString("ExDUBadWeekNumber"));
            }

            // Bit of a hack but if you're looking for dates this far out, I'd like to know what the hell you're
            // doing.
            if (year > 9998)
            {
                year = 9999;
            }

            if (year == 9999 && week == 53)
            {
                week = 52;
            }

            // Find out the weekday of Jan 1st in the year
            dt = new DateTime(year, 1, 1);

            // Calculate the offset for the first full week
            weekOffset = ((int)dow + 7 - (int)dt.DayOfWeek) % 7;

            // Adjust it back a week if the prior week contains at least four days
            if (weekOffset >= 4)
            {
                weekOffset -= 7;
            }

            // Get the start of the week requested
            dt = dt.AddDays(weekOffset);

            if (week != 1)
            {
                dt = dt.AddDays(7 * (week - 1));
            }

            // Add in the additional offset if requested
            if (offset != 0)
            {
                dt = dt.AddDays(offset);
            }

            return(dt);
        }
Пример #10
0
        /// <summary>
        /// This method is used to see if an ISO 8601 formatted date string is in floating format (a universal
        /// time indicator or time zone offset is not specified).
        /// </summary>
        /// <param name="dateTimeText">The ISO 8601 formatted date to parse</param>
        /// <returns>Returns true if the date/time has no universal time indicator (Z) or time zone offset
        /// (+/-HHMM) or if it has no time (assumes midnight local time).  Returns false if there is a universal
        /// time indicator or a time zone offset.</returns>
        /// <exception cref="ArgumentException">This is thrown if the specified date/time string is not valid</exception>
        public static bool IsFloatingFormat(string dateTimeText)
        {
            Match m = reISO8601.Match(dateTimeText);

            if (!m.Success)
            {
                throw new ArgumentException(LR.GetString("ExDUBadISOFormat"), nameof(dateTimeText));
            }

            if (m.Groups["Zulu"].Value.Length != 0 || m.Groups["TZHours"].Value.Length != 0)
            {
                return(false);
            }

            return(true);
        }
Пример #11
0
        /// <summary>
        /// This adds a standard set of holidays to the collection
        /// </summary>
        /// <remarks><para>This adds a standard set of holidays to the collection that the author gets to take.
        /// If you do not get the same set, you can modify the collection after the call or derive a class and
        /// override this method to provide the set that you need.</para>
        ///
        /// <para>As an alternative, you could serialize a set of holidays to an XML file and load them from it
        /// instead.</para>
        ///
        /// <para>Fixed dates are set to be adjusted to not fall on a weekend.  The holidays added are as
        /// follows:</para>
        ///
        /// <list type="table">
        ///     <listheader>
        ///         <term>Holiday</term>
        ///         <description>Description</description>
        ///     </listheader>
        ///     <item>
        ///         <term>New Year's Day</term>
        ///         <description>January 1st</description>
        ///     </item>
        ///     <item>
        ///         <term>Martin Luther King Day</term>
        ///         <description>3rd Monday in January</description>
        ///     </item>
        ///     <item>
        ///         <term>President's Day</term>
        ///         <description>Third Monday in February</description>
        ///     </item>
        ///     <item>
        ///         <term>Memorial Day</term>
        ///         <description>Last Monday in May</description>
        ///     </item>
        ///     <item>
        ///         <term>Independence Day</term>
        ///         <description>July 4th</description>
        ///     </item>
        ///     <item>
        ///         <term>Labor Day</term>
        ///         <description>1st Monday in September</description>
        ///     </item>
        ///     <item>
        ///         <term>Veteran's Day</term>
        ///         <description>November 11th</description>
        ///     </item>
        ///     <item>
        ///         <term>Thanksgiving</term>
        ///         <description>4th Thursday in November</description>
        ///     </item>
        ///     <item>
        ///         <term>Day After Thanksgiving</term>
        ///         <description>1 day after 4th Thursday in November</description>
        ///     </item>
        ///     <item>
        ///         <term>Christmas Day</term>
        ///         <description>December 25th</description>
        ///     </item>
        /// </list>
        /// </remarks>
        /// <returns>A reference to the holiday collection</returns>
        public virtual HolidayCollection AddStandardHolidays()
        {
            this.AddRange(new Holiday[] {
                new FixedHoliday(1, 1, true, LR.GetString("HCNewYearsDay")),
                new FloatingHoliday(DayOccurrence.Third, DayOfWeek.Monday, 1, 0, LR.GetString("HCMLKDay")),
                new FloatingHoliday(DayOccurrence.Third, DayOfWeek.Monday, 2, 0, LR.GetString("HCPresidentsDay")),
                new FloatingHoliday(DayOccurrence.Last, DayOfWeek.Monday, 5, 0, LR.GetString("HCMemorialDay")),
                new FixedHoliday(7, 4, true, LR.GetString("HCIndependenceDay")),
                new FloatingHoliday(DayOccurrence.First, DayOfWeek.Monday, 9, 0, LR.GetString("HCLaborDay")),
                new FixedHoliday(11, 11, true, LR.GetString("HCVeteransDay")),
                new FloatingHoliday(DayOccurrence.Fourth, DayOfWeek.Thursday, 11, 0, LR.GetString("HCThanksgiving")),
                new FloatingHoliday(DayOccurrence.Fourth, DayOfWeek.Thursday, 11, 1, LR.GetString("HCDayAfterTG")),
                new FixedHoliday(12, 25, true, LR.GetString("HCChristmas"))
            });

            return(this);
        }
Пример #12
0
        /// <summary>
        /// Get a description of the day instance
        /// </summary>
        /// <returns>A string describing the day instance (i.e. 1st Monday from end).</returns>
        public string ToDescription()
        {
            string suffix = DayInstance.NumericSuffix(instance);

            if (instance == 0)
            {
                return(String.Format(CultureInfo.InvariantCulture, "{0} {1}", LR.GetString("DIAny"),
                                     CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int)dow]));
            }

            if (instance < 0)
            {
                return(String.Format(CultureInfo.InvariantCulture, "{0}{1} {2} {3}", instance * -1,
                                     suffix, CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int)dow],
                                     LR.GetString("DIFromEnd")));
            }

            return(String.Format(CultureInfo.InvariantCulture, "{0}{1} {2}", instance, suffix,
                                 CultureInfo.CurrentCulture.DateTimeFormat.DayNames[(int)dow]));
        }
Пример #13
0
        /// <summary>
        /// This is used to get the descriptive suffix for a number (i.e. "st" for 1st, "nd" for 2nd, etc).
        /// </summary>
        /// <param name="number">The number for which to get the suffix</param>
        /// <returns>The number as a string with the appropriate suffix</returns>
        /// <remarks>It is static so that it can be shared with other classes that need it</remarks>
        public static string NumericSuffix(int number)
        {
            int    digits, idx;
            string suffix;

            digits = (number % 100) * ((number < 0) ? -1 : 1);

            if ((digits >= 10 && digits <= 19) || digits % 10 == 0)
            {
                idx = 4;
            }
            else
            {
                idx = digits % 10;
            }

            switch (idx)
            {
            case 1:
                suffix = LR.GetString("DIFirst");
                break;

            case 2:
                suffix = LR.GetString("DISecond");
                break;

            case 3:
                suffix = LR.GetString("DIThird");
                break;

            default:
                suffix = LR.GetString("DINth");
                break;
            }

            return(suffix);
        }
Пример #14
0
        /// <summary>
        /// This method is used to convert an ISO 8601 time zone string into a <see cref="System.TimeSpan"/>
        /// object.
        /// </summary>
        /// <param name="timeZone">The ISO 8601 formatted time zone to parse</param>
        /// <returns>The specified string converted to a time span</returns>
        /// <remarks>The string should be in the form +HH:MM or -HH:MM.  The sign (+/-) and time separator (:)
        /// are optional as are the minutes.  If minutes are not present, they are defaulted to zero.</remarks>
        /// <exception cref="ArgumentException">This is thrown if the specified time zone string is not valid</exception>
        public static TimeSpan FromISO8601TimeZone(string timeZone)
        {
            TimeSpan ts;
            int      hour, minutes = 0, seconds = 0;

            Match m = reTimeZone.Match(timeZone);

            if (!m.Success)
            {
                throw new ArgumentException(LR.GetString("ExDUBadISOTZFormat"), nameof(timeZone));
            }

            // Hour must be there, minutes are optional
            hour = Convert.ToInt32(m.Groups["TZHours"].Value, CultureInfo.InvariantCulture);

            if (m.Groups["TZMinutes"].Value.Length != 0)
            {
                minutes = Convert.ToInt32(m.Groups["TZMinutes"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["TZSeconds"].Value.Length != 0)
            {
                seconds = Convert.ToInt32(m.Groups["TZSeconds"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["TZHours"].Value[0] == '-')
            {
                ts = new TimeSpan(hour, 0 - minutes, 0 - seconds);
            }
            else
            {
                ts = new TimeSpan(hour, minutes, seconds);
            }

            return(ts);
        }
Пример #15
0
        //=====================================================================

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <remarks>Normally, you will not use the default constructor.  Its main reason for existence is for
        /// use in deserialization.  The defaults are set to January 1st, New Year's Day.</remarks>
        /// <overloads>There are three constructors for this class.</overloads>
        public FixedHoliday() : this(1, 1, true, LR.GetString("HCNewYearsDay"))
        {
        }
Пример #16
0
        /// <summary>
        /// This method is used to calculate the date on which a specific occurrence of any of a set of days
        /// occurs (for example, the 4th weekday in November or the last weekend day in January).
        /// </summary>
        /// <param name="year">The year in which the day occurs</param>
        /// <param name="month">The month in which the day occurs</param>
        /// <param name="occur">The occurrence of the day of the week on which the day falls</param>
        /// <param name="days">The day(s) of the week on which the day can occurs</param>
        /// <param name="offset">The number of days before or after the calculated date on which the day falls</param>
        /// <returns>Returns a <see cref="DateTime" /> object that represents the date calculated from the
        /// settings.</returns>
        /// <remarks><para>This method is intended for use in finding an occurrence of any one of a set of days
        /// of the week and is normally used with the <see cref="DaysOfWeek.Weekdays"/> or
        /// <see cref="DaysOfWeek.Weekends"/> day of week value.  However, the days of week parameter can be any
        /// valid combination of days including an individual day of the week.</para>
        ///
        /// <para>Use a positive value for the <c>nOffset</c> parameter for a number of days after the calculated
        /// date or a negative number for a number of days before the calculated date.</para>
        ///
        /// <para>Normally, this value will be zero so that the calculated date is the actual date returned.
        /// However, in cases where a date is calculated in terms of the number of days before or after a given
        /// date, this can be set to the offset to adjust the calculated date.  Note that if used, the date
        /// returned may not be on one of the days of the week specified to calculate the original unadjusted
        /// date.</para></remarks>
        /// <example>
        /// <code language="cs">
        /// // Returns 01/06/2004 (fourth weekday in Jan 2004)
        /// dtFourthWeekday = DateUtils.CalculateOccurrenceDate(2004, 1,
        ///     DayOccurrence.Fourth, DaysOfWeek.Weekdays, 0);
        ///
        /// // Returns 01/08/2004 (fourth weekday plus 2 days)
        /// dtPlusTwo = DateUtils.CalculateOccurrenceDate(2004, 1,
        ///     DayOccurrence.Fourth, DaysOfWeek.Weekdays, 2);
        /// </code>
        /// <code language="vbnet">
        /// ' Returns 01/06/2004 (fourth weekday in Jan 2004)
        /// dtFourthWeekday = DateUtils.CalculateOccurrenceDate(2004, 1,
        ///     DayOccurrence.Fourth, DaysOfWeek.Weekdays, 0)
        ///
        /// ' Returns 01/08/2004 (fourth weekday plus 2 days)
        /// dtPlusTwo = DateUtils.CalculateOccurrenceDate(2004, 1,
        ///     DayOccurrence.Fourth, DaysOfWeek.Weekdays, 2)
        /// </code>
        /// </example>
        /// <exception cref="ArgumentException">This is thrown if <c>None</c> is passed for the <c>DayOccurrence</c>
        /// parameter.</exception>
        public static DateTime CalculateOccurrenceDate(int year, int month, DayOccurrence occur, DaysOfWeek days,
                                                       int offset)
        {
            DateTime dtDate;
            int      count = 0, occurrence = (int)occur;

            if (occur == DayOccurrence.None)
            {
                throw new ArgumentException(LR.GetString("ExDUOccurIsNone"), nameof(occur));
            }

            // Calculating a specific occurrence or the last one?
            if (occur != DayOccurrence.Last)
            {
                dtDate = new DateTime(year, month, 1);

                while (count != occurrence)
                {
                    switch (dtDate.DayOfWeek)
                    {
                    case DayOfWeek.Sunday:
                        if ((days & DaysOfWeek.Sunday) != 0)
                        {
                            count++;
                        }
                        break;

                    case DayOfWeek.Monday:
                        if ((days & DaysOfWeek.Monday) != 0)
                        {
                            count++;
                        }
                        break;

                    case DayOfWeek.Tuesday:
                        if ((days & DaysOfWeek.Tuesday) != 0)
                        {
                            count++;
                        }
                        break;

                    case DayOfWeek.Wednesday:
                        if ((days & DaysOfWeek.Wednesday) != 0)
                        {
                            count++;
                        }
                        break;

                    case DayOfWeek.Thursday:
                        if ((days & DaysOfWeek.Thursday) != 0)
                        {
                            count++;
                        }
                        break;

                    case DayOfWeek.Friday:
                        if ((days & DaysOfWeek.Friday) != 0)
                        {
                            count++;
                        }
                        break;

                    case DayOfWeek.Saturday:
                        if ((days & DaysOfWeek.Saturday) != 0)
                        {
                            count++;
                        }
                        break;
                    }

                    if (count != occurrence)
                    {
                        dtDate = dtDate.AddDays(1);
                    }
                }
            }
            else
            {
                // Find last occurrence
                count++;
                dtDate = new DateTime(year, month, DateTime.DaysInMonth(year, month));

                while (count != 0)
                {
                    switch (dtDate.DayOfWeek)
                    {
                    case DayOfWeek.Sunday:
                        if ((days & DaysOfWeek.Sunday) != 0)
                        {
                            count--;
                        }
                        break;

                    case DayOfWeek.Monday:
                        if ((days & DaysOfWeek.Monday) != 0)
                        {
                            count--;
                        }
                        break;

                    case DayOfWeek.Tuesday:
                        if ((days & DaysOfWeek.Tuesday) != 0)
                        {
                            count--;
                        }
                        break;

                    case DayOfWeek.Wednesday:
                        if ((days & DaysOfWeek.Wednesday) != 0)
                        {
                            count--;
                        }
                        break;

                    case DayOfWeek.Thursday:
                        if ((days & DaysOfWeek.Thursday) != 0)
                        {
                            count--;
                        }
                        break;

                    case DayOfWeek.Friday:
                        if ((days & DaysOfWeek.Friday) != 0)
                        {
                            count--;
                        }
                        break;

                    case DayOfWeek.Saturday:
                        if ((days & DaysOfWeek.Saturday) != 0)
                        {
                            count--;
                        }
                        break;
                    }

                    if (count != 0)
                    {
                        dtDate = dtDate.AddDays(-1);
                    }
                }
            }

            // Return the date plus any additional offset
            return(dtDate.AddDays(offset));
        }
Пример #17
0
        /// <summary>
        /// Convert the duration instance to a text description with the specified maximum unit of time
        /// </summary>
        /// <param name="maxUnit">The maximum unit of time that should be represented in the returned string</param>
        /// <returns>Returns the duration description</returns>
        /// <remarks>The conversion to string breaks the duration down by largest to smallest unit (years down to
        /// seconds).  This version allows you to specify the maximum unit of time that should be represented.
        /// Any time in excess of the maximum time unit will be returned in the maximum time unit (i.e. PT1D will
        /// be returned as 24 hours for a maximum time unit of hours, P1M2W5D will be returned as 7 weeks for a
        /// maximum time unit of weeks if a month is defined as 30 days).</remarks>
        public string ToDescription(MaxUnit maxUnit)
        {
            StringBuilder sb = new StringBuilder(50);
            Duration      d  = new Duration(this.Ticks);

            int years, months, weeks, days, hours, minutes, seconds;

            if (d.Ticks < 0)
            {
                d.TimeSpan = d.TimeSpan.Negate();
            }

            switch (maxUnit)
            {
            case MaxUnit.Months:
                years   = 0;
                months  = (int)(d.TimeSpan.Days / Duration.DaysInOneMonth);
                weeks   = d.TimeSpan.Days - (int)(months * Duration.DaysInOneMonth);
                days    = d.TimeSpan.Days - (int)(months * Duration.DaysInOneMonth) - (int)(weeks * 7);
                hours   = d.TimeSpan.Hours;
                minutes = d.TimeSpan.Minutes;
                seconds = d.TimeSpan.Seconds;
                break;

            case MaxUnit.Weeks:
                years   = months = 0;
                weeks   = (int)(d.TimeSpan.Days / 7);
                days    = d.TimeSpan.Days - (weeks * 7);
                hours   = d.TimeSpan.Hours;
                minutes = d.TimeSpan.Minutes;
                seconds = d.TimeSpan.Seconds;
                break;

            case MaxUnit.Days:
                years   = months = weeks = 0;
                days    = d.TimeSpan.Days;
                hours   = d.TimeSpan.Hours;
                minutes = d.TimeSpan.Minutes;
                seconds = d.TimeSpan.Seconds;
                break;

            case MaxUnit.Hours:
                years   = months = weeks = days = 0;
                hours   = (int)d.TimeSpan.TotalHours;
                minutes = d.TimeSpan.Minutes;
                seconds = d.TimeSpan.Seconds;
                break;

            case MaxUnit.Minutes:
                years   = months = weeks = days = hours = 0;
                minutes = (int)d.TimeSpan.TotalMinutes;
                seconds = d.TimeSpan.Seconds;
                break;

            case MaxUnit.Seconds:
                years   = months = weeks = days = hours = minutes = 0;
                seconds = (int)d.TimeSpan.TotalSeconds;
                break;

            default:        // Max unit = Years, all parts specified
                years   = d.Years;
                months  = d.Months;
                weeks   = d.Weeks;
                days    = d.Days;
                hours   = d.TimeSpan.Hours;
                minutes = d.TimeSpan.Minutes;
                seconds = d.TimeSpan.Seconds;
                break;
            }

            if (years != 0)
            {
                sb.Append(years);
                sb.Append(LR.GetString((years == 1) ? "DurYear" : "DurYears"));
            }

            if (months != 0)
            {
                sb.Append(", ");
                sb.Append(months);
                sb.Append(LR.GetString((months == 1) ? "DurMonth" : "DurMonths"));
            }

            if (weeks != 0)
            {
                sb.Append(", ");
                sb.Append(weeks);
                sb.Append(LR.GetString((weeks == 1) ? "DurWeek" : "DurWeeks"));
            }

            if (days != 0)
            {
                sb.Append(", ");
                sb.Append(days);
                sb.Append(LR.GetString((days == 1) ? "DurDay" : "DurDays"));
            }

            // Append time if needed
            if (sb.Length == 0 || hours != 0 || minutes != 0 || seconds != 0)
            {
                if (hours != 0)
                {
                    sb.Append(", ");
                    sb.Append(hours);
                    sb.Append(LR.GetString((hours == 1) ? "DurHour" : "DurHours"));
                }

                if (minutes != 0)
                {
                    sb.Append(", ");
                    sb.Append(minutes);
                    sb.Append(LR.GetString((minutes == 1) ? "DurMinute" : "DurMinutes"));
                }

                // Always append seconds if there's nothing else
                if (seconds != 0 || sb.Length == 0)
                {
                    sb.Append(", ");
                    sb.Append(seconds);
                    sb.Append(LR.GetString((seconds == 1) ? "DurSecond" : "DurSeconds"));
                }
            }

            // Remove the leading comma separator if it's there
            if (sb[0] == ',')
            {
                sb.Remove(0, 2);
            }

            // Negative duration?
            if (this.Ticks < 0)
            {
                sb.Insert(0, ' ');
                sb.Insert(0, LR.GetString("DurNegative"));
            }

            return(sb.ToString());
        }
Пример #18
0
        /// <summary>
        /// Construct a duration from a string in ISO 8601 duration format
        /// </summary>
        /// <param name="duration">The ISO 8601 formatted duration to parse</param>
        /// <remarks>This parses a string in the form P#Y#M#W#DT#H#M#S to create a duration.  '#' indicates a
        /// string of one or more digits and the letters represent the years, months, weeks, days, hours,
        /// minutes, and seconds.  Any of the parts except the leading 'P' and the 'T' time separator can be
        /// omitted entirely if not needed.</remarks>
        /// <exception cref="ArgumentException">This is thrown if the specified duration string is not valid</exception>
        public Duration(string duration)
        {
            int years = 0, months = 0, weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0;

            // If null or empty, default to zero
            if (String.IsNullOrEmpty(duration))
            {
                ts = TimeSpan.Zero;
                return;
            }

            Match m = reDuration.Match(duration);

            if (!m.Success)
            {
                throw new ArgumentException(LR.GetString("ExDurBadISOFormat"), "duration");
            }

            if (m.Groups["Years"].Value.Length != 0)
            {
                years = Convert.ToInt32(m.Groups["Years"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["Months"].Value.Length != 0)
            {
                months = Convert.ToInt32(m.Groups["Months"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["Weeks"].Value.Length != 0)
            {
                weeks = Convert.ToInt32(m.Groups["Weeks"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["Days"].Value.Length != 0)
            {
                days = Convert.ToInt32(m.Groups["Days"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["Hours"].Value.Length != 0)
            {
                hours = Convert.ToInt32(m.Groups["Hours"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["Mins"].Value.Length != 0)
            {
                minutes = Convert.ToInt32(m.Groups["Mins"].Value, CultureInfo.InvariantCulture);
            }

            if (m.Groups["Secs"].Value.Length != 0)
            {
                seconds = Convert.ToInt32(m.Groups["Secs"].Value, CultureInfo.InvariantCulture);
            }

            ts = new TimeSpan(days, hours, minutes, seconds, 0);

            if (years != 0)
            {
                ts += new TimeSpan(years * Duration.TicksPerYear);
            }

            if (months != 0)
            {
                ts += new TimeSpan(months * Duration.TicksPerMonth);
            }

            if (weeks != 0)
            {
                ts += new TimeSpan(weeks * Duration.TicksPerWeek);
            }

            if (m.Groups["Negative"].Value == "-")
            {
                ts = ts.Negate();
            }
        }
Пример #19
0
        //=====================================================================

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <remarks>Normally, you will not use the default constructor.  Its main reason for existence is for
        /// use in deserialization.  The defaults are set to the first Monday in September, Labor Day.</remarks>
        /// <overloads>There are three constructors for this class</overloads>
        public FloatingHoliday() : this(DayOccurrence.First, DayOfWeek.Monday, 9, 0, LR.GetString("HCLaborDay"))
        {
        }
Пример #20
0
        /// <summary>
        /// This method can be used to calculate the Easter Sunday date using one of three methods defined by
        /// <see cref="EasterMethod"/>.
        /// </summary>
        /// <remarks>See the <see cref="EasterMethod"/> enumerated type for the ways in which Easter Sunday can
        /// be calculated.  A number of days can be added to or subtracted from the returned date to find other
        /// Easter related dates (i.e. subtract two from the returned date to get the date on which Good Friday
        /// falls).</remarks>
        /// <param name="year">The year in which to calculate Easter</param>
        /// <param name="method">The method to use for calculating Easter</param>
        /// <returns>The date on which Easter falls in the specified year as calculated using the specified
        /// method.</returns>
        /// <exception cref="ArgumentOutOfRangeException">An exception is thrown if the year is not between 1583
        /// and 4099 for the Orthodox and Gregorian methods or if the year is less than 326 for the Julian
        /// method.</exception>
        /// <example>
        /// <code language="cs">
        /// // Returns 04/11/2004 for Easter
        /// dtEaster = DateUtils.EasterSunday(2004, EasterMethod.Gregorian);
        ///
        /// // Calculate Good Friday from that date
        /// dtGoodFriday = dtEaster.AddDays(-2);
        /// </code>
        /// <code language="vbnet">
        /// ' Returns 04/11/2004 for Easter
        /// dtEaster = DateUtils.EasterSunday(2004, EasterMethod.Gregorian)
        ///
        /// ' Calculate Good Friday from that date
        /// dtGoodFriday = dtEaster.AddDays(-2)
        /// </code>
        /// </example>
        public static DateTime EasterSunday(int year, EasterMethod method)
        {
            int century, yearRem, temp, pfm, tabc, day, month;

            // Validate year
            if (method == EasterMethod.Julian && year < 326)
            {
                throw new ArgumentOutOfRangeException(nameof(year), year, LR.GetString("ExDUBadJulianYear"));
            }

            if (method != EasterMethod.Julian && (year < 1583 || year > 4099))
            {
                throw new ArgumentOutOfRangeException(nameof(year), year, LR.GetString("ExDUBadOrthGregYear"));
            }

            century = year / 100;     // Get century
            yearRem = year % 19;      // Get remainder of year / 19

            if (method != EasterMethod.Gregorian)
            {
                // Calculate PFM date (Julian and Orthodox)
                pfm = ((225 - 11 * yearRem) % 30) + 21;

                // Find the next Sunday
                temp = year % 100;
                day  = pfm + ((20 - ((pfm - 19) % 7) - ((40 - century) % 7) - ((temp + (temp / 4)) % 7)) % 7) + 1;

                // Convert Julian to Gregorian date for Orthodox method
                if (method == EasterMethod.Orthodox)
                {
                    // Ten days were skipped in the Gregorian calendar from October 5-14, 1582
                    day += 10;

                    // Only one in every four century years are leap years in the Gregorian calendar.  Every
                    // century is a leap year in the Julian calendar.
                    if (year > 1600)
                    {
                        day += (century - 16 - ((century - 16) / 4));
                    }
                }
            }
            else
            {
                // Calculate PFM date (Gregorian)
                temp = ((century - 15) / 2) + 202 - (11 * yearRem);

                switch (century)
                {
                case 21:
                case 24:
                case 25:
                case 27:
                case 28:
                case 29:
                case 30:
                case 31:
                case 32:
                case 34:
                case 35:
                case 38:
                    temp--;
                    break;

                case 33:
                case 36:
                case 37:
                case 39:
                case 40:
                    temp -= 2;
                    break;

                default:
                    break;
                }

                temp %= 30;

                pfm = temp + 21;

                if (temp == 29 || (temp == 28 && yearRem > 10))
                {
                    pfm--;
                }

                // Find the next Sunday
                tabc = (40 - century) % 4;

                if (tabc == 3)
                {
                    tabc++;
                }

                if (tabc > 1)
                {
                    tabc++;
                }

                temp = year % 100;

                day = pfm + ((20 - ((pfm - 19) % 7) - tabc - ((temp + (temp / 4)) % 7)) % 7) + 1;
            }

            // Return the date
            if (day > 61)
            {
                day  -= 61;
                month = 5;     // Can occur in May for EasterMethod.Orthodox
            }
            else
            if (day > 31)
            {
                day  -= 31;
                month = 4;
            }
            else
            {
                month = 3;
            }

            return(new DateTime(year, month, day));
        }
Пример #21
0
        /// <summary>
        /// This method is used to convert an ISO 8601 formatted date string to a DateTime value that it
        /// represents.
        /// </summary>
        /// <param name="dateTimeText">The ISO 8601 formatted date to parse.</param>
        /// <param name="toLocalTime">If true and the string is in a universal time format, the value is
        /// converted to local time before being returned.  If false, it is returned as a universal time
        /// value.</param>
        /// <returns>The specified string converted to a local date/time</returns>
        /// <exception cref="ArgumentException">This is thrown if the specified date/time string is not valid</exception>
        /// <remarks><para>The <see cref="System.DateTime.Parse(String)"/> method is capable of parsing a string
        /// in a very specific layout of the ISO 8601 format (SortableDateTimePattern).  However, if the string
        /// deviates even slightly from that pattern, it cannot be parsed.  This method takes an ISO 8601
        /// formatted date string in any of various formats and returns the DateTime value that it represents.</para>
        ///
        /// <para>This method does not handle all possible forms of the ISO 8601 format, just those related to
        /// date and time values (<c>YYYY-MM-DDTHH:MM:SS.MMMM+HH:MM</c>).  Date and time separators (except the
        /// 'T') are optional as is the time zone specifier.  The time indicator ('T') and the time value can be
        /// omitted entirely if not needed.  A 'Z' (Zulu) can appear in place of the time zone specifier to
        /// indicate universal time.  Date/times in universal time format or with a time zone offset are
        /// converted to local time if the <c>bToLocalTime</c> parameter is set to true.  All other values are
        /// assumed to be local time already and will be returned unmodified as are date-only values.</para></remarks>
        public static DateTime FromISO8601String(string dateTimeText, bool toLocalTime)
        {
            DateTime convertedDate;
            int      year, day, month, hour = 0, minutes = 0, wholeSeconds = 0, milliseconds = 0;
            double   fracSeconds;

            Match m = reISO8601.Match(dateTimeText);

            if (!m.Success)
            {
                throw new ArgumentException(LR.GetString("ExDUBadISOFormat"), nameof(dateTimeText));
            }

            // Day parts must be there
            year  = Convert.ToInt32(m.Groups["Year"].Value, CultureInfo.InvariantCulture);
            month = Convert.ToInt32(m.Groups["Month"].Value, CultureInfo.InvariantCulture);
            day   = Convert.ToInt32(m.Groups["Day"].Value, CultureInfo.InvariantCulture);

            // Sometimes we get a bad date with parts outside their respective ranges.  Rather than throw an
            // exception, we'll restrict them to the minimum or maximum value.
            if (year < 1)
            {
                year = 1;
            }

            if (month < 1)
            {
                month = 1;
            }
            else
            if (month > 12)
            {
                month = 12;
            }

            if (day < 1)
            {
                day = 1;
            }
            else
            if (day > DateTime.DaysInMonth(year, month))
            {
                day = DateTime.DaysInMonth(year, month);
            }

            // Time parts are optional
            if (m.Groups["Hour"].Value.Length != 0)
            {
                hour = Convert.ToInt32(m.Groups["Hour"].Value, CultureInfo.InvariantCulture);

                if (m.Groups["Minutes"].Value.Length != 0)
                {
                    minutes = Convert.ToInt32(m.Groups["Minutes"].Value, CultureInfo.InvariantCulture);

                    if (m.Groups["Seconds"].Value.Length != 0)
                    {
                        fracSeconds  = Convert.ToDouble(m.Groups["Seconds"].Value, CultureInfo.InvariantCulture);
                        wholeSeconds = (int)fracSeconds;
                        milliseconds = (int)((fracSeconds - wholeSeconds) * 1000);
                    }
                }
            }

            convertedDate = new DateTime(year, month, day);

            // Sometimes we get something like 240000 to represent the time for a whole day.  By adding the time
            // parts as a time span, we bypass any potential problems with the DateTime() constructor that
            // expects the time parts to be within bounds.
            convertedDate += new TimeSpan(0, hour, minutes, wholeSeconds, milliseconds);

            // Convert to local time if necessary
            if (m.Groups["Zulu"].Value.Length != 0)
            {
                if (toLocalTime)
                {
                    convertedDate = convertedDate.ToLocalTime();
                }
            }
            else
            if (m.Groups["TZHours"].Value.Length != 0)
            {
                // If a time zone offset was specified, add it to the time to get UTC
                hour = Convert.ToInt32(m.Groups["TZHours"].Value, CultureInfo.InvariantCulture);

                if (m.Groups["TZMinutes"].Value.Length == 0)
                {
                    minutes = 0;
                }
                else
                {
                    minutes = Convert.ToInt32(m.Groups["TZMinutes"].Value, CultureInfo.InvariantCulture);
                }

                convertedDate = convertedDate.AddMinutes(0 - (hour * 60 + minutes));

                if (toLocalTime)
                {
                    convertedDate = convertedDate.ToLocalTime();
                }
            }

            return(convertedDate);
        }