Got the Time?

Get Time, Date, and Duration Info with DateTime and TimeSpan

ClassAct

LANGUAGES: VB

TECHNOLOGIES: TimeSpan Type | Manipulating TimeSpan Values

 

Got the Time?

Get Time, Date, and Duration Info with DateTime and TimeSpan

 

By Ken Getz

 

If you're a VB or VBScript developer and have ever attempted to measure elapsed time using VB's Date type, you're going to love the richness of the DateTime and TimeSpan types. You're sure to find most of the functionality you need built right into them. Let's spend some time (no pun intended) exploring the DateTime (for working with a specific moment in time) and TimeSpan (for working with an elapsed time) types.

 

DateTime Homework

In June's installment of this column, I suggested you take some time to create functions that took advantage of the DateTime type. Specifically, I suggested the following four functions:

  • FirstDayInMonth - Given a date, return a date representing the day in the month.
  • LastDayInMonth - Given a date, return a date representing the last day in the month.
  • NextAnniversary - Given a date, return the next anniversary of that date. For example, given someone's birth date, calculate the next occurrence of that date.
  • Age - Given a person's birth date, calculate that person's current age.

 

These programming tasks are relatively easy with the DateTime type, and each has many possible solutions. I've placed shared procedures for the above functions in the DateTimeInfo class in the sample project, and you can test them out using the sample page UsingDateTime.aspx, shown in FIGURE 1 (see end of article for download details). FIGURE 2 shows the code for the entire DateTimeInfo class.

 


FIGURE 1: Use the built-in Date and Time methods to create sophisticated solutions to specific problems.

 

Shared Function FirstDayInMonth( _

 ByVal dtmDate As DateTime) As DateTime

  Return New DateTime(dtmDate.Year, dtmDate.Month, 1)

End Function

 

Shared Function LastDayInMonth( _

 ByVal dtm As DateTime) As DateTime

  Dim dt As New DateTime(dtm.Year, dtm.Month, 1)

  Return dt.AddDays( _

   DateTime.DaysInMonth(dt.Year, dt.Month) - 1)

End Function

 

Shared Function NextAnniversary( _

 ByVal dtm As DateTime) As DateTime

  ' Get the anniversary in the current year.

  Dim dtmCurrent As _

   New DateTime(Today.Year, dtm.Month, dtm.Day)

 

  ' If the anniversary has already passed,

  ' add one year.

  If dtmCurrent < Today Then

    dtmCurrent = dtmCurrent.AddYears(1)

  End If

  Return dtmCurrent

End Function

 

Shared Function Age(ByVal dtm As DateTime) As Integer

  ' Given the DateTime value representing

  ' the birthdate, return the current age.

  Dim intAge As Integer = Today.Year - dtm.Year

  If New DateTime(Today.Year, _

   dtm.Month, dtm.Day) > Today Then

    intAge -= 1

  End If

  Return intAge

End Function

FIGURE 2: The DateTime type makes performing many calculations involving dates and times easy.

 

The FirstDayInMonth solution is simple. The code returns a new DateTime value, which sets the parameters to the year of the supplied date; the month of the supplied date; and 1, which represents the first day of the month:

 

Return New DateTime(dtmDate.Year, dtmDate.Month, 1)

 

The LastDayInMonth solution requires a bit more effort. This time, the code creates a new DateTime value, using the same code as in the previous procedure. The code adds on the number of days returned by the DaysInMonth method, minus one:

 

Dim dt As New DateTime(dtm.Year, dtm.Month, 1)

Return dt.AddDays( _

 DateTime.DaysInMonth(dt.Year, dt.Month) - 1)

 

The NextAnniversary procedure starts by creating a DateTime value corresponding to the date of the anniversary in the current year:

 

Dim dtmCurrent As _

 New DateTime(Today.Year, dtm.Month, dtm.Day)

 

If the anniversary has passed (that is, if the value of the anniversary date is less than that of the current date), the code adds one year and then returns the result:

 

If dtmCurrent < Today Then

  dtmCurrent = dtmCurrent.AddYears(1)

End If

Return dtmCurrent

 

The Age method starts by subtracting the Year property of the current date and the birth date:

 

Dim intAge As Integer = Today.Year - dtm.Year

 

If the birth date hasn't passed already in the current year, however, the intAge value is off by one. Therefore, if the value of the birth date within the current year is greater than the value of the current date, the code subtracts one from the age:

 

If New DateTime(Today.Year, _

 dtm.Month, dtm.Day) > Today Then

  intAge -= 1

End If

 

You'll find the DateTime type and its members very convenient when you need to manipulate dates and times as part of your own applications. You can extend and expand these procedures easily to meet your own needs.

 

Handle Elapsed Times with the TimeSpan Type

The DateTime type handles only moments in time. That is, a DateTime variable can represent only a single instant. If you want to work with elapsed times, you'll use the TimeSpan type and its members. You should be aware of some of the details of the TimeSpan type:

  • Like the DateTime type, the TimeSpan type is a value type, not a reference type. This means you needn't use the New keyword with TimeSpan variables unless you care to take advantage of one of the constructors supplied by the TimeSpan structure.
  • A TimeSpan variable represents a number of ticks (100 nanosecond increments), and 1 tick is the smallest time increment a TimeSpan variable can represent.
  • You can represent a TimeSpan value formatted as [-]d.hh:mm:ss.ff, where d represents the number of days; hh:mm:ss represents the hours, minutes, and seconds; and f represents fractions of a second.
  • Because months and years vary in size, the largest unit of time TimeSpan variables represent is the day. Long periods of time will be represented by large numbers of days.

 

The sample pages, TimeSpanProperties.aspx, TimeSpanFields.aspx, and TimeSpanMethods.aspx, allow you to try out most of the members of the TimeSpan type. On TimeSpanProperties.aspx, you can test out the members using the supplied starting and ending times, or you can enter your own. FIGURE 3 shows the TimeSpanProperties.aspx page in use.

 


FIGURE 3: Enter a range of times or a string containing a time span to parse. Click Calculate to see the properties of the corresponding TimeSpan value.

 

Create TimeSpan Values

You can create a TimeSpan value in a number of different ways. For example, when you call the Subtract method of the DateTime structure, the return value is a TimeSpan value. The sample page, TimeSpanProperties.aspx, uses this code as it loads to create a TimeSpan value:

 

Dim ts As TimeSpan

Dim dtStart As DateTime

Dim dtEnd As DateTime

dtStart = DateTime.Parse(txtStart.Text)

dtEnd = DateTime.Parse(txtEnd.Text)

 

ts = dtEnd.Subtract(dtStart).Duration

 

The Duration method of the TimeSpan structure returns the absolute value of the TimeSpan ticks. In the previous example, if you enter the starting time and ending time out of order, you may still want to treat the time span as a positive value. The example uses the Duration method to return the length of time between the start and end times, disregarding the actual order of the values.

 

In addition, the TimeSpan structure provides a group of constructors. You can supply any of the following:

  • A long value, indicating a number of ticks.
  • Three integer values, representing the number of elapsed hours, minutes, and seconds.
  • Four integer values, representing the number of elapsed days, hours, minutes, and seconds.
  • Five integer values, representing the number of elapsed days, hours, minutes, seconds, and milliseconds.

 

For example, the following code uses four integers to represent five days, two hours, thirty-one minutes, and one second:

 

Dim ts As New TimeSpan(5, 2, 31, 1)

 

You also can call the shared Parse method. It attempts to convert a string containing a time interval in the format [-]d.hh:mm:ss.ff into a TimeSpan value. This is how the sample page does its job:

 

Dim ts As TimeSpan

ts = TimeSpan.Parse(txtParse.Text)

 

The TimeSpan class also provides a series of methods (see the TimeSpanMethods.aspx page, shown in FIGURE 4), which you can use to fill a TimeSpan value. In the sample page, you'll find arbitrary values that show how different values work, but each of the From... methods accepts a numeric value and fills a TimeSpan value accordingly. For example, to fill a TimeSpan value with exactly 14.75 days, you could write this code:

 

Dim ts As TimeSpan

ts = TimeSpan.FromDays(14.75)

 


FIGURE 4: The From... methods of a TimeSpan value are simple, but they allow you to create a TimeSpan value given a number of days, hours, minutes, and so on.

 

Get Specific with TimeSpan Members

The TimeSpan instance members are all relatively self-explanatory. These members, shown in FIGURE 3, retrieve specific information from the TimeSpan value calculated when you click Calculate. Each of the values shown in FIGURE 3 represents the TimeSpan value calculated on the form.

 

By the way, the Total... properties (TotalDays, TotalMinutes, and so on) really represent the TimeSpan value, measured only in the specified interval. TotalMinutes, for example, represents the number of minutes (and fractional minutes) the TimeSpan value represents. The same goes for TotalDays (the total number of days and fractional days). The only one of these properties guaranteed always to be a whole number is Ticks because ticks are the base unit of time measurement for this type.

 

The TimeSpan structure also provides a number of read-only fields (properties stored as values). These fields include:

  • MaxValue and MinValue, the largest positive and negative values that can be stored in the TimeSpan structure.
  • TicksPerDay, TicksPerHour, TicksPerMinute, TicksPerSecond, and TicksPerMillisecond allow you to convert from ticks to any other type of value without having to calculate these ratios yourself.
  • Zero provides a 0 value as a TimeSpan type, so you can compare your own TimeSpan value to 0 without having to perform a conversion. For example:

 

If ts = TimeSpan.Zero Then

  ' You know your TimeSpan value

  ' contains no ticks.

End If

 

You also may want to investigate the DateTimeFormatInfo class, part of the System.Globalization namespace. This class allows you to set and retrieve formatting information pertinent to date and time values, including such things as the date and time separator values (/ and : in the United States), day names, the first day of the week, and more. If you're interested in writing applications that take time and date values into account and that will work correctly in more than one locale, you'll need to spend some time working through the DateTimeFormatInfo class.

 

This column was adapted from courseware originally written by the author for Application Developer's Training Company (http://www.appdev.com).

 

The files referenced in this article are available for download.

 

Ken Getz is a senior consultant with MCW Technologies and splits his time between programming, writing, and training. He specializes in tools and applications written in Visual Studio .NET and Visual Basic .NET. Ken is co-author of several books, including ASP.NET Developer's Jumpstart with Paul D. Sheriff, Access Cookbook with Andy Baron and Paul Litwin, Access 2002 Developer's Handbook with Paul Litwin and Mike Gunderloy, and VBA Developer's Handbook 2nd Ed. with Mike Gilbert. Ken co-wrote the training materials for AppDev's VB .NET, ASP.NET, Access 97 and 2000, Visual Basic 5.0, and Visual Basic 6.0 classes. He frequently speaks at technical conferences, including Microsoft's TechEd and Informant Communications Group's conferences on Office and ASP.NET. Readers may contact Ken at mailto:[email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish