There are two things which surprise folks that are not familiar with this type. One is that when you create an instance, the signature and/or values that you initialize it with determine whether the input is interpreted as UTC or local. So new Date() creates a Date with the current time (which means that the local time should match what's on your watch), new Date(number) creates a date with the given number of milliseconds offset from 1/1/1970 UTC, new Date(text) parses the text form of the date (which may specify its own time zone), and new Date(year, month, etc) creates a date with the specified values on the current time zone.
Because initializing a UTC date with milliseconds is not very developer-friendly, I usually use the UTC method as a helper, for example new Date(Date.UTC(1999, 1, 25)).
The other part that may confuse developers is the fact that the toString method always writes out the local version of the date, regardless of how it was initialized. So if you want to handle UTC dates and not worry about differences in your users' time zones, you should initialize them with the Date(number) constructor, and display them with the toUTCString method.
Here is a nice table of some of the values you'd get - I generated this on my local machine, at -8 from UTC (Pacific Standard Time).
|new Date()||Wed Jun 4 16:25:29 PDT 2008||Wed, 4 Jun 2008 23:25:29 UTC|
|new Date(0)||Wed Dec 31 16:00:00 PST 1969||Thu, 1 Jan 1970 00:00:00 UTC|
|new Date(-1)||Wed Dec 31 15:59:59 PST 1969||Wed, 31 Dec 1969 23:59:59 UTC|
|new Date(836438400000)||Wed Jul 3 17:00:00 PDT 1996||Thu, 4 Jul 1996 00:00:00 UTC|
|new Date(Date.UTC(2008, 5, 6))||Thu Jun 5 17:00:00 PDT 2008||Fri, 6 Jun 2008 00:00:00 UTC|
More on Date and how it interacts with ADO.NET Data Services on the next installment...