Ideally, every application built would be designed with correct date handling techniques. In practice, applications are often built using ad hoc date formatting to match a corporate culture, the default format on a company's server, or the favorite format of the lead developer. Also, many applications are not locale aware or were not designed to be deployed in an environment where locale issues were not considered important. Because of this it is extremely important to know the date formats in use for input and output when building applications that will integrate with other systems or databases and to handle these formats explicitly.
As with anything else in programming, assumptions are dangerous and consistency is desirable so the key is to follow some basic guidelines when working with dates:
- Use a consistent date format in your application and publish it in the documentation;
- At the very minimum, ensure you have some mechanism in place to deal with ambiguous dates;
- When accepting user input, do not assume the user will provide the date in the correct format without assistance;
- Always convert dates to date objects (e.g.
DateTime in C#) as soon as possible when accepting input from a user, application, or database; and
- Always explicitly format dates when writing output.
Date ambiguity is a serious problem in applications. Different date formats are in use internationally and different companies use different date formats even among their own applications. Whenever you are accepting date information as an input you need to ensure that the ambiguous dates are interpreted correctly. Examples of ambiguous dates: "01/01/2004" is always January 1st, 2004 but "01/02/2004" could either be January 2nd, 2004 or February 1st, 2004 depending on the date format. Correct handling of ambiguous dates can be done by always using explicit input and output formats for your dates.
Formatting Dates As Input
Dates can be input by users or can come from an application or database you are integrating with. You must determine the format the other application stores dates in and explicitly translate the date into your own format. It is good to do this even if the other application uses the same date format as the application you are building, because either date format may change in the future. For example, a new database may be used that uses a different default date format or the application could be deployed on a server that is configured with a different locale setting.
To ensure that translations across formats work correctly, use your knowledge of the date formats to parse out the year, month, and day for the date coming in, and explicitly build a date object from the components. The parsing technique can be very simple (e.g. using a string split into an array) but you should encode the positions of the date components in a configuration file so that it is easy to change the date format of your input. A basic example is below:
string  dateComponents;
char  tokenSep = tokenSeparator.ToCharArray();
dateComponents = date.Split( tokenSep );
dtm_1 = new DateTime( System.Convert.ToInt32( dateComponents[YEAR] ),
System.Convert.ToInt32( dateComponents[MONTH] ),
System.Convert.ToInt32( datecomponents[DAY] ) );
When receiving date input from a user interface, you should always use a calendar control, whenever possible, to make it easy for users to enter the date in the correct format. Calendar controls also prevent entering dates that are not actual calendar dates. If it is not possible to use a calendar control, you should provide separate inputs for day, month, and year. Failing this, use a text box that has a label indicating the correct format.
Regardless of the way you receive user input, it should always be validated to ensure it is in the correct format and is a valid date. You can do this when the date is converted from user input to a
DateTime object with a try/catch block to catch any invalid dates (see above). Once this is done, you can perform application specific date validation (e.g. ensuring a date is within a certain range).
Formatting Dates As Output
A date format should be explicitly stated in the web.config and used to format any outgoing dates used in output. This allows you to specify your format with certainty.
string dateFormat =
string myOutput = "Date: " + dtm_1.ToString( dateFormat );
Persistence of dates can raise issues similar to those involved in importing dates from other applications or databases because most databases you persist to will use some internal representation of the date rather than the text string you pass in. Because of this internal representation, you have to watch out for any translations being done by the database.
Let's assume you are using SQL Server and stored procedures to persist dates to a database. In this case you will be passing the date to SQL Server via a string that SQL Server will interpret as a date, according to its locale. To avoid relying on assumptions about SQL Server interpreting your dates correctly, the date format can be specified using the following SQL:
set DATEFORMAT mdy
However, this will not control the format of dates passed in as arguments to stored procedures. To guarantee a stored procedure will use your explicit date format, you can pass the dates in as varchars and explicitly cast them to datetimes in the SQL code:
declare @dtmStart SmallDateTime;
set @dtmStart = Cast( @StartDate as SmallDateTime );
This will guarantee that you have correctly sent the date to the SQL Server table in the correct format regardless of the locale setting of the SQL Server and the date format will match the internal representation expected by your application.
The most important thing when working with dates is consistency; use explicit formatting at all times. Do not make assumptions about input or output formats, even if your code is being written to run on a single machine and you never plan to integrate with any other application or database. If you follow these simple practices you should be able to make issues resulting from date format problems easier to track down and deal with, as well as removing the guesswork from date handling in your applications.