//******************************************************************************************************
// 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
}
}