views:

1851

answers:

6

Isn't there a (simple) way to tell Linq To SQL classes that a particular DateTime property should be considered as UTC (i.e. having the Kind property of the DateTime type to be Utc by default), or is there a 'clean' workaround?

The time zone on my app-server is not the same as the SQL 2005 Server (cannot change any), and none is UTC. When I persist a property of type DateTime to the dB I use the UTC value (so the value in the db column is UTC), but when I read the values back (using Linq To SQL) I get the .Kind property of the DateTime value to be 'Unspecified'.

The problem is that when I 'convert' it to UTC it is 4 hours off. This also means that when it is serialized it it ends up on the client side with a 4 hour wrong offset (since it is serialized using the UTC).

+3  A: 

The only way I can think to do this would be to add a shim property in a partial class that does the translation...

Marc Gravell
A: 

Ended up with a solution partially based on Marc's suggestion. For details, see link

ericsson007
You shouldn't change the generated code because your changes will be overwritten when the code is regenerated.
Mark Byers
A: 

This code snippet will allow you to convert the DateTimes (Kind=Unspecified) you get back from LINQ to SQL into UTC times without the times being affected.

TimeZoneInfo UTCTimeZone = TimeZoneInfo.FindSystemTimeZoneById("UTC");
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(myLinq2SQLTime, UTCTimeZone);

There are probably cleaner ways to do this but I had this to hand and could test it quickly!

I am not sure if there is a way to get it working with LINQ to SQL classes transparently - you might want to look in the partial class and see if you can hook where the values are read/written.

Schneider
A: 

I you want UTC, TimeZone class can do it for you, if you want to convert between different timezones, than TimeZoneInfo is for you. exemple from my code with TimeZoneInfo:

TimeZoneInfo cet = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
ac.add_datetime = TimeZoneInfo.ConvertTime(DateTime.Now, cet);
Michal Rogozinski
+5  A: 

SQL Server DateTime does not include any timezone or DateTimeKind information, therefore DateTime values retrieved from the database correctly have Kind = DateTimeKind.Unspecified.

If you want to make these times UTC, you should 'convert' them as follows:

DateTime utcDateTime = new DateTime(databaseDateTime.Ticks, DateTimeKind.Utc);

or the equivalent:

DateTime utcDateTime = DateTime.SpecifyKind(databaseDateTime.Ticks, DateTimeKind.Utc);

I assume your problem is that you are attempting to convert them as follows:

DateTime utcDateTime = databaseDateTime.ToUniversalTime();

This may appear reasonable at first glance, but according to the MSDN documentation for DateTime.ToUniversalTime, when converting a DateTime whose Kind is Unspecified:

The current DateTime object is assumed to be a local time, and the conversion is performed as if Kind were Local.

This behavior is necessary for backwards compatibility with .NET 1.x, which didn't have a DateTime.Kind property.

Joe
This is a nice workaround, though the answer about `partial void OnLoaded` allows a nicer fix
vdboor
+2  A: 

The generated LinqToSql code provides extensibility points, so you can set values when the objects are loaded.

The key is to create a partial class which extends the generated class, and then implement the OnLoaded partial method.

For instance, let's say your class is Person, so you have a generated partial Person class in Blah.designer.cs.

Extend the partial class by creating a new class (must be in a different file), as follows:

public partial class Person {

  partial void OnLoaded() {
    this._BirthDate = DateTime.SpecifyKind(this._BirthDate, DateTimeKind.Utc);
  }
}
rob263
Awesome! this allowed me to make a clean fix!
vdboor