Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Date control with support for languages and different date formats

0.00/5 (No votes)
31 May 2005 1  
Using .NET's System.Globalization class for retrieving month names in forgein lanaguages, and the DateTimeFormatInfo for keeping your dates the correct way around.

Introduction

There are many Date controls in the Internet including many here at CodeProject. However few don't tap into .NET's System.Globalization class for retrieving the month names in foreign languages. Names for months in Afrikaans to Vietnamese can be achieved without any knowledge of the spoken language. Furthermore I have also added the possibility to work with any date format I choose. This control works well with US or European date formats. The control also has Visual Studio designer support.

Background

The System.Globalization namespace contains classes that define culture-related information, including the language, the country/region, the calendars in use, the format patterns for dates, currency, and numbers.

I have used the David Truxall control found on CodeProject as a template for the control, along with the following added features:

Properties

Property Default Value Description
YearsForward 0 (Optional) An integer for setting the number of years into the future that the control renders from the current year.
YearsBack 0 (Optional) An integer for setting the number of years into the past that the control renders from the current year.
Culture (Optional) A string same as Culture Name for displaying the month names. For example, en-gb es-ES. See MSDN for a complete list. If none is set it uses the server's regional code.

- It has no effect on the value of the control.
MonthFormat MMMM (Optional) A string for setting the month text in the control.

Example MMM, MMMM, MM.

- It has no effect on the value of the control.
DateFormat Use the format on the server as default A string for setting the output date value format.

For example, dd/MM/yyyy MM-dd-yyyy yyyyMMdd
Value A value for setting the date.

* Please note if you use dd/MM/yyyy make sure the value is set with double-digits, for example 02/04/2005 is valid while 2/4/2005 is not valid.
SelectCurrentDate true A Boolean to set the value to current date when the value is not specified.

Examples for use:

<%@ Register TagPrefix="cc1" 
  Namespace="i386.UI" Assembly="i386.UI" %>

German with short month text, 10 years into future and two years into the past from the current year:

<cc1:dropdowndatetime  id="DropDownDateTime1" runat="server" YearsForward="2" 
   YearsBack="10" Culture="de-DE"   SelectCurrentDate="False" MonthFormat="MMM">
</cc1:dropdowndatetime>

US date formatting with the date:

<cc1:dropdowndatetime id="Dropdowndatetime4" runat="server" 
  dateFormat="MM/dd/yyyy" Value="11/02/2005">
</cc1:dropdowndatetime>

The YearsForward and YearsBack properties can have negative values, which controls the range, as well as the order:

YearsForward YearsBack Years Displayed
-11 20 1985 ... 1994
11 -20 1994 ... 1985
11 20 1985 ... 2016

How the control works

Firstly, the DateFormat is set to the current one used on the server as default unless the DateFormat properties are set.

private string _DateFormat= 
      System.Threading.Thread.CurrentThread.
             CurrentCulture.DateTimeFormat.ShortDatePattern;        
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;
    }
}


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;    
}

The control implements IPostBackDataHandler to manage the resetting of the value of the control when it changes on PostBack. This is the same as David Truxall's except for building of the Value property for the postCollection.

bool IPostBackDataHandler.LoadPostData(string postDataKey, 
     System.Collections.Specialized.NameValueCollection postCollection)
{
    ....
    ....                
    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);
    }
}

Building the child controls

When SelectCurrentDate is set to true (by default) and the Value of the control is left blank we set the control to the current date. We use DateTimeFormatInfo and DateFormat to correctly format the date into a string for the Value property. If SelectCurrentDate is set to false the control is set to January 1st of the first year listed in the year drop box. We use the JavaScript to restrict days on leap years and also to keep the Value input box updated. The Value is kept up to date by the client and server values.

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()));
    }
     // Restore 

    System.Threading.Thread.CurrentThread.CurrentCulture = 
                                              ExistingCulture;


    // 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)
    {
        // See if the year is in the list.

        if (ddlboxYear.Items.FindByValue(SelectedYear.ToString())!=null) 
        {
           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);

Debugging mode

It is used to check what is happening with the control. The DebugMode outputs the Value, ViewStates, CultureInfo and DateFormat. To set the DebugMode on, use DebugMode="true".

<cc1:dropdowndatetime DebugMode=true id="DropDownDateTime1" runat="server">
</cc1:dropdowndatetime>

Browser compatibility

This is only a short list of browsers I've tested with. I don't have Netscape installed on my PC.

Browser Under OS
Safari 1.0.3
Mac System 9+ Fully
Netscape 4.77 Mac System 10.2.8 No
Opera 6.0.3 Mac System 10.2.8 Fully
Internet Explorer 5.1, 5.2 Mac System 9+ Fully
Firefox 1.x Windows XP Fully
Internet Explorer 4.0 + Windows XP Fully
Netscape ?? Windows ??

Internet Explorer 3.0 will need to use server validation. Please let me know if a certain browser doesn't function correctly.

JavaScript support

From the debugging mode you may notice the hidden input box. This Input box can be used in JavaScript before postback is made to the server.

Updates, versions and bug fixes

  • 18th May 2005, Version 0.2
    • Added and fixed the negative values for YearsForward and YearsBack properties.
    • Support for older JavaScript browsers.

Future enhancements

  • Support and testing for old and non/disable JavaScript browsers using server validation.
  • EnableSetDate property is not completed yet. This feature enables/disable the date box by using a checkbox and allows blank dates.
  • Server validation for date and leap year. Included in the source code is a DateTimeValidator.
  • Another feature would be to support a Value whose year is outside the range of YearsForward and YearsBack properties.
  • Time support.

Feel free to comment or add features yourself. If you rate this page lower please leave a comment in the forum below.

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