Linq to SQL DateTime values are local (Kind=Unspecified) - How do I make it UTC?

后端 未结 8 1856
萌比男神i
萌比男神i 2020-12-05 03:43

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 t

相关标签:
8条回答
  • 2020-12-05 04:31

    I use this way to specify the DateTimeKind on the fly:

    DateTime myDateTime = new DateTime(((DateTime)myUtcValueFromDb).Ticks, DateTimeKind.Utc);
    
    0 讨论(0)
  • 2020-12-05 04:34

    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.

    0 讨论(0)
  • 2020-12-05 04:35

    @rob263 provided an excellent method.

    This is only an additional help I wish to provide if you are using Entity Framework instead of Linq To Sql.

    Entity Framework does not support OnLoaded event.

    Instead, you can do the following:

     public partial class Person
        {
            protected override void OnPropertyChanged(string property)
            {
                if (property == "BirthDate")
                {
                    this._BirthDate= DateTime.SpecifyKind(this._BirthDate, DateTimeKind.Utc);
                }
    
                base.OnPropertyChanged(property);
            }
    
        }
    
    0 讨论(0)
  • 2020-12-05 04:41

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

    0 讨论(0)
  • 2020-12-05 04:45

    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, 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.

    0 讨论(0)
  • 2020-12-05 04:45

    For our case it was impractical to always specify the DateTimeKind as stated previously:

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

    We are using Entity Framework, but this should be similar to Linq-to-SQL

    If you want to force all DateTime objects coming out of the database to be specified as UTC you'll need to add a T4 transform file and add additional logic for all DateTime and nullable DateTime objects such that they get initialized as DateTimeKind.Utc

    I have a blog post which explains this step by step: http://www.aaroncoleman.net/post/2011/06/16/Forcing-Entity-Framework-to-mark-DateTime-fields-at-UTC.aspx

    In short:

    1) Create the .tt file for your .edmx model (or .dbml for Linq-to-SQL)

    2) Open the .tt file and find the "WritePrimitiveTypeProperty" method.

    3) Replace the existing setter code. This is everything between the ReportPropertyChanging and the ReportPropertyChanged method callbacks with the following:

    <#+ if( ((PrimitiveType)primitiveProperty.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.DateTime)
                {
    #>
            if(<#=code.FieldName(primitiveProperty)#> == new DateTime())
            {
                <#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
    <#+ 
                if(ef.IsNullable(primitiveProperty))
                {  
    #>              
                if(value != null)
                    <#=code.FieldName(primitiveProperty)#> = DateTime.SpecifyKind(<#=code.FieldName(primitiveProperty)#>.Value, DateTimeKind.Utc);
    <#+             } 
                else
                {#>
                <#=code.FieldName(primitiveProperty)#> = DateTime.SpecifyKind(<#=code.FieldName(primitiveProperty)#>, DateTimeKind.Utc);                
    <#+ 
                } 
    #>
            }
            else
            {
                <#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
            }
    <#+ 
            }
            else
            {
    #>
        <#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
    <#+ 
            }
    #>
    
    0 讨论(0)
提交回复
热议问题