Click here to Skip to main content
15,886,362 members
Articles / Programming Languages / C#

Time scheduler in C#

Rate me:
Please Sign up or sign in to vote.
4.67/5 (17 votes)
16 May 2007GPL34 min read 135.7K   2.5K   82  
This library allows iterating through a sequence of events or time ranges based on a time schedule.
using System;
using System.Collections.Generic;
using System.Text;

namespace Idaligo.Time
{
	public class ShiftedAnchor : IAnchor
	{
		private Scale scale;
		private Anchor anchor;
		private int number;

		public ShiftedAnchor(Scale baseScale, Scale scale, int number)
			: this(new Anchor(baseScale), scale, number)
		{
		}

		protected ShiftedAnchor(Anchor @base, Scale scale, int number)
		{
			if (@base == null) throw new ArgumentNullException("@base");
			if (number < 0) throw new ArgumentOutOfRangeException("number", number, "Must be 0 or greater.");
			Validate(@base, scale, number);
			this.anchor = @base;
			this.scale = scale;
			this.number = number;
		}

		private void Validate(Anchor @base, Scale scale, int number)
		{
#warning Left undone: ShiftedAnchor.ValidateScaleAndNumber
		}

		public bool AtPoint(DateTime at)
		{
			bool result;
			if (this.scale == Scale.Week)
			{
				DateTime starts = (this.anchor.AtPoint(at)) ? at : this.anchor.Previous(at);
				if (starts.DayOfWeek != DayOfWeek.Sunday)
				{
					starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
				}

				if (this.number == 0)
				{
					result = starts == at;
				}
				else
				{
					result = at == this.Next(starts);
				}
			}
			else
			{
				if (this.number == 0)
				{
					result = this.anchor.AtPoint(at);
				}
				else
				{
					result = at == this.Next(this.anchor.Previous(at));
				}
			}
			return result;
		}



		public IEnumerable<DateTime> Walk(DateTime from)
		{
			if (this.AtPoint(from))
			{
				yield return from;
			}
			while (true)
			{
				from = this.Next(from);
				yield return from;
			}
		}

		public DateTime Next(DateTime from)
		{
			return this.Go((this.anchor.AtPoint(from)) ? from : this.anchor.Previous(from), from, true);
		}

		private DateTime Go(DateTime starts, DateTime from, bool forward)
		{
			DateTime result;

			if (this.scale == Scale.Year)
			{
				throw new InvalidProgramException();
			}
			else if (this.scale == Scale.Month)
			{
				if (this.anchor.Scale == Scale.Year)
				{
					if (this.number > 11)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddMonths(this.number);
					}
				}
				else
				{
					throw new InvalidOperationException();
				}
			}
			else if (this.scale == Scale.Week)
			{
				#region Week
				if (starts.DayOfWeek != DayOfWeek.Sunday)
				{
					starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
				}

				if (this.anchor.Scale == Scale.Year)
				{
					if (this.number > 51)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddDays(this.number * 7);
						while ((result.DayOfYear - 1) / 7 != this.number)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							if (starts.DayOfWeek != DayOfWeek.Sunday)
							{
								starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
							}
							result = starts.AddDays(this.number * 7);
						}
					}
				}
				else if (this.anchor.Scale == Scale.Month)
				{
					if (this.number > 4)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddDays(this.number * 7);
						while (result.Day / 7 != this.number)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							if (starts.DayOfWeek != DayOfWeek.Sunday)
							{
								starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
							}
							result = starts.AddDays(this.number * 7);
						}
					}
				}
				else
				{
					throw new InvalidOperationException();
				}
				#endregion
			}
			else if (this.scale == Scale.Day)
			{
				#region Day
				if (this.anchor.Scale == Scale.Year)
				{
					if (this.number > 365)
					{
						throw new InvalidOperationException();
					}
					else if (this.number > 364)
					{
						// 365 (366th - leap year)
						result = starts.AddDays(this.number);
						while (result.DayOfYear != 366)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							result = starts.AddDays(this.number);
						}
					}
					else
					{
						// 364 (365th - usual year)
						result = starts.AddDays(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Month)
				{
					if (this.number > 30)
					{
						throw new InvalidOperationException();
					}
					else if (this.number > 27)
					{
						// 30 (31th)
						// 29 (30th)
						// 28 (29th)
						result = starts.AddDays(this.number);
						while (result.Date.Day != this.number + 1)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							result = starts.AddDays(this.number);
						}
					}
					else
					{
						result = starts.AddDays(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Week)
				{
					if (this.number > 6)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddDays(this.number);
					}
				}
				else
				{
					throw new InvalidOperationException();
				}
				#endregion
			}
			else if (this.scale == Scale.Hour)
			{
				#region Hour
				if (this.anchor.Scale == Scale.Year)
				{
					if (this.number > 8783 /* 366x24 - 1 */)
					{
						throw new InvalidOperationException();
					}
					else if (this.number > 8759 /* 365x24 - 1 */)
					{
						result = starts.AddHours(this.number);
						while ((result.DayOfYear - 1) * 24 + result.Hour != this.number)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							result = starts.AddHours(this.number);
						}
					}
					else
					{
						result = starts.AddHours(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Month)
				{
					if (this.number > 773 /* 31x24 - 1*/)
					{
						throw new InvalidOperationException();
					}
					else if (this.number > 671 /* 28x24 - 1 */)
					{
						result = starts.AddHours(this.number);
						while ((result.Day - 1) * 24 + result.Hour != this.number)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							result = starts.AddHours(this.number);
						}
					}
					else
					{
						result = starts.AddHours(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Week)
				{
					if (this.number > 167)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddHours(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Day)
				{
					if (this.number > 23)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddHours(this.number);
					}
				}
				else
				{
					throw new InvalidOperationException();
				}
				#endregion
			}
			else if (this.scale == Scale.Minute)
			{
				#region Minute
				if (this.anchor.Scale == Scale.Year)
				{
					if (this.number > 527039 /* 366x24x60 - 1*/)
					{
						throw new InvalidOperationException();
					}
					else if (this.number > 525599 /* 365x24x60 - 1*/)
					{
						result = starts.AddMinutes(this.number);
						while ((result.DayOfYear - 1) * 24 * 60 + result.Hour * 60 + result.Minute != this.number)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							result = starts.AddMinutes(this.number);
						}
					}
					else
					{
						result = starts.AddMinutes(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Month)
				{
					if (this.number > 44639 /* 31x24x60 - 1 */)
					{
						throw new InvalidOperationException();
					}
					else if (this.number > 40319 /* 28x24x60 - 1 */)
					{
						result = starts.AddMinutes(this.number);
						while ((result.Day - 1) * 24 * 60 + result.Hour * 60 + result.Minute != this.number)
						{
							starts = (forward) ? this.anchor.Next(starts) : this.anchor.Previous(starts);
							result = starts.AddMinutes(this.number);
						}
					}
					else
					{
						result = starts.AddMinutes(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Week)
				{
					if (this.number > 8399 /* 24x7x60 -1 */)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddMinutes(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Day)
				{
					if (this.number > 1439 /* 24x60 - 1*/)
					{
						throw new InvalidOperationException();
					}
					else
					{
						result = starts.AddMinutes(this.number);
					}
				}
				else if (this.anchor.Scale == Scale.Hour)
				{
					if (this.number > 59)
					{
						throw new NotSupportedException();
					}
					else
					{
						result = starts.AddMinutes(this.number);
					}
				}
				else
				{
					throw new InvalidOperationException();
				}
				#endregion
			}
			else if (this.scale == Scale.Second)
			{
				result = starts.AddSeconds(this.number);
			}
			else
			{
				throw new NotSupportedException(this.scale.ToString());
			}

			if (forward)
			{
				if (result <= from)
				{
					if (this.scale == Scale.Week)
					{
						starts = this.anchor.Next(starts);
						if (starts.DayOfWeek != DayOfWeek.Sunday)
						{
							starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
						}
					}
					else
					{
						starts = this.anchor.Next(starts);
					}
					result = this.Go(starts, from, forward);
				}
			}
			else
			{
				if (result >= from)
				{
					if (this.scale == Scale.Week)
					{
						starts = this.anchor.Previous(starts);
						if (starts.DayOfWeek != DayOfWeek.Sunday)
						{
							starts = starts.AddDays(-(int) starts.DayOfWeek).AddDays(7);
						}
					}
					else
					{
						starts = this.anchor.Previous(starts);
					}
					result = this.Go(starts, from, forward);
				}
			}

			return result;
		}


		public DateTime Previous(DateTime from)
		{
			return this.Go((this.anchor.AtPoint(from)) ? from : this.anchor.Previous(from), from, false);
		}

	}
}

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, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
United States United States
C# .NET developer since 2003

Comments and Discussions