.NET / Making Dates
As with any other .NET data structure, you have to create an instance
of the DateTime value type before you can use it. DateTime has seven
different constructors, although three of them are just duplicates of
some others with an extra parameter (a Calendar parameter used for
globalization). So really there are only four constructors. Those
constructors allow you to initialize a DateTime structure:
=B7 To a 64-bit integer value representing a number of ticks
=B7 To a specified year, month, and day
=B7 To a specified year, month, day, hour, minute, and second
=B7 To a specified year, month, day, hour, minute, second, and
millisecond
For example, this code initializes a DateTime to October 27, 1961 at
8:47 am:
C#
DateTime MyDate =3D
new DateTime(1961, 10, 27, 08, 47, 00);
VisualBasic
Dim MyDate as DateTime =3D
new DateTime(1961, 10, 27, 08, 47, 00)
.NET
Parsing Dates
DateTime has two static methods that will parse a string to create a
DateTime value. DateTime.Parse attempts to parse a valid date and time
out of the string that's passed to it. The string must contain the
representation of a date and time in one of the formats described in
the DateTimeFormatInfo object that is initialized for the current
culture.
DateTimeFormatInfo contains information about different date formats
like month/year, short and long date/time patterns, weekday and month
name abbreviations, and other things that describe the myriad ways that
dates and times can be formatted.
Parse tries very hard to make sense of the string that's passed to it
in order to create a valid DateTime value. It ignores leading and
trailing white space, and unrecognized characters if possible, and it
fills in missing information with the corresponding current date and
time values. Parse will throw a FormatException, though, if it's unable
to decipher the string you send to it.
Overloaded versions of DateTime.Parse let you specify an object that
implements the IFormatProvider provider to describe the expected date
format.
The other static method that parses strings to make DateTime values is
called ParseExact. For this method to succeed, the string that you pass
to it must exactly match the format that you specify in the
IFormatProvider parameter.
The program below illustrates how to use the Parse and ParseExact
methods to read dates and times.
C#
public static void Main()
{
DateTime MyDate =3D new DateTime(1961, 10, 27, 08, 47, 00);
Console.WriteLine(MyDate.ToString());
DateTime NewDate;
NewDate =3D DateTime.Parse("10/27/61 08:47");
Console.WriteLine(NewDate.ToString());
NewDate =3D DateTime.Parse("10/1961");
Console.WriteLine(NewDate.ToString());
NewDate =3D DateTime.Parse("27 October 1961 8:47 pm");
Console.WriteLine(NewDate.ToString());
IFormatProvider format =3D
new System.Globalization.CultureInfo("fr-FR", true);
string[] expectedFormats =3D {"g", "G", "f", "F"};
// This is DD/MM/YYYY format
NewDate =3D DateTime.ParseExact(
"27/10/1961 08:47:00",
expectedFormats,
format,
System.Globalization.DateTimeStyles.AllowWhiteSpaces);
Console.WriteLine("Parsed DD/MM/YY: {0}", NewDate.ToString());
try
{
NewDate =3D DateTime.ParseExact(
"10/27/1961",
expectedFormats,
format,
System.Globalization.DateTimeStyles.AllowWhiteSpaces);
Console.WriteLine(NewDate.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
VisualBasic
Public Shared Sub Main
Dim MyDate as DateTime =3D new DateTime(1961, 10, 27, 08, 47, 00)
Console.WriteLine(MyDate.ToString())
Dim NewDate as DateTime
NewDate =3D DateTime.Parse("10/27/61 08:47")
Console.WriteLine(NewDate.ToString())
NewDate =3D DateTime.Parse("10/1961")
Console.WriteLine(NewDate.ToString())
NewDate =3D DateTime.Parse("27 October 1961 8:47 pm")
Console.WriteLine(NewDate.ToString())
Dim format as IFormatProvider =3D _
new System.Globalization.CultureInfo("fr-FR", true)
Dim expectedFormats as String() =3D {"g", "G", "f", "F"}
' This is DD/MM/YYYY format
NewDate =3D DateTime.ParseExact( _
"27/10/1961 08:47:00", _
expectedFormats, _
format, _
System.Globalization.DateTimeStyles.AllowWhiteSpaces)
Console.WriteLine("Parsed DD/MM/YY: {0}", NewDate.ToString())
Try
NewDate =3D DateTime.ParseExact( _
"10/27/1961", _
expectedFormats, _
format, _
System.Globalization.DateTimeStyles.AllowWhiteSpaces)
Console.WriteLine(NewDate.ToString())
Catch e as Exception
Console.WriteLine(e.Message)
End Try
End Sub
The only real tricky part here is the string array passed as the second
parameter to ParseExact. This array specifies the formats that the
method should try to match when parsing the string. In the code above,
I used the general formats (short date with short or long time), and
full formats (long date with short or long time). If the string to be
parsed doesn't match one of those formats, then ParseExact throws a
FormatException exception. See the official documentation for the
DateTimeFormatInfo class for a complete list of format characters and
patterns.
.NET
Date Calculations
Last updated Jun 16, 2005.
The DateTime value type has methods and properties that let you mangle
dates in many fun and interesting ways. Properties such as Date,
DayOfWeek, Hour, and Ticks let you get information about specific
attributes of the DateTime value. All of the properties, by the way,
are read only. There is no way to set the Month property on a DateTime
value.
There are methods that let you add years, months, days, hours, minutes,
seconds, and milliseconds to dates; and methods that will convert
DateTime values to other date formats like a Windows FileTime or an OLE
Automation date. See the official documentation for full information on
those methods.
DateTime also provides overloads for the comparison operators so you
can write things like:
if (yourBirthDate < myBirthDate)
Console.WriteLine("You're older than I am");
If you're writing in Visual Basic, of course, you don't have access to
the overloaded operators so you'd need to use the Compare or CompareTo
method, like this:
If yourBirthDate.CompareTo(myBirthDate) < 0 Then
Console.WriteLine("You're older than I am")
End If
The overloaded subtraction operator lets you subtract one date from
another to obtain the difference in time between the two dates. The
returned value is expressed in a TimeSpan: a number of ticks (100
nanosecond time periods).
TimeSpan is really just a number that knows how to express itself in
terms of days, hours, minutes, seconds, and milliseconds. TimeSpan
properties provide you with a way to get the value expressed in these
terms (whole days, minutes, and so on), and methods let you initialize
a TimeSpan structure from these values. The overloaded TimeSpan
constructor lets you initialize a structure with a given number of
days, hours, minutes, seconds, and milliseconds.
The largest time unit that TimeSpan "knows" about is the day. It's
impossible to convert a TimeSpan value to months, for example, because
months have differing numbers of days. The same is true for years. So,
if you call TimeSpan.ToString to output a value, it will be expressed
in days, hours, minutes, seconds, and milliseconds.
TimeSpan has two types of properties: those that return whole values,
and those that return fractional values. The Days property, for
example, gets the number of whole days represented by a TimeSpan value.
By contrast, the TotalDays property gets the value expressed as whole
and fractional days. So if you have a TimeSpan that represents 25
hours, the value of the Days property would be 1, and the value of the
TotalDays property would be 1.04167 (that is, 1 and 1/24 days). There
are similar properties for hours, minutes, seconds, and milliseconds.
Of course, since TimeSpan is "just a number," you can use the standard
comparison operators to see which of two values is larger or smaller,
and you can use the standard operators to add and subtract TimeSpan
values. TimeSpan, though, is not terribly useful all by itself. It's
really intended to be used in conjunction with DateTime values.
The difference between two dates, as pointed out above, is expressed in
a TimeSpan. This code subtracts one date from another to get the time
elapsed between them.
C#
DateTime BirthDate =3D new DateTime(1961, 10, 27, 08, 47, 00);
DateTime Today =3D DateTime.Now;
TimeSpan Age =3D Today - BirthDate;
VisualBasic
Dim BirthDate as DateTime =3D new DateTime(1961, 10, 27, 08, 47, 00)
Dim Today as DateTime =3D DateTime.Now
Dim Age as TimeSpan =3D Today.Subtract(BirthDate)
You should note that in the second line of code I got the current date
and time by accessing the static DateTime.Now property.
If you initialize the BirthDate variable in the code above with your
own birth date, then the Age variable will represent your current age.
If you then want to see what the date will be when you're twice as old
as you are right now, you simply add the calculated Age value to Today,
like this:
C#
DateTime ALongTimeFromNow =3D Today + Age;
Console.WriteLine(ALongTimeFromNow.ToString());
VisualBasic
Dim ALongTimeFromNow as DateTime =3D Today.Add(Age)
Console.WriteLine(ALongTimeFromNow.ToString())
.NET
Official Documentation
Last updated Jun 16, 2005.
The DateTime and TimeSpan topics in the MSDN .NET Reference fully
describe the methods and properties of these objects, and give some
very good examples of using them in typical situations.
If you need to work with other calendars or multiple cultures, be sure
to check the references for Calendar, DateTimeStyles, and
DateTimeFormatInfo in the System.Globalization namespace.
http://www.imc.org/rfc2822
.NET
Properties
Last updated Jul 27, 2005.
I had originally planned to duplicate all of the DateTime properties
and methods in W3CDateTime. As I got into it, though, I started
thinking that I was needlessly duplicating a lot of effort. This is
something of a judgement call, I'll admit. However, it seemed silly to
implement the Hour property when I could just as easily call get the
Hour property on W3CDateTime.DateTime. That is, these two calls would
be identical:
hour =3D myDate.Hour;
hour =3D myDate.DateTime.Hour;
In most cases, I avoided duplicating effort. The result is that I only
implemented a handful of properties for W3CDateTime, all of them
static. The properties that I implemented are:
LocalUtcOffset returns the offset between the local time (on the
computer that's running the program) and UTC time.
MaxValue returns a W3CDateTime that represents the maximum value that
can be represented. This value is expressed in UTC time.
MinValue returns a W3CDateTime that represents the minimum value that
can be represented. This value is expressed in UTC time.
Now returns the current local time, expressed in the local time zone.
Today returns the current date, expressed in the local time zone. The
time portion is set to 00:00:00.
UtcNow returns the current time, expressed in UTC time.
All of these are static properties. With the exception LocalUtcOffset,
all of these properties are duplicates of properties implemented by
System.DateTime. The duplication seemed reasonable in these cases.
New Methods
I needed the ability to do comparisons on W3CDateTime values, and also
to add days, months, years, etc. I also needed to subtract two dates to
determine the number of days or hours between them. System.DateTime
implements all of this functionality, of course, but it becomes
difficult to use. For example, if I wanted to add days to a W3CDateTime
to get another value, I would have to write:
myDateTime =3D new W3CDateTime(myDateTime.DateTime.AddDays(5),
myDateTime.UtcOffset);
By creating an AddDays method, I'm now able to write:
myDateTime =3D myDateTime.AddDays(5);
Subtracting two dates was a little trickier in that I had to be sure to
use the UtcTime property. Otherwise, subtracting dates from two
different time zones would produce erroneous results.
For those reasons, I implemented the AddYears, AddHours, and similar
methods, as well as both overloads of the Subtract method that are
supported by System.DateTime.
For comparisons, I implemented a static Compare method as well as the
IComparable.CompareTo method. For equality testing, I implemented
Equals and GetHashCode as outlined in the SDK article Implementing the
Equals Method.
Finally, I implemented two conversion methods: ToLocalTime and
ToUniversalTime. These are similar to the methods implemented by
System.DateTime, except that I added an overload that will convert the
value to any given timezone offset.