You are on page 1of 6

Access Answers: Access developer needs date

Doug Steele
Doug will address commonly asked questions from Access developers. This month, he looks at
problems dealing with date values.
I'm running into problems using dates, especially among users with varying regional settings.

This problem is very common, and can cause headaches when developing for users in different countries.
First, be aware that dates are not stored in any particular format. Rather, the date/time variable type is an
IEEE 64-bit (8-byte) floating-point number. The integer part of the number represents the date as the
number of days relative to 30 Dec., 1899 (i.e.: 04 Apr, 1897 is -1000, 29 Dec, 1899 is -1, 04 Jan, 1899 is
+5, 05 Jun, 2003 is +37777 and so on). The decimal part of the number represents the time as a fraction of a
day (i.e.: 3:00 AM is .125, 8:00 AM is .3333333, Noon is .5, 6:00 PM is .75 and so on)
It doesn't matter how the date was input. As long as your application interpreted it correctly when it was
input (more about this later), it will be stored such that it can be used regardless of the date format. Note
that this also means that you must provide a complete date if you're going to use a date/time field: if you
only supply a partial date, Access is going to do its best to "fill in the gaps" and provide you with a
complete date:
?Format("05/30", "dd mmm, yyyy")
30 May, 2003
?Format("10/2004", "dd mmm, yyyy")
01 Oct, 2004

What it boils down to is that it's irrelevant what Regional Settings are in effect when the data is entered, the
dates will be stored consistently.
The second area to discuss is how to use dates in your application. There are essentially 3 options for literal
dates:
1. You can delimit the date with octothorpes (#)
2. You can delimit the date with quotes
3. You can enter the number for the date (as discussed above)
(Over the years, I've got in a number of arguments with people about whether # is the pound symbol, the hash symbol,
the sharp sign or the number sign. To avoid any such discussion, I'm going to refer to that character as the octothorpe.
See http://www.sigtel.com/tel_tech_octothorpe.html for more details. As well, for the purposes of simplification, I'm
going to ignore time in the following discussion. What I'm describingdoesn't change with the addition of time.
When you delimit your dates with octothorpes (#), it doesn't matter what the user locale settings has for
Short Date format. Access is very specific about how it treats dates delimited this way. Assuming that the
date is all numeric, the first choice is to assume that the date is in mm/dd/(yy)yy format. Only if it cannot
interpret the input as a date in that format is it going to try using a different format for interpretation. There
is some flexibility in how you represent octothorpe-delimited dates: unambiguous settings like yyyy-mm-dd
or dd mmm, (yy)yy will work as well. As you'll see, though,dd/mm/(yy)yy dates cannot be used reliably
with octothorpe-delimiters (and yes, I realize mm/dd/(yy)yy isn't unambiguous, but you have to remember
that Access was developed in the US).
When you delimit your dates with quotes, Access will take the string and convert it to a date using the
locale settings of the current user.
The following examples should illustrate the differences between the three approaches.
In this first example, the Short Date format is set to yyyy-mm-dd:
?Format(Date())
2003-05-31
?Format(#01/02/03#, "dd mmm, yyyy")
02 Jan, 2003
?Format("01/02/03", "dd mmm, yyyy")
03 Feb, 2001
?Format(37777, "dd mmm, yyyy")
05 Jun, 2003

In this example, the Short Date format is set to mm/dd/yyyy (the same results will be obtained if the Short
Date format is mm/dd/yy):
?Format(Date())
05/31/2003
?Format(#01/02/03#, "dd mmm, yyyy")
02 Jan, 2003
?Format("01/02/03", "dd mmm, yyyy")
02 Jan, 2003
?Format(37777, "dd mmm, yyyy")
05 Jun, 2003

Finally, for this example, the Short Date format is set to dd/mm/yyyy (the same results will be obtained if
the Short Date format is dd/mm/yy):
?Format(Date())
31/05/2003
?Format(#01/02/03#, "dd mmm, yyyy")
02 Jan, 2003
?Format("01/02/03", "dd mmm, yyyy")
01 Feb, 2003
?Format(37777, "dd mmm, yyyy")
05 Jun, 2003

As you can see, the date is interpreted identically in all three cases when delimited with octothorpes, but
differently in all three cases when delimited with quotes. (As expected, using a number as a date is treated
consistently, regardless of the Short Date format.)
What happens, though, if what's being passed isn't valid for the Short Date format that's in effect? The
following examples show the difference when using 13/12/11 (which obviously isn't valid in mm/ dd/yyyy
format, since there's no 13th month):
With the Short Date format set to yyyy-mm-dd:
?Format(Date())
2003-05-31
?Format(#13/12/11#, "dd mmm, yyyy")
11 Dec, 2013
?Format("13/12/11", "dd mmm, yyyy")
11 Dec, 2013

With the Short Date format set to mm/dd/yyyy:


?Format(Date())
05/31/2003
?Format(#13/12/11#, "dd mmm, yyyy")
11 Dec, 2013
?Format("13/12/11", "dd mmm, yyyy")
11 Dec, 2013

With the Short Date format set to dd/mm/yyyy:


?Format(Date())
31/05/2003
?Format(#13/12/11#, "dd mmm, yyyy")
11 Dec, 2013
?Format("13/12/11", "dd mmm, yyyy")
13 Dec, 2011

Again, in all three cases the date was interpreted consistently when delimited with octothorpes (wrongly,
possibly, but consistently!), but differently when delimited with quotes.
As was shown above, using octothorpes (#) as delimiters is consistent, regardless of the user's locale
settings.
I'll admit that the examples above were somewhat contrived, as they don't use 4-digit years. When you use
4-digit years, the results are more consistent, since now Access only has to decide between month and day.
Regardless of whether the Short Date format is yyyy-mm-dd, mm/dd/yyyy or dd/mm/yyyy, you will get the
following results:
?Format(#13/12/2011#, "dd mmm, yyyy")
13 Dec, 2011
?Format("13/12/2011", "dd mmm, yyyy")
13 Dec, 2011
?Format(#12/13/2011#, "dd mmm, yyyy")
13 Dec, 2011
?Format("12/13/2011", "dd mmm, yyyy")
13 Dec, 2011

I'm constantly surprised, though, how many people don't use 4 digit years. Wasn’t there some noise in the
press a few years ago about this?
Of course, if you can be confident that your dates are valid, you needn't worry about incorrect
interpretation. The only thing that matters is to present them for use in a manner that Access (or Jet, if
you're going running a query) can handle them.
Since you are developing the application, you have complete control over which approach your code will
use to represent dates. My recommendation is that you create a wrapper function to format all of your dates
whenever you want to use them in VBA code. In this way, you can be assured that the user's locale settings
won't matter.
A favourite of mine is the following:
Function SQLDate(DateIn As Variant) As String

If IsDate(DateIn) Then
SQLDate = Format$(DateIn, "\#mm\/dd\/yyyy\#")
End If

End Function

but you could just as easily use


Function SQLDate(DateIn As Variant) As String

If IsDate(DateIn) Then
SQLDate = Format$(DateIn, "\#yyyy\-mm\-dd\#")
End If

End Function

(For the curious, the \ character is an escape character to ensure that what follows it is shown exactly as it appears.
Since # has special meaning in formatting, you need to escape it to ensure that you get # and not a digit. Similarly, \/
ensures that you get / as the separator between the date parts. If you didn't include the escape, you would get whatever
the user has specified as the date separator in their locale settings, and that won't always be interpreted correctly)
Now, you can use this, for example, in the WhereCondition of the OpenReport method:
DoCmd.OpenReport "MyReport", acViewPreview, , & _
"InvoiceDate > " & SQLDate(Me!txtInvoiceDT)

(where txtInvoiceDT is a text box on your form), or in generating an SQL string to be used:
strSQL = "SELECT Field1, Field2 " & _
"FROM MyTable " & _
"WHERE ActiveDTM Between " & _
SQLDate(Me!txtStartDT) & _
" AND " & SQLDate(Me!txtEndDT)

(where txtStartDT and txtEndDT are text boxes on your form).


One advantage of wrapping all your dates in such a function is that it becomes easy to reformat your SQL
strings if you start using a different DBMS. For example, while Jet prefers dates to look like
#mm/dd/yyyy#, SQL Server prefers ' yyyy-mm-dd', and the ODBC canonical format is {dyyyy-mm-dd'}
' If
you know that you're going to migrate from Jet to another DBMS, you can build this into yourSQLDate
function. By passing a second parameter to the function, you can have it automatically return the date in the
appropriate format for use with the specific DBMS you're using.
Function SQLDate(DateIn As Variant, _
Optional DataSource As String = "Jet" _
) As String

If IsDate(DateIn) Then
Select Case UCase$(DataSource)
Case "JET"
SQLDate = Format$(DateIn, "\#yyyy\-mm\-dd\#")
Case "SQL"
SQLDate = Format$(DateIn, "\'yyyy\-mm\-dd\'")
Case "ODBC"
SQLDate = Format$(DateIn, "\{\d \'yyyy\-mm\-dd\'}")
End Select
End If

End Function

Another consideration is in terms of constructing dates from values you already know. Consider the case
where you are trying to create a date when you know the year, month and day. Since you don't know what
Short Date format your user will have, you typically want to avoid having Access coerce the date. The
CDate function (as well as the CVDate function) respects the user's locale settings. That means you
shouldn't rely on that function to convert your string to a date. Rather, you should use theDateSerial
function. On the other hand, if you're letting the user type a date into an unbound text box, using theCDate
function (or CVDate function) in your code will ensure that you interpret the user's input as they intended
(provided, of course, that the locale is set appropriately on their machine).
(While the Help file states that the "CVDate function is also provided for compatibility with previous versions of
Visual Basic", it does have an advantage when dealing with Date fields in queries. CDate fails on Null values, whereas
CVDate doesn't.)
The last area of discussion is recognizing user input as dates. As you may suspect, since you do not
necessarily know what your user's locale settings have for Short Date format, this is where most of the
problems occur.
When you're using a text box bound to a Date field, it's not that difficult, as you'll get an error if Access
can't interpret the input as a date. There is still the possibility of the user using the wrong date format when
keying, and a possible solution to that is to set the field's format to something unambiguous, and they can
see how what they keyed is being interpreted. Figure 1 shows an example of how to set the field:
Figure 1. Setting the field format
Figure 2 shows the user entering the date in their preferred format:

Figure 2. Entering a date into the form


Finally, Figure 3 shows the field after the date has been entered:

Figure 3. Date display after input


Now, the user has immediate confirmation that Access has correctly interpreted the date that they input.
Note that this approach will work equally well with unbound forms. (In fact, setting the format of the field is
required to ensure that Access will attempt to coerce the input into a date with unbound forms)
Of course, a much safer approach is to use a calendar control for input, so that there's no chance of
misinterpretation. However, in some instances, the use of the control can cause delays in data entry.
Unfortunately, the use of calendars on forms is a bigger topic than I can get into in this column. If you'd like
more information about using calendars, Microsoft Access MVP Stephen Lebans has an excellent example
of using a Class to wrap the Microsoft Month Calendar Common Control (thus avoiding distribution or
versioning issues that can occur if you use the ActiveX Month Calendar control) at
http://www.lebans.com/monthcalendar.htm. As well, Microsoft Access MVP Tony Toews has a list of other
alternatives to the Microsoft Calendar Control at http://www.granite.ab.ca/access/calendars.htm
Doug Steele has worked with databases, both mainframe and PC, for many years with a major Canadian oil company.
He has taught introductory computer programming at the University of Waterloo. Microsoft has recognized him as an
Access MVP for his contributions to the Microsoft-sponsored newsgroups over the years.

You might also like