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
{
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;
if (SelectCurrentDate && this.Value=="")
{
SelectedDay = dt.Day;
SelectedMonth = dt.Month;
SelectedYear = dt.Year;
DateTimeFormatInfo formatInfo =
new DateTimeFormatInfo();
formatInfo.FullDateTimePattern = DateFormat;
this.Value = dt.ToString(DateFormat,formatInfo);
}
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());
CultureInfo ExistingCulture =
System.Threading.Thread.CurrentThread.CurrentCulture;
if (Culture!=null)
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo(Culture);
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()));
}
System.Threading.Thread.CurrentThread.CurrentCulture =
ExistingCulture;
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());
}
}
if (SelectedYear>0)
{
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;
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.