source

SQL DateTime에 대한 링크 값은 로컬(Kind=Unspecified)입니다. UTC로 만들려면 어떻게 해야 합니까?

lovecheck 2023. 7. 21. 21:41
반응형

SQL DateTime에 대한 링크 값은 로컬(Kind=Unspecified)입니다. UTC로 만들려면 어떻게 해야 합니까?

Linkq To SQL 클래스에 특정 DateTime 속성을 UTC로 간주해야 한다고(즉, DateTime 유형의 Kind 속성을 기본적으로 UTC로 지정) 알리는 (간단한) 방법이 있습니까? 아니면 '깨끗한' 해결 방법이 있습니까?

앱 서버의 표준 시간대가 SQL 2005 Server(변경할 수 없음)와 동일하지 않고 UTC가 없습니다.DateTime을 dB에 입력하는 속성을 유지하는 경우 UTC 값을 사용하지만(따라서 db 열의 값은 UTC) 값을 다시 읽을 때(LinqTo SQL 사용) DateTime 값의 .Kind 속성이 '지정되지 않음'으로 표시됩니다.

문제는 제가 UTC로 '변환'할 때 4시간이 어긋난다는 것입니다.이는 또한 직렬화된 경우 UTC를 사용하여 직렬화되었기 때문에 클라이언트 측에서 4시간의 잘못된 오프셋이 발생한다는 것을 의미합니다.

생성된 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입니다.지정되지 않음.

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

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

또는 그에 상응하는 것:

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

다음과 같이 변환하려고 하는 것이 문제라고 생각합니다.

DateTime utcDateTime = databaseDateTime.ToUniversalTime();

DateTime에 대한 MSDN 문서에 따르면 이는 언뜻 보기에는 합리적인 것처럼 보일 수 있습니다.UniversalTime으로, 종류가 지정되지 않은 날짜 시간을 변환할 때:

현재 DateTime 개체는 로컬 시간으로 가정되며 변환은 Kind were Local처럼 수행됩니다.

이 동작은 와의 이전 버전과의 호환성을 위해 필요합니다.날짜 시간이 없는 NET 1.x.친절한 재산.

제가 생각할 수 있는 유일한 방법은 번역을 하는 부분 클래스에 심 속성을 추가하는 것입니다...

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

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

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

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

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

간단히 말해서:

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

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

기존 세터 코드를 교체합니다.이것이 그 사이의 모든 것입니다.ReportPropertyChanging 리고그고.ReportPropertyChanged메소드 콜백은 다음과 같습니다.

<#+ 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를 사용하고 있다면 제가 제공하고 싶은 추가적인 도움일 뿐입니다.

엔티티 프레임워크가 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로 반환되는 날짜 시간(Kind=Unspecified)을 영향을 받는 시간 없이 UTC 시간으로 변환할 수 있습니다.

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

이를 위한 더 깨끗한 방법이 있을 수 있지만, 저는 이것을 손에 넣었고 빠르게 테스트할 수 있었습니다!

LINQ에서 SQL 클래스로 투명하게 작동할 수 있는 방법이 있는지 확신할 수 없습니다. 부분 클래스를 보고 값이 읽히거나 쓰여진 위치를 후크할 수 있는지 확인해야 할 수도 있습니다.

저는 UTC를 원하며, 다른 시간대 간에 변환을 원한다면 TimeZoneInfo가 당신을 위한 것보다 TimeZone 클래스가 당신을 위해 그것을 해줄 수 있습니다.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

반응형