Click here to Skip to main content
15,892,059 members
Articles / Programming Languages / C#

Working with date/time patterns

Rate me:
Please Sign up or sign in to vote.
4.64/5 (10 votes)
3 Apr 20073 min read 45.6K   206   35  
Working with date/time patterns
#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
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect
Austria Austria
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions