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) 기존 세터 코드를 교체합니다. 이것은 다음과 함께 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를 사용하는 경우 제공하려는 추가 도움말 일뿐입니다.
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);
'IT TIP' 카테고리의 다른 글
OpenCL / AMD : 딥 러닝 (0) | 2020.12.12 |
---|---|
`.catch (err => console.error (err))`가 권장되지 않는 이유는 무엇입니까? (0) | 2020.12.12 |
제네릭-여기서 T는 숫자입니까? (0) | 2020.12.12 |
Ninject 모듈의 의도는 무엇입니까? (0) | 2020.12.12 |
std :: stoi는 실제로 사용하기에 안전합니까? (0) | 2020.12.12 |