IT TIP

Linq to SQL DateTime 값은 로컬입니다 (종류 = Unspecified)-UTC로 만들려면 어떻게해야합니까?

itqueen 2020. 12. 12. 12:53
반응형

Linq to SQL DateTime 값은 로컬입니다 (종류 = Unspecified)-UTC로 만들려면 어떻게해야합니까?


특정 DateTime 속성이 UTC로 간주되어야한다고 Linq To SQL 클래스에 (즉, DateTime 유형의 Kind 속성이 기본적으로 Utc가되도록하는) (간단한) 방법이 있습니까? 아니면 '깨끗한'해결 방법이 있습니까? ?

내 앱 서버의 표준 시간대는 SQL 2005 Server (변경할 수 없음)와 동일하지 않으며 UTC도 아닙니다. DateTime 유형의 속성을 dB로 유지하면 UTC 값을 사용하지만 (db 열의 값은 UTC가 됨) 값을 다시 읽을 때 (Linq To SQL 사용) DateTime의 .Kind 속성을 얻습니다. 값은 '지정되지 않음'이됩니다.

문제는 내가 그것을 UTC로 '변환'하면 4 시간 떨어져 있다는 것입니다. 이것은 또한 직렬화 될 때 클라이언트 측에서 4 시간의 잘못된 오프셋으로 끝납니다 (UTC를 사용하여 직렬화되기 때문에).


생성 된 LinqToSql 코드는 확장 지점을 제공하므로 개체가로드 될 때 값을 설정할 수 있습니다.

핵심은 생성 된 클래스를 확장하는 부분 클래스를 만든 다음 OnLoaded부분 메서드 를 구현하는 것입니다.

예를 들어, 클래스가 가정 해 봅시다 Person당신이 생성 된 부분이, 그래서 Person에서 클래스를 Blah.designer.cs.

다음과 같이 새 클래스 (다른 파일에 있어야 함)를 작성하여 부분 클래스를 확장하십시오.

public partial class Person {

  partial void OnLoaded() {
    this._BirthDate = DateTime.SpecifyKind(this._BirthDate, DateTimeKind.Utc);
  }
}

SQL Server DateTime에는 표준 시간대 또는 DateTimeKind 정보가 포함되어 있지 않으므로 데이터베이스에서 검색된 DateTime 값의 Kind = DateTimeKind.Unspecified가 올바르게 지정됩니다.

이 시간을 UTC로 만들려면 다음과 같이 '변환'해야합니다.

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

또는 동등한 것 :

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

귀하의 문제는 다음과 같이 변환하려는 것입니다.

DateTime utcDateTime = databaseDateTime.ToUniversalTime();

언뜻보기에는 합리적으로 보일 수 있지만 종류가 지정되지 않은 DateTime을 변환 할 때 DateTime.ToUniversalTime대한 MSDN 설명서 에 따르면 다음과 같습니다.

현재 DateTime 개체는 현지 시간으로 간주되며 Kind가 Local 인 것처럼 변환이 수행됩니다.

이 동작은 DateTime.Kind 속성이없는 .NET 1.x와의 하위 호환성을 위해 필요합니다.


이렇게 할 수있는 유일한 방법은 번역을 수행하는 부분 클래스에 shim 속성을 추가하는 것입니다.


우리의 경우 앞에서 언급 한대로 항상 DateTimeKind를 지정하는 것은 비현실적이었습니다.

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

우리는 Entity Framework를 사용하고 있지만 이것은 Linq-to-SQL과 유사해야합니다.

데이터베이스에서 나오는 모든 DateTime 개체를 UTC로 지정하려면 T4 변환 파일을 추가하고 DateTimeKind.Utc로 초기화되도록 모든 DateTime 및 nullable DateTime 개체에 대한 논리를 추가해야합니다.

이 단계를 단계별로 설명하는 블로그 게시물이 있습니다. http://www.aaroncoleman.net/post/2011/06/16/Forcing-Entity-Framework-to-mark-DateTime-fields-at-UTC.aspx

요컨대 :

1) .edmx 모델 용 .tt 파일 (또는 Linq-to-SQL의 경우 .dbml)을 만듭니다.

2) .tt 파일을 열고 "WritePrimitiveTypeProperty"메소드를 찾습니다.

3) 기존 세터 코드를 교체합니다. 이것은 다음과 함께 ReportPropertyChangingReportPropertyChanged메소드 콜백 사이의 모든 것입니다 .

<#+ 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)#>);
<#+ 
        }
#>

@ rob263은 훌륭한 방법을 제공했습니다.

이것은 Linq To Sql 대신 Entity Framework를 사용하는 경우 제공하려는 추가 도움말 일뿐입니다.

Entity Framework는 OnLoaded 이벤트를 지원하지 않습니다.

대신 다음을 수행 할 수 있습니다.

 public partial class Person
    {
        protected override void OnPropertyChanged(string property)
        {
            if (property == "BirthDate")
            {
                this._BirthDate= DateTime.SpecifyKind(this._BirthDate, DateTimeKind.Utc);
            }

            base.OnPropertyChanged(property);
        }

    }

이 방법을 사용 하여 즉석 에서 DateTimeKind 를 지정합니다 .

DateTime myDateTime = new DateTime(((DateTime)myUtcValueFromDb).Ticks, DateTimeKind.Utc);

이 코드 조각을 사용하면 LINQ에서 SQL로 돌아온 DateTimes (Kind = Unspecified)를 시간에 영향을주지 않고 UTC 시간으로 변환 할 수 있습니다.

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

이 작업을 수행하는 더 깨끗한 방법이있을 수 있지만이 작업을 수행하고 신속하게 테스트 할 수있었습니다!

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.


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);            

참고URL : https://stackoverflow.com/questions/823313/linq-to-sql-datetime-values-are-local-kind-unspecified-how-do-i-make-it-utc

반응형