Another common task in coding business applications is the manipulation of dates and times. To aid the coding of these tasks, the Framework provides the DateTime and TimeSpan classes. The DateTime class handles date and time values, whereas the TimeSpan class handles date and time differences. Date is a data type, and there’s no equivalent class in the Framework. All date variables are implemented by the DateTime class in the Framework. In effect, the Date data type is an alias for the DateTime data type, and both types are implemented by the System.DateTime class of the Framework.
The DateTime Class
The DateTime class is used for storing date and time values, and it’s one of the Framework’s base data types. Date and time values are stored internally as Double numbers. The integer part of the value corresponds to the date, and the fractional part corresponds to the time. To convert a DateTime variable to a Double value, use the method To0ADateTime, which returns a value that is an OLE (Object Linking and Embedding) Automation-compatible date. The value 0 corresponds to midnight of December 30, 1899. The earliest date you can represent as an OLE Automation-compatible date corresponds to the Double value is −657,434, and it’s the first day of the year 100.
To initialize a DateTime variable, supply a date value enclosed in a pair of pound symbols. If the value contains time information, separate it from the date part by using a space:
Dim date1 As Date = #4/15/2007# Dim date2 As Date = #4/15/2007 2:01:59#Code language: PHP (php)
If you have a string that represents a date, and you want to assign it to a DateTime variable for further processing, use the DateTime class’s Parse and ParseExact methods. The Parse method parses a string and returns a date value if the string can be interpreted as a date value. Let’s say your code prompts the user for a date and then it uses it in date calculations. The user-supplied date is read as a string, and you must convert it to a date value:
Dim sDate1 As String Dim dDate1 As DateTime sDate1 = InputBox("Please enter a date after 1/1/2002") Try dDate1 = DateTime.Parse(sDate1) ' use dDate1 in your calculations Catch exc As Exception MsgBox("You've entered an invalid date") End TryCode language: PHP (php)
The Parse method will convert a string that represents a date to a DateTime value, regardless of the format of the date. You can enter dates such as 1/17/2007, Jan. 17, 2007, or January 17, 2007 (with or without the comma). The ParseExact method allows you to specify more options, such as the possible formats of the date value.
Different Cultures, Different Dates
Different cultures use different date formats, and Windows supports them all. However, you must make sure that the proper format is selected in the Regional And Language Options. By default, dates are interpreted as specified by the current date format in the target computer’s regional settings. The Parse method allows you to specify the culture to be used in the conversion. The following statements prompt the user for a date value and then interpret it in a specific culture (I’m using the English date format for the example):
Dim sDate1 As String Dim dDate1 As DateTime sDate1 = InputBox("Please enter a date") Try Dim culture As CultureInfo = _ New CultureInfo("en-GB", True) dDate1 = DateTime.Parse(sDate1, culture) Debug.WriteLine(dDate1.ToLongDateString) Catch exc As Exception MsgBox("You've entered an invalid date") End Try
To use the CultureInfo class in your code, you must import the System.Gobalization namespace in your project. These statements will convert any English date regardless of the regional settings. If you enter the string 16/3/2007 in the input box, the preceding statements will produce the following output:
Friday, March 16, 2007
Let’s see how the same date will be parsed in two different cultures. Insert the following code segment in a button’s Click event handler:
Dim sDate1 As String Dim dDate1 As DateTime sDate1 = InputBox("Please enter a date") Try Dim culture As CultureInfo = _ New CultureInfo("en-GB", True) dDate1 = DateTime.Parse(sDate1, culture) Debug.WriteLine(dDate1.ToLongDateString) culture = New CultureInfo("en-US", True) dDate1 = DateTime.Parse(sDate1, culture) Debug.WriteLine(dDate1.ToLongDateString) Catch exc As Exception MsgBox("You've entered an invalid date") End Try
The method ToLongDateString returns the verbose description of the date, so that we can read the name of the month instead of guessing it. Run the code and enter a date that can be interpreted differently in the two cultures, such as 4/9/2007. The following output will be produced:
Tuesday, September 04, 2007 Monday, April 09, 2007
If the month part of the date exceeds 12, the exception handler will be activated. Dates are always a tricky issue in programming, and you should include the appropriate culture in the Parse method so that user-supplied dates will be converted correctly, even if the user’s culture hasn’t been set correctly in the regional settings.
The DateTime class exposes the following properties, which are straightforward.
The Date property returns the date from a date/time value and sets the time to midnight. The TimeOfDay property returns the time part of the date. The following statements
Dim date1 As DateTime date1 = Now() Debug.WriteLine(date1) Debug.WriteLine(date1.Date) Debug.WriteLine(date1.TimeOfDay)Code language: PHP (php)
will print something like the following values in the Output window:
8/5/2007 9:41:55 AM 8/5/2007 12:00:00 AM 09:41:55.5296000 DayOfWeek, DayOfYear
These two properties return the day of the week (a string such as Monday) and the number of the day in the year (an integer from 1 to 365, or 366 for leap years), respectively.
Hour, Minute, Second, Millisecond
These properties return the corresponding time part of the date value passed as an argument. If the current time is 9:47:24 p.m., the three properties of the DateTime class will return the integer values 9, 47, and 24 when applied to the current date and time:
Debug.WriteLine("The current time is " & Date.Now.ToString) Debug.WriteLine("The hour is " & Date.Now.Hour) Debug.WriteLine("The minute is " & Date.Now.Minute) Debug.WriteLine("The second is " & Date.Now.Second)Code language: CSS (css)
Day, Month, Year
These three properties return the day of the month, the month, and the year of a DateTime value, respectively. The Day and Month properties are numeric values, but you can convert them to the appropriate string (the name of the day or month) with the WeekDayName() and MonthName() functions. Both functions accept as an argument the number of the day (a value from 1 to 7) or month (from 1 to 13), and they return the name. Use the value 13 with a 13-month calendar (applies to non-U.S. and non-European calendars). They also accept a second optional argument that is a True/False value and indicates whether the function should return the abbreviated name (if True) or full name (if False). The WeekDayName() function accepts a third optional argument, which determines the first day of the week. Set this argument to one of the members of the FirstDayOfWeek enumeration. By default, the first day of the week is Sunday.
This property returns the number of ticks from a date/time value. Each tick is 100 nanoseconds (or 0.0001 milliseconds). To convert ticks to milliseconds, multiply them by 10,000 (or use the TimeSpan object’s TicksPerMillisecond property, discussed later in this chapter). We use this property to time operations precisely: The Ticks property is a long value, and you can read its value before and after the operation you want to time. The difference between the two values is the duration of the operation in tenths of nanoseconds. Divide it by 10,000 to get the duration in milliseconds.
The DateTime class exposes several methods for manipulating dates. The most practical methods add and subtract time intervals to and from an instance of the DateTime class.
Compare is a shared method that compares two date/time values and returns an integer value indicating the relative order of the two values. The syntax of the Compare method is the following, where date1 and date2 are the two values to be compared:
order = System.DateTime.Compare(date1, date2)
The method returns an integer, which is −1 if date1 is less than date2, 0 if they’re equal, and 1 if date1 is greater than date2. Of course, you can compare dates directly with a statement such as this one:
If date1 > date2 Then ...
When comparing dates, keep in mind that older dates are smaller than newer dates. The preceding comparison is true if date1 follows date2. You can also use the Subtract method to find out the difference between two dates in days, weeks, months, and years.
This shared method returns the number of days in a specific month. Because February contains a variable number of days depending on the year, the DaysInMonth method accepts as arguments both the month and the year:
monDays = DateTime.DaysInMonth(year, month)
This shared method creates a date/time value from an OLE Automation-compatible date.
newDate = DateTime.From0ADate(dtvalue)
The argument dtvalue must be a Double value in the range from −657,434 (first day of year 100) to 2,958,465 (last day of year 9999).
This shared method returns a True/False value that indicates whether the specified year is a leap year:
This method adds a TimeSpan object to the current instance of the DateTime class. The TimeSpan object represents a time interval, and there are many methods to create a TimeSpan object, which are all discussed in the section ‘‘The TimeSpan Class’’ later in this chapter. The following statements create a new TimeSpan object that represents 3 days, 6 hours, 2 minutes, and 50 seconds and add this TimeSpan object to the current date and time. Depending on when these statements are executed, the two date/time values will differ, but the difference between them will always be 3 days, 6 hours, 2 minutes, and 50 seconds:
Dim TS As New TimeSpan() Dim thisMoment As Date = Now() TS = New TimeSpan(3, 6, 2, 50) Debug.WriteLine(thisMoment) Debug.WriteLine(thisMoment.Add(TS))Code language: PHP (php)
The values printed in the Output window when I tested this code segment were as follows:
9/1/2007 10:10:49 AM 9/4/2007 4:13:39 PM
This method is the counterpart of the Add method; it subtracts a TimeSpan object from the current instance of the DateTime class and returns another Date value.
Adding Intervals to Dates
Various methods add specific intervals to a date/time value. Each method accepts the number of intervals to add (days, hours, milliseconds, and so on) to the current instance of the DateTime class. These methods are the following: AddYears, AddMonths, AddDays, AddHours, AddMinutes, AddSeconds, AddMilliseconds, and AddTicks. As stated earlier, a tick is 100 nanoseconds and is used for really fine timing of operations. None of the Add xxx methods act on the current instance of the DateTime class; instead, they return a new DateTime value with the appropriate value.
To add 3 years and 12 hours to the current date, use the following statements:
If the argument is a negative value, the corresponding intervals are subtracted from the current instance of the class.
This method converts a date/time value to a string, using a specific format. The DateTime class recognizes numerous format patterns, which are listed in the following two tables. Table 9.1 lists the standard format patterns, and Table 9.2 lists the characters that can format individual parts of the date/time value. You can combine the custom format characters to format dates and times in any way you wish.
The syntax of the ToString method is the following, where formatSpec is a format specification:
aDate.ToString(formatSpec)Code language: CSS (css)
The D named date format, for example, formats a date value as a long date; the following statement will return the highlighted string shown below the statement:
Debug.Writeline(#9/17/2010#.ToString("D")) Friday, September 17, 2010Code language: PHP (php)
Table 9.1 lists the named formats for the standard date and time patterns. The format characters are case-sensitive — for example, g and G represent slightly different patterns.
Table 9.1: The Date and Time Named Formats
|Named Format||Output||Format Name|
|D||dddd, MMMM dd, yyyy||LongDatePattern|
|F||dddd, MMMM dd, yyyy HH:mm:ss.mmm||FullDateTimePattern (long date and long time)|
|f||dddd, MMMM dd, yyyy HH:mm.ss||FullDateTimePattern (long date and short time)|
|g||MM/dd/yyyy HH:mm||general (short date and short time)|
|G||MM/dd/yyyy HH:mm:ss||General (short date and long time)|
|M, m||MMMM dd||MonthDayPattern (month and day)|
|r, R||ddd, dd MMM yyyy HH:mm:ss GMT||RFC1123Pattern|
|t||HH:mm||ShortTimePattern (short time)|
|T||HH:mm:ss||LongTimePattern (long time)|
|u||yyyy-MM-dd HH:mm:ss||UniversalSortableDateTimePattern (sortable GMT value)|
|U||dddd, MMMM dd, yyyy HH:mm:ss||UniversalSortableDateTimePattern (long date, long GMT time)|
|Y, y||MMMM, yyyy||YearMonthPattern (month and year)|
Table 9.2: Date Format Specifier
|d||The date of the month|
|dd||The day of the month with a leading zero for single-digit days|
|ddd||The abbreviated name of the day of the week (a member of the AbbreviatedDayNames enumeration)|
|dddd||The full name of the day of the week (a member of the DayNamesFormat enumeration)|
|M||The number of the month|
|MM||The number of the month with a leading zero for single-digit months|
|MMM||The abbreviated name of the month (a member of the AbbreviatedMonthNames enumeration)|
|MMMM||The full name of the month|
|y||The year without the century (the year 2001 will be printed as 1)|
|yy||The year without the century (the year 2001 will be displayed as 01)|
|yyyy||The complete year|
|gg||The period or era (this pattern is ignored if the date to be formatted does not have an associated period, such as A.D. or B.C.)|
|h||The hour in 12-hour format|
|hh||The hour in 12-hour format with a leading zero for single-digit hours|
|H||The hour in 24-hour format|
|HH||The hour in 24-hour format with a leading zero for single-digit hours|
|m||The minute of the hour|
|mm||The minute of the hour with a leading zero for single-digit minutes|
|s||The second of the hour|
|ss||The second of the hour with a leading zero for single-digit seconds|
|t||The first character in the a.m./p.m. designator|
|tt||The a.m./p.m. designator|
|z||The time-zone offset (applies to hours only)|
|zz||The time-zone offset with a leading zero for single-digit hours (applies to hours only)|
|zzz||The full time-zone offset (hour and minutes) with leading zeros for single-digit hours and minutes|
The following examples format the current date by using all the format patterns listed in Table 13.1. An example of the output produced by each statement is shown under each statement, indented and highlighted.
Table 9.2 lists the format characters that can be combined to build custom format date and time values. The patterns are case-sensitive. If the custom pattern contains spaces or characters enclosed in single quotation marks, these characters will appear in the formatted string.
The following examples format the current time by using a few of the format patterns listed in Table 13.2. The output produced by each statement is shown under each statement, indented and highlighted.
To display the full month name and the day in the month, for instance, use the following statement:
Debug.WriteLine(now().ToString("MMMM d")) July 27Code language: CSS (css)
You may have noticed some overlap between the named formats and the format characters. The character d signifies the short date pattern when used as a named format, and the number of the day when used as format character. The compiler figures out how it’s used based on the context. If the format argument is d/mm, it will display the day and month number, whereas the format argument d, mmm will display the number of the day followed by the month’s name. If you use the character d on its own, however, it will be interpreted as the named format for the short date format.
Date Conversion Methods
The DateTime class supports methods for converting a date/time value to many of the other base types, which are presented here briefly.
The ToFileTime method converts the value of the current Date instance to the format of the local system file time. There’s also an equivalent FromFileTime method, which converts a file time value to a Date value.
These two methods convert the date part of the current DateTime instance to a string with the long (or short) date format. The following statement will return a value like the one highlighted, which is the long date format:
Debug.WriteLine(Now().ToLongDateString) Tuesday, July 15, 2008Code language: CSS (css)
These two methods convert the time part of the current instance of the Date class to a string with the long (or short) time format. The following statement will return a value like the one highlighted:
Debug.WriteLine(Now().ToLongTimeString) 6:40:53 PMCode language: CSS (css)
This method converts the DateTime instance into an OLE Automation-compatible date (a long value).
ToUniversalTime converts the current instance of the DateTime class into universal coordinated time (UCT). If you convert the local time of a system in New York to UCT, the value returned by this method will be a date/time value that’s five hours ahead. The date may be the same or the date of the following day. If the statement is executed after 7 p.m. local time, the date will be that of the following day. The method ToLocalTime converts a UCT time value to local time.
Dates as Numeric Values
The Date type encapsulates complicated operations, and it’s worth taking a look at the inner workings of the classes that handle dates and times. Let’s declare two variables to experiment a little with dates: a Date variable, which is initialized to the current date, and a Double variable.
Dim Date1 As Date = Now() Dim dbl As DoubleCode language: PHP (php)
Insert a couple of statements to convert the date to a Double value and print it:
dbl = Date1.ToOADate Debug.WriteLine(dbl)
On the date I tested this code, June 1, 2007, the value was 39234.6418796643. The integer part of this value is the date, and the fractional part is the time. If you add one day to the current date and then convert it to a double again, you’ll get a different value:
dbl = (Now().AddDays(1)).ToOADate Debug.WriteLine(dbl)
This time, the value 39235.6426065857 was printed; its integer part is tomorrow’s value. You can add two days to the current date by adding (48 × 60) minutes. The original integer part of the numeric value will be increased by two:
dbl = Now().AddMinutes(48 * 60).ToOADate Debug.WriteLine(dbl)
The value printed this time will be 39236.6435319329.
Let’s see how the date-manipulation methods deal with leap years. We’ll add 10 years to the current date via the AddYears method, and we’ll print the new value with a single statement:
Debug.WriteLine(Now().AddYears(10).ToLongDateString)Code language: CSS (css)
The value that will appear in the Immediate window will be Thursday, June 01, 2017. The Double value of this date is 42887.6470126852. If you add 3,650 days, you’ll get a different value because the 10-year span contains at least two leap years:
Debug.WriteLine(Now().AddDays(3650).ToLongDateString) Debug.WriteLine(Now().AddDays(3650).ToOADate)Code language: CSS (css)
The new value that will be printed in the Immediate window will be Monday, May 29, 2004, and the corresponding Double value will be 42884.6450151968.
Can you figure out what time it was when I executed the preceding statements? If you multiply the fractional part (0.6426065857) by 24, you’ll get 15.4225580568, which is 15:00 hours and some minutes. If you multiply the fractional part of this number by 60, you’ll get 25.353483408, which is 25 minutes and some seconds. Finally, you can multiply the new fractional part by 60 to get the number of seconds: 21.20900448. So, it was 3:25:21 p.m. And the last fractional part corresponds to 209 milliseconds.