Reputation: 7684
I am dealing with a database in which all dates were incorrectly stored using the web servers local date/time (in this case, Eastern time.) Assuming that all date/times persisted in the database are Eastern, how can I convert this date to the users local time once I've selected the data into my C# models?
Upvotes: 0
Views: 1406
Reputation: 13059
You might use TimeZoneInfo
classes for a such a operation (from client side)
Converts a time from one time zone to another.
String dbTime = "2015.02.21 1:00 AM"; // <= A sample time
DateTime time = DateTime.Parse(dbTime); // <= Convert it to a datetime
TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); // <= TimeZoneInfo for Eastern
TimeZoneInfo local = TimeZoneInfo.Local; // <=TimeZoneInfor for local
Console.WriteLine(TimeZoneInfo.ConvertTime(time, estern, local)); // Will return the Local time related to provided to Eastern Time
Additional : As Matt Johnson explains , yes local
will be server's time zone. So to use this approach as he Matt Johnson explained you need to identify the users timezone from a setting previously set, or from their IP
(if possible) OR via a field passed to server (may be Through URL)
Upvotes: 1
Reputation: 241573
You can either store UTC-based datetimes in the database, or you can store a datetimeoffset
with the correct offset. See DateTime vs DateTimeOffset to decide which makes sense for your use case. (I'll assume a UTC datetime for the rest of this response)
The problem is, since you've been only storing a datetime
, and it's based on US Eastern Time, you already have a potential loss of information. Let me explain:
Now perhaps you will be lucky and find there are no transactions recorded in that small window, but perhaps not. There is one way that you might be able to disambiguate though.
Many databases have an integer primary key that is auto-incrementing, or have some other incremental field. You can use this for disambiguation.
For example:
ID | ... | TransactionDate
----+-----+--------------------
101 | ... | 2014-11-02 00:55:00
102 | ... | 2014-11-02 01:00:00
103 | ... | 2014-11-02 01:30:00
104 | ... | 2014-11-02 01:55:00
105 | ... | 2014-11-02 01:15:00 <--- transition!
106 | ... | 2014-11-02 01:59:00
107 | ... | 2014-11-02 02:00:00
In the above table, because we have some records in the 1:00 hour that are out of sequence, it's a reasonable assumption that records 101-104 occurred during Eastern Daylight Time (UTC-4), and records 105-107 occurred during Eastern Standard Time (UTC-5).
This method is not something you can easily automate though. Sometimes you will have transactions in the ambiguous hour, but not any out of sequence. That means that either all of them came before the transition, or all of them came after. There's no way to tell.
You'll need to write some C# code or SQL scripts to query the table and transform the data. I recommend either creating a second table for the output, or a second column within the existing table. Don't try to update the values in place, or you will have a hard time unwinding it if things go wrong.
With regard to the conversion itself, if you are doing it in .NET code, you can use the TimeZoneInfo
class, with the "Eastern Standard Time"
time zone id. Don't get confused with the naming, that identifier represents both EST and EDT - despite the word "standard" in it's name.
DateTime dt = (DateTime) yourSqlDataReader["TransactionDate"];
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
if (tz.IsAmbiguousTime(dt))
{
// record this item in some way, so you can review it manually later
}
else
{
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
// save this field to a new table or a new column in the current table
}
After you do the conversions, go though and manual fill in any gaps from the ambiguous periods. When you're satisfied, then copy the values back into place, or move your code to point at the new UTC column, etc.
From this point forward, always store transaction times in terms of UTC. In .NET, use DateTime.UtcNow
, or in SQL, use GETUTCDATE()
or SYSUTCDATETIME()
.
Now the last part of the problem is - how are you going to convert to the user's time zone for display? Well you can certainly use TimeZoneInfo
again, or you can use a more comprehensive library, such as Noda Time. But whichever path you take, you'll probably need to know what the user's time zone is! The simplest thing to do is to gather this from the user of your application, via a dropdown setting in a user profile page (for example).
Another approach, if you are good with JavaScript, you can pass the UTC time all the way down to the client, and then load it into a JavaScript Date
object, or you can use a JavaScript library like moment.js. The benefit of either of these is that the client will automatically be able to convert the value to whatever time zone the user's computer is set to. This works particularly well if you are using a modern application development style, such as sending data via WebAPI and displaying it with a JavaScript framework like Angular.
Upvotes: 3