Click here to Skip to main content
15,884,739 members
Articles / Web Development / IIS

Date control with support for languages and different date formats

Rate me:
Please Sign up or sign in to vote.
4.14/5 (11 votes)
31 May 20054 min read 93.3K   713   47  
Using .NET's System.Globalization class for retrieving month names in forgein lanaguages, and the DateTimeFormatInfo for keeping your dates the correct way around.
#region Namespaces
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web;
using System.ComponentModel;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Web.UI.Design;
using System.Collections;
using System.Text;

using System.Globalization;
// resolve ambiguous reference
using AttributeCollection = System.ComponentModel.AttributeCollection;
#endregion

namespace i386.UI
{
	/// <summary>
	/// Drop down date control which support date formatting and different cultures.
	///  Author: Gavin Lyons, i386.com
	///  Version: 0.2 - 18 May 2005.
	///  
	///  --- You must leave this Summary section with the code.
	/// </summary>
	[DefaultProperty("Value")]
	public class DropDownDateTime: System.Web.UI.Control, INamingContainer, IPostBackDataHandler
	{
		private string _Culture;
		private bool _DebugMode=false;
		//MM/dd/yyyy for US dd/MM/yyyy for UK, this make the default setting automatic "		
		private string _DateFormat=System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
		private string _MonthFormat = "MMMM";
		private bool _SelectCurrentDate = true;
		private bool _EnableSetDate=false;
		private bool _TimeInput=false;
		private int _YearsForward=0;
		private int  _YearsBack=0;
		

		/// <summary>
		/// Specifies a number of years from the current year. Value can also be negative
		/// </summary>
		[Bindable(true), 
		Description("Specifies how the month should be display MMM or MMMM"), 
		Category("Behavior"), 
		DefaultValue(null)]
		public string MonthFormat
		{
			get {return _MonthFormat;}
			set {_MonthFormat= value;}
		}


		public string Value 
		{
			get 
			{
				string s = (string)ViewState["Value"];
				if(s == null) return String.Empty;
				else return s;
			}				
			set 
			{
				this.SetSelected(value);
				ViewState["Value"] = value;
			}
		}

		/// <summary>
		/// Show the hidden box with the DateTime value, also display Culture and DateFormat. Useful for Debuging purposes.
		/// </summary>
		public bool DebugMode
		{
			get {return _DebugMode;}
			set {_DebugMode=value;}
		}
		/// <summary>
		/// Displays a TimeInput box - THIS FEATURE IS NOT WORKING YET!
		/// </summary>
		[Bindable(true), 
		Description("TimeInput"), 
		Category("Behavior"), 
		DefaultValue(false)]
		public bool TimeInput
		{
			get {return _TimeInput;}
			set {_TimeInput=value;}
		}
		/// <summary>
		/// Specifies a number of years from the current year. Value can also be negative
		/// </summary>
		[Bindable(true), 
		Description("Specifies a number of years from the current year. Value can also be negative"), 
		Category("Behavior"), 
		DefaultValue(0)]
		public int YearsBack
		{
			get {return _YearsBack;}
			set {_YearsBack = value;}
		}
		/// <summary>
		/// Specifies a number of years from the current year. Value can also be negative
		/// </summary>
		[Bindable(true), 
		Description("Specifies a number of years from the current year. Value can also be negative"), 
		Category("Behavior"), 
		DefaultValue(0)]
		public int YearsForward
		{
			get {return _YearsForward;}
			set {_YearsForward= value;}
		}
		/// <summary>
		/// Enables a checkbox to activate the date dropdownlists, if the checkbox is not set then the date is blank!!!
		/// </summary>
		[Bindable(true), 
		Description("Enables a checkbox to activate the date dropdownlists, if the checkbox is not set then the date is blank!!!"), 
		Category("Behavior"), 
		DefaultValue(false)]
		public bool EnableSetDate
		{
			get {return _EnableSetDate;}
			set {_EnableSetDate=value;}
		}

		/// <summary>
		/// Specifies the date format output dd/MM/yyyy MM-dd-yyyy etc.. 
		/// If this is not set then the server date format is taken.  
		/// Please note MMM ddd MMMM dddd are not valid!!
		/// </summary>
		[Bindable(true), 
		Description("Specifies the date format output dd/MM/yyyy MM-dd-yyyy etc.. If this is not set then the server date format is taken. Please note MMM ddd MMMM dddd are not valid!!"), 
		Category("Behavior"), 
		DefaultValue(-1)]
		public string DateFormat
		{
			get {return _DateFormat;}
			set {_DateFormat = value;}
		}
		/// <summary>
		/// Specifies the date language, example en-GB for english, fr-FR for french etc..
		/// If this is not set the server culture is taken.
		/// </summary>
		[Bindable(true), 
		Description("Specifies the date language, example en-GB for english, fr-FR for french etc.. If this is not set the server culture is taken."), 
		Category("Behavior"), 
		DefaultValue(-1)]
		public string Culture
		{
			get {return _Culture;}
			set {_Culture = value;}
		}
		public bool SelectCurrentDate
		{
			get {return _SelectCurrentDate;}
			set {_SelectCurrentDate=value;}	
		}
		#region ViewState Properties
		private int SelectedDay
		{
			get
			{
				if(ViewState["SelectedDay"] == null)
					return -1;
				else
					return (int)ViewState["SelectedDay"];
			}
			set
			{
				ViewState["SelectedDay"] = value;
			}
		}

		private int SelectedMonth
		{
			get
			{
				if(ViewState["SelectedMonth"] == null)
					return -1;
				else
					return (int)ViewState["SelectedMonth"];
			}
			set
			{
				ViewState["SelectedMonth"] = value;
			}
		}

		private int SelectedYear
		{
			get
			{
				if(ViewState["SelectedYear"] == null)
					return -1;
				else
					return (int)ViewState["SelectedYear"];
			}
			set
			{
				ViewState["SelectedYear"] = value;
			}
		}
		private string SelectedTime
		{
			get
			{
				return (string)ViewState["SelectedTime"];
			}
			set
			{
				ViewState["SelectedTime"] = value;
			}
		}
		
		private bool Checked
		{
			get 
			{
				if(ViewState["Checked"] == null)
					return false;
				else
					return (bool)ViewState["SelectedYear"];
			}
			set
			{
				ViewState["Checked"] = value;
			}
		}
		#endregion
		private static readonly object EventControlChanged = new object();
		public event EventHandler Change;
		public DropDownDateTime()
		{
			this.Load +=new EventHandler(DropDownDateTime_Load);
			this.Init +=new EventHandler(DropDownDateTime_Init);
		}
		private void DropDownDateTime_Init(object sender, EventArgs e)
		{
			if(Page != null)
			{
				// Register the control with the page's postback mechanism, or
				// the control will not update on Postback
				Page.RegisterRequiresPostBack(this);
			}
			//			if(this.DetermineRenderUplevel() && this.EnableClientScript)
			// Use the EnableClientScript property to specify whether client-side validation is enabled.
			// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemWebUIWebControlsBaseValidatorClassEnableClientScriptTopic.asp
			// The DetermineRenderUplevel method is a helper function used primarily by the RenderUplevel property to determine whether the client's browser supports uplevel rendering. For a browser to support uplevel rendering, it must support Internet Explorer Document Object Model (DOM) version 4 or later and ECMAScript version 1.2 or later.
			// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwebuiwebcontrolsbasevalidatorclassdeterminerenderupleveltopic.asp

			if (!Page.IsClientScriptBlockRegistered("DropDownDateTimeScript"))
			{
				// Might be an idea to put the Javascript Functions in the aspnet_client directory, so browsers could cache the JS functions.
				// interesting URL http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/webresource.asp
				#region Main Javascript Function
				string JSCode= @"
// Author Gavin Lyons, i386.com
//function for returning how many days there are in a month including leap years	
function DaysInMonth(WhichMonth, WhichYear)
{	
  var DaysInMonth = 31;
  if (WhichMonth == 4 || WhichMonth == 6 || WhichMonth == 9 || WhichMonth == 11) DaysInMonth = 30;
  if (WhichMonth == 2 && (WhichYear/4) != Math.floor(WhichYear/4))	DaysInMonth = 28;
  if (WhichMonth == 2 && (WhichYear/4) == Math.floor(WhichYear/4))	DaysInMonth = 29;
  return DaysInMonth;
}
//function to change the available days in a months
function ChangeOptionDays(Which, DateFormat)
{
	if (document.getElementById) { 
		DaysObject = document.getElementById(Which + '_Day');
		MonthObject = document.getElementById(Which + '_Month');
		YearObject = document.getElementById(Which + '_Year');
		TimeObject = document.getElementById(Which + '_Time');
		CheckBoxObject= document.getElementById(Which + '_CheckBox');
		DateBoxObject = document.getElementById(Which);
	} 
	else if (document.layers) { 
		DaysObject = document.layers[Which + '_Day'];
		MonthObject = document.layers[Which + '_Month'];
		YearObject = document.layers[Which + '_Year'];
		TimeObject = document.layers[Which + '_Time'];
		CheckBoxObject= document.layers[Which + '_CheckBox'];
		DateBoxObject = document.layers[Which]; 
	} 
	else if (document.all) { 
		DaysObject = document.all[Which + '_Day'];
		MonthObject = document.all[Which + '_Month'];
		YearObject = document.all[Which + '_Year'];
		TimeObject = document.all[Which + '_Time'];
		CheckBoxObject= document.all[Which + '_CheckBox'];
		DateBoxObject = document.all[Which];
	} 
	Day= DaysObject[DaysObject.selectedIndex].text;
	Month = MonthObject[MonthObject.selectedIndex].value;
	Year = YearObject[YearObject.selectedIndex].text;
	DaysForThisSelection = DaysInMonth(Month, Year);
	CurrentDaysInSelection = DaysObject.length;
	if (Day!='--' && Year!='--' && Month!='--' ) {
	if (CurrentDaysInSelection > DaysForThisSelection)
	{
		for (i=0; i<(CurrentDaysInSelection-DaysForThisSelection); i++)
		{
			DaysObject.options[DaysObject.options.length - 1] = null;
		}
	}
	if (DaysForThisSelection > CurrentDaysInSelection)
	{
		for (i=0; i<(DaysForThisSelection-CurrentDaysInSelection); i++)
		{
			NewOption = new Option(DaysObject.options.length + 1);
			DaysObject.add(NewOption);
		}
	}
	if (DaysObject.selectedIndex < 0) DaysObject.selectedIndex == 0;
	DateBoxObject.value=formatDate(new Date(Year, (Month-1), Day), DateFormat);
	if (CheckBoxObject)
	{
		if (CheckBoxObject.checked)
		{
			DaysObject.disabled=false;MonthObject.disabled=false;YearObject.disabled=false;
		}
		else
		{
			DaysObject.disabled=true;MonthObject.disabled=true;YearObject.disabled=true;DateBoxObject.value='';
		}
	}
	} else {DateBoxObject.value=''}	
}

  
  // Date Convertion functions
  function formatDate(vDate, vFormat){ 
    var vDay              = addZero(vDate.getDate()); 
    var vMonth            = addZero(vDate.getMonth()+1); 
    var vYearLong         = addZero(vDate.getFullYear()); 
    var vYearShort        = addZero(vDate.getFullYear().toString().substring(3,4)); 
    var vYear             = (vFormat.indexOf('yyyy')>-1?vYearLong:vYearShort) 
    var vHour             = addZero(vDate.getHours()); 
    var vMinute           = addZero(vDate.getMinutes()); 
    var vSecond           = addZero(vDate.getSeconds()); 
    var vDateString       = vFormat.replace(/dd/g, vDay).replace(/MM/g, vMonth).replace(/y{1,4}/g, vYear) 
    vDateString           = vDateString.replace(/hh/g, vHour).replace(/mm/g, vMinute).replace(/ss/g, vSecond) 
    return vDateString 
  } 
  function addZero(vNumber){return ((vNumber < 10) ? '0' : '') + vNumber;} 
";
				#endregion
				Page.RegisterClientScriptBlock("PickListScript", "<script language=\"javascript\" type=\"text/javascript\">" + JSCode + "</script>");
			}

		}
		private void DropDownDateTime_Load(object sender, EventArgs e)
		{
			//Be sure child controls exist so they can be manipulated
			EnsureChildControls();
		}
		protected override void CreateChildControls()
		{
			DateTime dt = DateTime.Today;
			// Use CurrentDate if Value is empty and SelectCurrentDate is true.
			if (SelectCurrentDate && this.Value=="")
			{
				// Use Current Date
				SelectedDay  = dt.Day;
				SelectedMonth = dt.Month;
				SelectedYear = dt.Year;
				DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
				formatInfo.FullDateTimePattern = DateFormat;
				this.Value = dt.ToString(DateFormat,formatInfo);
			}

			// Days
			DropDownList ddlboxDay = new DropDownList();
			ddlboxDay.ID ="Day";
			ddlboxDay.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
			for ( int nDay = 1; nDay<32; nDay++)	ddlboxDay.Items.Add(nDay.ToString());
			
			// So we can restore the Culture later
			CultureInfo ExistingCulture = System.Threading.Thread.CurrentThread.CurrentCulture; 
			// Culture - changes language of months	
			if (Culture!=null)	System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(Culture);	
			// Months
			DropDownList ddlboxMonth = new DropDownList();
			ddlboxMonth.ID ="Month";
			ddlboxMonth.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
			for ( int nMonth=1; nMonth<=12; nMonth++)
			{ 
				DateTime MonthDate = new DateTime(2000,nMonth,1);
				ddlboxMonth.Items.Add(new ListItem(MonthDate.ToString(this.MonthFormat),nMonth.ToString()));
			}



			// Years (Forward and Back properties)	
			DropDownList ddlboxYear = new DropDownList();
			ddlboxYear.ID ="Year";
			ddlboxYear.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
			ddlboxYear.ID ="Year";
			
			if (YearsBack>=0)
			{
				for (int nYear = -YearsBack; nYear<=YearsForward; nYear++)
				{
					int ddlYear =dt.Year+nYear;
					ddlboxYear.Items.Add(ddlYear.ToString());
				}
			}
			else
			{
				for (int nYear = YearsForward; nYear<=-YearsBack; nYear++)
				{
					int ddlYear =dt.Year-nYear;
					ddlboxYear.Items.Add(ddlYear.ToString());
				}
			}

			// Select the DropDownList for the year
			if (SelectedYear>0)
			{
				if  (ddlboxYear.Items.FindByValue(SelectedYear.ToString())!=null) // See if the year is in the list.
				{
					ddlboxYear.Items.FindByValue(SelectedYear.ToString()).Selected = true;
				}
			}
			if (SelectedMonth>0)	ddlboxMonth.Items.FindByValue(SelectedMonth.ToString()).Selected = true;
			if (SelectedDay>0)		ddlboxDay.Items.FindByValue(SelectedDay.ToString()).Selected = true;

			// Add Child Control
			Controls.Add(ddlboxDay);
			Controls.Add(ddlboxMonth);
			Controls.Add(ddlboxYear);

			// Time - Not Fully test or implemented yet!
			if (TimeInput)
			{ 
				TextBox txtTime = new TextBox();
				txtTime.Width = 60;
				txtTime.Text = SelectedTime; // Set for ViewState Value.
				txtTime.Attributes.Add("Size","8"); // Firefox support
				txtTime.ID = "Time";
				txtTime.Attributes.Add("onchange","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
				LiteralControl lc = new LiteralControl("&nbsp;");
				Controls.Add(lc);				
				Controls.Add(txtTime);
			}

			if (EnableSetDate)
			{	// Checkbox
				CheckBox chkDate = new CheckBox();
				chkDate.ID = "CheckBox";
				chkDate.Checked = Checked;		
				chkDate.Attributes.Add("onclick","ChangeOptionDays('" + this.ClientID +"','" + DateFormat + "');");
				Controls.Add(chkDate);
				if (!Checked)
				{
					ddlboxYear.Enabled=false;
					ddlboxMonth.Enabled=false;
					ddlboxDay.Enabled=false;
					//this.Value="";
				}
				else
				{
					ddlboxYear.Enabled=true;
					ddlboxMonth.Enabled=true;
					ddlboxDay.Enabled=true;
				}
			}
			// Restore 
			System.Threading.Thread.CurrentThread.CurrentCulture = ExistingCulture;
		}

		protected virtual void OnChanged(EventArgs e)
		{
			EventHandler ControlChanged = (EventHandler)Events[EventControlChanged];
			if(ControlChanged != null)
				ControlChanged(this, e);
		}
		public event EventHandler Changed
		{
			add
			{
				Events.AddHandler(EventControlChanged, value);
			}
			remove
			{
				Events.RemoveHandler(EventControlChanged, value);
			}
		}
		protected virtual void OnChange(EventArgs e)
		{
			if (Change != null)
				// Raise event.
				Change(this, e);
		}
		protected override void OnPreRender(EventArgs e)
		{
			base.OnPreRender(e);
			if (Page != null)
			{
			}
		}
		protected override void Render(HtmlTextWriter output)
		{
			if (DebugMode)
			{
				DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
				output.Write("<input type=\"text\" name=\"" + this.ClientID + "\" id=\"" + this.ClientID + "\"  value=\"" + this.Value + "\"><br/>" + DateFormat + " "
					+ System.Threading.Thread.CurrentThread.CurrentCulture.DisplayName + "<br/>" + 
					Value + " MM " + SelectedMonth + " dd " + SelectedDay + " yyyy "  + SelectedYear + " time " + SelectedTime + "<br/>");
			}
			else
			{
				output.Write("<input type=\"hidden\" name=\"" + this.ClientID + "\" id=\"" + this.ClientID + "\"  value=\"" + this.Value + "\">");
			}
			EnsureChildControls();
			base.Render(output);
		}
		// Override RaisePostDataChangedEvent method.
		void IPostBackDataHandler.RaisePostDataChangedEvent()
		{
			// Call the event method. This is optional.
			OnChange(EventArgs.Empty);
		}
		bool IPostBackDataHandler.LoadPostData(string postDataKey, 
			System.Collections.Specialized.NameValueCollection postCollection)
		{
			int Day = 0;
			int Month = 0;
			int Year = 0;
			string Time = "";
			bool Changed = false;
			// Updates the Day Viewstate value
			if(postCollection[this.UniqueID.ToString() + ":Day"] != "")
			{
				Day = Int32.Parse(postCollection[this.UniqueID.ToString() + ":Day"]);
				if (Day != this.SelectedDay)
				{
					this.SelectedDay = Day;
					Changed = true;
				}
			}
			else
			{ // Probably don't need this bit
				if(this.SelectedDay != -1)
				{
					this.SelectedDay = -1;
					Changed = true;
				}
			}
			// Updates the Month Viewstate value
			if(postCollection[this.UniqueID.ToString() + ":Month"] != "")
			{
				Month = Int32.Parse(postCollection[this.UniqueID.ToString() + ":Month"]);
				if (Month != this.SelectedMonth)
				{
					this.SelectedMonth = Month;
					Changed = true;
				}
			}
			else
			{ // Probably don't need this bit
				if(this.SelectedMonth != -1)
				{
					this.SelectedMonth = -1;
					Changed = true;
				}
			}
			// Updates the Year Viewstate value 
			if(postCollection[this.UniqueID.ToString() + ":Year"] != "")
			{
				Year = Int32.Parse(postCollection[this.UniqueID.ToString() + ":Year"]);
				if (Year != this.SelectedYear)
				{
					this.SelectedYear = Year;
					Changed = true;
				}
			}
			else
			{
				if(this.SelectedYear != -1)
				{
					this.SelectedYear = -1;
					Changed = true;
				}
			}
			// Updates the Time Viewstate value  *** Implemented yet!
			if(postCollection[this.UniqueID.ToString() + ":Time"] != "")
			{
				Time = postCollection[this.UniqueID.ToString() + ":Time"];
				if (Time  != this.SelectedTime )
				{
					this.SelectedTime  = Time ;
					Changed = true;
				}
			}

			// Checkbox
			/*
			if(postCollection[this.UniqueID.ToString() + ":Checkbox"] != "")
			{
				Year = bool.Parse(postCollection[this.UniqueID.ToString() + ":Year"]);
				if (Year != this.SelectedYear)
				{
					this.SelectedYear = Year;
					Changed = true;
				}
			}
			*/
			if(this.SelectedDay == -1 && this.SelectedMonth == -1 && this.SelectedYear == -1)
				this.Value = "";
			else
			{
				// Build a DateTime string based on the DateFormat
				DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
				formatInfo.FullDateTimePattern = DateFormat;
				DateTime dt = new DateTime(this.SelectedYear, this.SelectedMonth, this.SelectedDay);
				this.Value = dt.ToString(DateFormat,formatInfo);
			}
			return Changed;
		}

		private void SetSelected(string StoredValue)
		{
			DateTimeFormatInfo formatInfo = new DateTimeFormatInfo();
			formatInfo.FullDateTimePattern = DateFormat;
			DateTime dt = DateTime.ParseExact(StoredValue,DateFormat,formatInfo);	
			SelectedDay  = dt.Day;
			SelectedMonth = dt.Month;
			SelectedYear = dt.Year;	
		}
	}
}


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
Software Developer (Senior)
Austria Austria
Programmer, Cook, Photographer I guess that's me.

http://www.i386.com

http://blog.glyons.at

Comments and Discussions