//****************************************************************************************************** // Schedule.cs - Gbtc // // Copyright © 2012, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 08/01/2006 - Pinal C. Patel // Generated original version of source code. // 09/15/2008 - J. Ritchie Carroll // Converted to C#. // 09/14/2009 - Stephen C. Wills // Added new header and license agreement. // 12/14/2012 - Starlynn Danyelle Gilliam // Modified Header. // //****************************************************************************************************** using System; using System.ComponentModel; using System.Text; namespace GSF.Scheduling { /// /// Represents a schedule defined using UNIX crontab syntax. /// /// /// /// Operators: /// /// /// There are several ways of specifying multiple date/time values in a field: /// /// /// /// The comma (',') operator specifies a list of values, for example: "1,3,4,7,8" /// /// /// /// /// The dash ('-') operator specifies a range of values, for example: "1-6", /// which is equivalent to "1,2,3,4,5,6" /// /// /// /// /// The asterisk ('*') operator specifies all possible values for a field. /// For example, an asterisk in the hour time field would be equivalent to /// 'every hour' (subject to matching other specified fields). /// /// /// /// /// The slash ('/') operator (called "step"), which can be used to skip a given /// number of values. For example, "*/3" in the hour time field is equivalent /// to "0,3,6,9,12,15,18,21". So "*" specifies 'every hour' but the "*/3" means /// only those hours divisible by 3. /// /// /// /// /// /// Fields: /// /// /// /// +---------------- minute (0 - 59) /// | +------------- hour (0 - 23) /// | | +---------- day of month (1 - 31) /// | | | +------- month (1 - 12) /// | | | | +---- day of week (0 - 7) (Sunday=0 or 7) /// | | | | | /// * * * * * /// /// /// /// Each of the patterns from the first five fields may be either * (an asterisk), which matches all legal values, /// or a list of elements separated by commas. /// /// /// See http://en.wikipedia.org/wiki/Cron for more information. /// /// /// /// public class Schedule { #region [ Members ] // Fields private string m_name; private string m_description; private bool m_useLocalTime; private SchedulePart m_minutePart; private SchedulePart m_hourPart; private SchedulePart m_dayPart; private SchedulePart m_monthPart; private SchedulePart m_dayOfWeekPart; private DateTime m_lastDueAt; #endregion #region [ Constructors ] /// /// Initializes a new instance of the class. /// public Schedule() : this("Schedule" + (++s_instances)) { } /// /// Initializes a new instance of the class. /// /// Name of the schedule. /// Default of '* * * * *' is used. public Schedule(string name) : this(name, "* * * * *") { } /// /// Initializes a new instance of the class. /// /// Name of the schedule. /// Rule formated in UNIX crontab syntax. public Schedule(string name, string rule) : this(name, rule, "") { } /// /// Initializes a new instance of the class. /// /// Name of the schedule. /// Rule formated in UNIX crontab syntax. /// Description of defined schedule. public Schedule(string name, string rule, string description) : this(name, rule, description, false) { } /// /// Initializes a new instance of the class. /// /// Name of the schedule. /// Rule formated in UNIX crontab syntax. /// Description of defined schedule. /// Flag that determines whether to use local time for schedule. public Schedule(string name, string rule, string description, bool useLocalTime) { Name = name; Rule = rule; Description = description; UseLocalTime = useLocalTime; } #endregion #region [ Properties ] /// /// Gets or sets the name of the . /// /// The value being assigned is null or empty string. public string Name { get { return m_name; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value)); m_name = value; } } /// /// Gets or sets the rule of the defined in UNIX crontab syntax. /// /// The value being assigned is null or empty string. /// The number of in the rule is not exactly 5. public string Rule { get { return m_minutePart.ValueText + " " + m_hourPart.ValueText + " " + m_dayPart.ValueText + " " + m_monthPart.ValueText + " " + m_dayOfWeekPart.ValueText; } set { if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value)); string[] scheduleParts = value.RemoveDuplicateWhiteSpace().Split(' '); if (scheduleParts.Length != 5) throw new ArgumentException("Schedule rule must have exactly 5 parts (Example: * * * * *)"); m_minutePart = new SchedulePart(scheduleParts[0], DateTimePart.Minute); m_hourPart = new SchedulePart(scheduleParts[1], DateTimePart.Hour); m_dayPart = new SchedulePart(scheduleParts[2], DateTimePart.Day); m_monthPart = new SchedulePart(scheduleParts[3], DateTimePart.Month); m_dayOfWeekPart = new SchedulePart(scheduleParts[4], DateTimePart.DayOfWeek); // Update the schedule description. StringBuilder description = new StringBuilder(); description.Append(m_minutePart.Description); description.Append(", "); description.Append(m_hourPart.Description); description.Append(", "); description.Append(m_dayPart.Description); description.Append(", "); description.Append(m_monthPart.Description); description.Append(", "); description.Append(m_dayOfWeekPart.Description); m_description = description.ToString(); } } /// /// Gets or sets a description of the . /// /// A default description is created automatically when the is set. public string Description { get { return m_description; } set { if (!string.IsNullOrEmpty(value)) m_description = value; } } /// /// Gets or sets a flag that determines whether the scheduler uses local time or UTC time for scheduling. /// public bool UseLocalTime { get { return m_useLocalTime; } set { m_useLocalTime = value; } } /// /// Gets the of the that represents minute . /// [Browsable(false)] public SchedulePart MinutePart { get { return m_minutePart; } } /// /// Gets the of the that represents hour . /// [Browsable(false)] public SchedulePart HourPart { get { return m_hourPart; } } /// /// Gets the of the that represents day of month . /// [Browsable(false)] public SchedulePart DayPart { get { return m_dayPart; } } /// /// Gets the of the that represents month . /// [Browsable(false)] public SchedulePart MonthPart { get { return m_monthPart; } } /// /// Gets the of the that represents day of week . /// [Browsable(false)] public SchedulePart DaysOfWeekPart { get { return m_dayOfWeekPart; } } /// /// Gets the when the was last due. /// [Browsable(false)] public DateTime LastDueAt { get { return m_lastDueAt; } } /// /// Gets the current status of the . /// [Browsable(false)] public string Status { get { StringBuilder status = new StringBuilder(); status.Append(" Schedule name: "); status.Append(m_name); status.AppendLine(); status.Append(" Schedule rule: "); status.Append(Rule); status.AppendLine(); status.Append(" Last run time: "); status.Append(m_lastDueAt == DateTime.MinValue ? "Never" : m_lastDueAt.ToString()); status.AppendLine(); return status.ToString(); } } #endregion #region [ Methods ] /// /// Checks whether the is due at the present system time. /// /// true if the is due at the present system time; otherwise false. public bool IsDue() { DateTime currentDateTime = m_useLocalTime ? DateTime.Now : DateTime.UtcNow; if (m_minutePart.Matches(currentDateTime) && m_hourPart.Matches(currentDateTime) && m_dayPart.Matches(currentDateTime) && m_monthPart.Matches(currentDateTime) && m_dayOfWeekPart.Matches(currentDateTime)) { m_lastDueAt = currentDateTime; return true; } return false; } /// /// Gets a hash code for the . /// /// An based hashcode. public override int GetHashCode() { return Rule.GetHashCode(); } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// /// true if the specified is equal to the current ; otherwise false /// public override bool Equals(object obj) { Schedule other = obj as Schedule; return (object)other != null && this.Name == other.Name && this.Rule == other.Rule; } /// /// Gets the string representation of . /// /// String representation of . public override string ToString() { return m_name; } #endregion #region [ Static ] // Static Fields private static int s_instances; #endregion } }