#region Usings
using System;
using System.Text.RegularExpressions;
#endregion
namespace DateTools
{
/// <summary>
/// Provides methods for matching dates against patterns and find dates matching these patterns.
/// </summary>
public class DateTimePattern
{
#region Variables
private int? _year = null;
private int? _month = null;
private int? _day = null;
private int? _hour = null;
private int? _minute = null;
private int? _second = null;
#endregion
#region CTOR / DTOR
/// <summary>
/// Creates a new DateTimePattern matching every Date.
/// </summary>
public DateTimePattern()
{
this.Year = null;
this.Month = null;
this.Day = null;
this.Hour = null;
this.Minute = null;
this.Second = null;
}
/// <summary>
/// Creates a new DateTimePattern matching the given Date represented by the
/// Year, Month, Day, Hour, Minute and Second parameters. If any of these
/// parameters is null it acts as wildcard matching any value.
/// </summary>
/// <param name="Year">the year</param>
/// <param name="Month">the month</param>
/// <param name="Day">the day</param>
/// <param name="Hour">the hour</param>
/// <param name="Minute">the minute</param>
/// <param name="Second">the second</param>
public DateTimePattern( int? Year, int? Month, int? Day, int? Hour, int? Minute, int? Second )
: this()
{
this.Year = Year;
this.Month = Month;
this.Day = Day;
this.Hour = Hour;
this.Minute = Minute;
this.Second = Second;
}
/// <summary>
/// Creates a new DateTimePattern matching the exact Date given.
/// </summary>
/// <param name="Date">the Date</param>
public DateTimePattern( DateTime Date )
: this( Date.Year, Date.Month, Date.Day, Date.Hour, Date.Minute, Date.Second )
{
}
#endregion
#region Properties
#region Year
/// <summary>
/// Get or set the year part of this DateTimePattern. If Year is null
/// it will act as a wildcard matching every year.
/// </summary>
public int? Year
{
get { return _year; }
set { _year = value; }
}
#endregion
#region Month
/// <summary>
/// Get or set the month part of this DateTimePattern. If Month is null
/// it will act as a wildcard matching every month.
/// </summary>
public int? Month
{
get { return _month; }
set { _month = value; }
}
#endregion
#region Day
/// <summary>
/// Get or set the day part of this DateTimePattern. If Day is null
/// it will act as a wildcard matching every day.
/// </summary>
public int? Day
{
get { return _day; }
set { _day = value; }
}
#endregion
#region Hour
/// <summary>
/// Get or set the hour part of this DateTimePattern. If Hour is null
/// it will act as a wildcard matching every hour.
/// </summary>
public int? Hour
{
get { return _hour; }
set { _hour = value; }
}
#endregion
#region Minute
/// <summary>
/// Get or set the minute part of this DateTimePattern. If Minute is null
/// it will act as a wildcard matching every minute.
/// </summary>
public int? Minute
{
get { return _minute; }
set { _minute = value; }
}
#endregion
#region Second
/// <summary>
/// Get or set the second part of this DateTimePattern. If Second is null
/// it will act as a wildcard matching every second.
/// </summary>
public int? Second
{
get { return _second; }
set { _second = value; }
}
#endregion
#endregion
#region Public Methods
#region DateMatchesTemplate
/// <summary>
/// Returns a flag if the given Date will match this DateTimePattern.
/// </summary>
/// <param name="Date">The Date to check.</param>
/// <returns>a <see cref="bool"/> which is true if the Date matches, false if not.</returns>
public bool DateMatchesTemplate( DateTime Date )
{
if ( this.Second != null && this.Second != Date.Second )
return false;
if ( this.Minute != null && this.Minute != Date.Minute )
return false;
if ( this.Hour != null && this.Hour != Date.Hour )
return false;
if ( this.Day != null && this.Day != Date.Day )
return false;
if ( this.Month != null && this.Month != Date.Month )
return false;
if ( this.Year != null && this.Year != Date.Year )
return false;
return true;
}
#endregion
#region GetFirstPossibleDate
/// <summary>
/// Returns the first possible matching date for this DateTimePattern.
/// </summary>
/// <returns>a <see cref="DateTime"/></returns>
public DateTime GetFirstPossibleDate()
{
return MergeMinToTemplate();
}
#endregion
#region GetLastPossibleDate
/// <summary>
/// Returns the last possible matching date for this DateTimePattern.
/// </summary>
/// <returns>a <see cref="DateTime"/></returns>
public DateTime GetLastPossibleDate()
{
return MergeMaxToTemplate();
}
#endregion
#region GetNextPossibleDate
/// <summary>
/// Returns the next possible date starting with <see cref="DateTime.Now"/> which
/// matches this DateTimePattern.
/// </summary>
/// <returns>a <see cref="DateTime"/></returns>
public DateTime GetNextPossibleDate()
{
return GetNextPossibleDate( DateTime.Now );
}
/// <summary>
/// Returns the next possible date starting from the given
/// parameter which matches this DateTimePattern.
/// </summary>
/// <param name="Date">The starting date.</param>
/// <returns>a <see cref="DateTime"/></returns>
public DateTime GetNextPossibleDate( DateTime Date )
{
DateTime dMin = MergeMinToTemplate();
if ( Date <= dMin )
return dMin;
DateTime dMax = MergeMaxToTemplate();
if ( Date >= dMax )
return dMax;
DateTime dTmp = MergeDateToTemplate( Date );
DateTime dTmp1;
if (dTmp == Date)
return dTmp;
if ( dTmp > Date )
{
// seconds
if ( this.Second == null )
{
dTmp1 = dTmp.AddSeconds( -1 );
if ( dTmp1 > Date )
dTmp = new DateTime( dTmp1.Year, dTmp1.Month, dTmp1.Day, dTmp1.Hour, dTmp1.Minute, 0 );
if ( dTmp <= Date )
return dTmp;
}
// minutes
if ( this.Minute == null )
{
dTmp1 = dTmp.AddMinutes( -1 );
if ( dTmp1 > Date )
dTmp = new DateTime( dTmp1.Year, dTmp1.Month, dTmp1.Day, dTmp1.Hour, 0, dTmp1.Second );
if ( dTmp <= Date )
return dTmp;
}
// hours
if ( this.Hour == null )
{
dTmp1 = dTmp.AddHours( -1 );
if ( dTmp1 > Date )
dTmp = new DateTime( dTmp1.Year, dTmp1.Month, dTmp1.Day, 0, dTmp1.Minute, dTmp1.Second );
if ( dTmp <= Date )
return dTmp;
}
// days
if ( this.Day == null )
{
dTmp1 = dTmp.AddDays( -1 );
if ( dTmp1 > Date )
dTmp = new DateTime( dTmp1.Year, dTmp1.Month, 1, dTmp1.Hour, dTmp1.Minute, dTmp1.Second );
if ( dTmp <= Date )
return dTmp;
}
// months
if ( this.Month == null )
{
dTmp1 = dTmp.AddMonths( -1 );
if ( dTmp1 > Date )
dTmp = new DateTime( dTmp1.Year, 1, dTmp1.Day, dTmp1.Hour, dTmp1.Minute, dTmp1.Second );
if ( dTmp <= Date )
return dTmp;
}
// years
if ( this.Year == null )
{
dTmp1 = dTmp.AddYears( -1 );
if ( dTmp1 > Date )
dTmp = new DateTime( 1, dTmp1.Month, dTmp1.Day, dTmp1.Hour, dTmp1.Minute, dTmp1.Second );
if ( dTmp <= Date )
return dTmp;
}
}
else
{
// seconds
if ( this.Second == null )
{
dTmp = dTmp.AddSeconds( 1 );
if ( dTmp < Date )
dTmp = new DateTime( dTmp.Year, dTmp.Month, dTmp.Day, dTmp.Hour, dTmp.Minute, 0 );
if ( dTmp >= Date )
return dTmp;
}
// minutes
if ( this.Minute == null )
{
dTmp = dTmp.AddMinutes( 1 );
if ( dTmp < Date )
dTmp = new DateTime( dTmp.Year, dTmp.Month, dTmp.Day, dTmp.Hour, 0, dTmp.Second );
if ( dTmp >= Date )
return dTmp;
}
// hours
if ( this.Hour == null )
{
dTmp = dTmp.AddHours( 1 );
if ( dTmp < Date )
dTmp = new DateTime( dTmp.Year, dTmp.Month, dTmp.Day, 0, dTmp.Minute, dTmp.Second );
if ( dTmp >= Date )
return dTmp;
}
// days
if ( this.Day == null )
{
dTmp = dTmp.AddDays( 1 );
if ( dTmp < Date )
dTmp = new DateTime( dTmp.Year, dTmp.Month, 1, dTmp.Hour, dTmp.Minute, dTmp.Second );
if ( dTmp >= Date )
return dTmp;
}
// months
if ( this.Month == null )
{
dTmp = dTmp.AddMonths( 1 );
if ( dTmp < Date )
dTmp = new DateTime( dTmp.Year, 1, dTmp.Day, dTmp.Hour, dTmp.Minute, dTmp.Second );
if ( dTmp >= Date )
return dTmp;
}
// years
if ( this.Year == null )
{
dTmp = dTmp.AddYears( 1 );
if ( dTmp < Date )
dTmp = new DateTime( 1, dTmp.Month, dTmp.Day, dTmp.Hour, dTmp.Minute, dTmp.Second );
if ( dTmp >= Date )
return dTmp;
}
}
return dTmp;
}
#endregion
#region ToString
/// <summary>
/// Returns this DateTimePattern as a <see cref="String"/> representing wildcards as '*'. The
/// format is <b>yyyy.MM.dd HH:mm.ss</b>. See <see cref="DateTime.ToString(string)"/>.
/// </summary>
/// <returns>This DateTimePattern as <see cref="String"/>.</returns>
public override string ToString()
{
return String.Format( "{0}.{1}.{2} {3}:{4}.{5}",
( this.Year == null ) ? "****" : ( (int)this.Year ).ToString( "0000" ),
( this.Month == null ) ? "**" : ( (int)this.Month ).ToString( "00" ),
( this.Day == null ) ? "**" : ( (int)this.Day ).ToString( "00" ),
( this.Hour == null ) ? "**" : ( (int)this.Hour ).ToString( "00" ),
( this.Minute == null ) ? "**" : ( (int)this.Minute ).ToString( "00" ),
( this.Second == null ) ? "**" : ( (int)this.Second ).ToString( "00" ) );
}
#endregion
#region Parse
/// <summary>
/// Returns a DateTimePattern instance from the given string. The format of this
/// string is the same as the string returned from <see cref="DateTimePattern.ToString"/>.
/// </summary>
/// <param name="DateTimePatternString">The string representation of a DateTimePattern</param>
/// <returns>a DateTimePattern instance</returns>
public static DateTimePattern Parse( string DateTimePatternString )
{
Regex r = new Regex( @"^(\*{1,4}|\d{1,4})\.(\*{1,2}|\d{1,2})\.(\*{1,2}|\d{1,2}) +(\*{1,2}|\d{1,2}):(\*{1,2}|\d{1,2})\.(\*{1,2}|\d{1,2})$" );
Match m = r.Match( DateTimePatternString );
if ( m.Groups.Count != 7 )
throw new FormatException( "Unable to parse DateTimePatternString (" + DateTimePatternString + ")" );
DateTimePattern p = new DateTimePattern(
( m.Groups[1].Value[0] == '*' ) ? (int?)null : int.Parse( m.Groups[1].Value ),
( m.Groups[2].Value[0] == '*' ) ? (int?)null : int.Parse( m.Groups[2].Value ),
( m.Groups[3].Value[0] == '*' ) ? (int?)null : int.Parse( m.Groups[3].Value ),
( m.Groups[4].Value[0] == '*' ) ? (int?)null : int.Parse( m.Groups[4].Value ),
( m.Groups[5].Value[0] == '*' ) ? (int?)null : int.Parse( m.Groups[5].Value ),
( m.Groups[6].Value[0] == '*' ) ? (int?)null : int.Parse( m.Groups[6].Value )
);
return p;
}
#endregion
#endregion
#region Private Methods
private DateTime MergeDateToTemplate( DateTime Date )
{
return new DateTime(
( this.Year != null ) ? (int)this.Year : Date.Year,
( this.Month != null ) ? (int)this.Month : Date.Month,
( this.Day != null ) ? (int)this.Day : Date.Day,
( this.Hour != null ) ? (int)this.Hour : Date.Hour,
( this.Minute != null ) ? (int)this.Minute : Date.Minute,
( this.Second != null ) ? (int)this.Second : Date.Second
);
}
private DateTime MergeMaxToTemplate()
{
return MergeDateToTemplate( DateTime.MaxValue );
}
private DateTime MergeMinToTemplate()
{
return MergeDateToTemplate( DateTime.MinValue );
}
private DateTime MergeNowToTemplate()
{
return MergeDateToTemplate( DateTime.Now );
}
#endregion
}
}