날짜 처리 다시 물기

2557 단어 dotnet
안녕

내 팀 동료 중 한 명이 우리 코드 기반에서 흥미로운 문제를 발견하여 내가 글을 써야겠다고 생각했습니다.

TLDR: DateTimeOffset을 DateTime.MinValue와 비교하지 말고 DateTimeOffset.MinValue와 비교하십시오.

기술적으로 시스템 시간대가 항상 UTC 또는 UTC에서 일부 오프셋을 뺀 값이 되도록 보장할 수 있는 경우 DateTimeOffset을 DateTime.MinValue와 비교할 수 있습니다.

디테일 속으로



API에 대한 팀원의 모든 요청은 동일한 예외와 함께 실패했지만 마스터 분기와 똑같은 요청을 실행했음에도 불구하고 오류를 재현할 수 없었습니다.

FluentValidation 패키지의 AbstractValidator 생성자에서 예외가 발생했습니다.

public class TestValidator : AbstractValidator<ThingWithDate>
{
    public TestValidator()
    {
        RuleFor(x => x.Date)
            .GreaterThan(default(DateTime));
    }
}

이 유효성 검사기는 BaseController(👍)를 통해 API의 거의 모든 컨트롤러에 주입되었습니다.

문제를 재현하려면 발칸 반도(UTC+3)에 있는 동료와 동일한 시스템 시간대를 사용하여 서비스를 실행해야 했습니다.

스택 추적에서 다음을 확인할 수 있습니다.
  • 우리는 TestValidator
  • 이는 DateTimeOffset 암시적 캐스트 연산자를 눌러 DateTimeDateTimeOffset 로 변환하는 것입니다.
  • 하나의 DateTimeOffset 매개변수를 허용하는 DateTime 생성자를 호출합니다.
  • 생성자가 ValidateDate(DateTime, Timespan) 를 호출합니다. TimeSpan는 UTC와 로컬 시스템 시간대의 차이입니다.

  • 내부적으로 a DateTimeOffsetDateTime이고 오프셋은 분 단위입니다. ValidateDate 당연히 오프셋이 적용될 때 DateTime가 유효한지 확인합니다. DateTime.MinValue에 음수 오프셋을 적용하면 DateTime 유형으로 나타낼 수 없는 날짜가 표시되고 대신 ArgumentOutOfRangeException가 표시됩니다.

    다음은 validate 메소드lifted from here에 대한 코드입니다. 댓글은 내꺼야...

    private static DateTime ValidateDate(DateTime dateTime, TimeSpan offset)
    {
        // +2 is 72000000000 ticks
        // utcTicks is converting the "local" dateTime to UTC by subtracting the offset
        Int64 utcTicks = dateTime.Ticks - offset.Ticks;
    
        // This section validates that utcTicks is a valid time that can be represented
    
        // utcTicks = -72000000000
        // DateTime.MinTicks = 0
        // -72000000000 < 0 == true => Kablamo
        if (utcTicks < DateTime.MinTicks || utcTicks > DateTime.MaxTicks)
        {
            throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("Argument_UTCOutOfRange"));
        }
        return new DateTime(utcTicks, DateTimeKind.Unspecified);
    }
    

    좋은 웹페이지 즐겨찾기