윤년 버그로부터 보호하기 위해 설계된 코딩 관행을 어떻게 개발할 수 있습니까? [닫은]


80

마이크로 소프트는 지난주 윈도우 애저에서 날짜를 계산할 때 소프트웨어 오류 (윤년 이상)로 인해 심각한 중단이 발생 했다고 발표 했습니다.

DateTime.Now.AddYears(1)윤년에 대한 판단에서 정말 단순한 오류였습니까 ?

어떤 코딩 관행이 이것을 막을 수 있었습니까?

편집 dcstraw DateTime.Now.AddYears(1)가 윤년에 지적했듯이 실제로 .NET에서 올바른 날짜를 반환합니다. 따라서 프레임 워크 버그는 아니지만 날짜 계산의 버그 인 것 같습니다.


7
'하나의'대답이없고 이것은 토론적인 질문에 가깝기 때문에 프로그래머에게 마이그레이션해야한다고 생각합니다. 또한 : 항상 코드를 단위 테스트하십시오. 항상.
조지 스토커

2
DateTime 문제는 형편없고 복잡한 문제입니다. UTC로 모든 것을 수행하는 것과 같은 말을 할 수도 있지만 항상 번역 지점이있을 것입니다. 그리고 그럴 때 모든 버그 를 피하기 위해 고려해야 할 순열의 수 는 엄청납니다. 우리 대부분은 신경 써야하는 시스템에서 작업하지 않습니다.
Josh

9
나는이 질문이 너무 흥미로워 서 닫히지 않는다고 생각한다 :-)
Steven

11
4 개 투표를 마감 하시겠습니까? 나는 이것이 나쁜 기질, 행복한 가까운 일이 SO 진화의 한 단계에 불과하기를 바랍니다. 그것은 모두 당신보다 너무 거룩합니다.
Iain Holder

7
@IainMH는 특히 그것을 닫은 거의 모든 사람들이 몇 표 이상으로 질문을 한 적이 없기 때문에 당신과 동의해야합니다.
Lloyd

답변:


95

뻔뻔한 플러그 :

더 나은 날짜 및 시간 API 사용

내장 된 .NET 날짜 및 시간 라이브러리는 제대로 사용하기가 매우 어렵습니다. 그들은 당신이 필요한 모든 것을 할 있게 해주지 만, 당신은 타입 시스템을 통해 자신을 명확하게 표현할 수 없습니다 . DateTime은 엉망 이고, DateTimeOffset그렇지 않을 때 시간대 정보를 실제로 보존하고 TimeZoneInfo있다고 생각하게 만들 수 있으며, 고려해야 할 모든 것에 대해 생각하도록 강요하지 않습니다.

이들 중 어느 것도 "단지 시간"또는 "날짜"를 말하는 좋은 방법을 제공하지 않으며 "현지 시간"과 "특정 시간대의 시간"을 명확하게 구분하지 않습니다. 그레고리력이 아닌 다른 달력을 사용 Calendar하려면 전체 시간 동안 수업 을 진행해야합니다 .

이것이 제가 Noda Time을 구축하는 이유 입니다. Joda Time "엔진" 의 포트를 기반으로 구축 되었지만 새롭고 간결한 API가 위에 있는 대체 날짜 및 시간 라이브러리 입니다.

생각하고 싶을 수있는 몇 가지 요점은 알지 못하면 놓치기 쉽습니다.

  • 현지 날짜 / 시간을 특정 시간대에 매핑하는 것은 생각만큼 간단하지 않습니다. 일광 절약 전환으로 인해 특정 현지 날짜 / 시간이 한 번, 두 번 (모호함) 또는 0 번 (건너 뛰었 음) 발생할 수 있습니다.
  • 시간대는 역사적으로 다양 TimeZoneInfo합니다. 솔직히 말해서 일반적으로 공개하려는 것보다 더 많습니다 . ( "표준 시간"이라는 개념이 시간이 지남에 따라 변경되거나 영구적 인 일광 절약 시간 제로 전환되는 시간대는 지원하지 않습니다.)
  • zoneinfo 데이터베이스를 사용하더라도 시간대 ID가 반드시 안정적인 것은 아닙니다. (CLDR은이 문제를 해결합니다. 결국 Noda Time에서 지원하고 싶은 것입니다.)
  • 날짜와 시간의 텍스트 표현은 순서뿐 아니라 날짜 구분 기호, 시간 구분 기호 및 생식력 달 이름과 같은 이상한 것들이 악몽입니다.
  • 하루의 시작이 항상 자정은 아닙니다. 예를 들어 브라질에서는 봄 일광 절약 전환이 벽시계를 오후 11:59:59에서 오전 1 시로 이동합니다.
  • 어떤 경우에는 (내가 알고있는) 시간대가 하루 종일 건너 뛰도록 강요 할 수 있습니다. 2011 년 12 월 30 일은 사모아에서 발생하지 않았습니다! 나는 대부분의 개발자가 아마도 이것을 무시할 수 있다고 생각하지만 ...
  • 그레고리력이 아닌 다른 캘린더를 사용하려는 경우,주의를 기울이고 예상되는 방식을 확실히 알고 있어야합니다.

특정 개발 관행까지 :

  • 당신이 진정으로 표현하고자하는 것이 무엇인지 생각해보십시오.Noda Time의 핵심 이점은 개발자가 데이터를 표현하기 위해 다양한 유형 중에서 선택하도록 강요하는 것입니다. 제대로하면 다른 모든 것이 더 간단 해집니다.
  • 생각할 수있는 모든 것을 단위 테스트합니다. 물론 시스템이 수행하는 작업에 따라 다르지만 특히 다른 시간대, 일광 절약 전환 동안 발생하는 작업 및 물론 윤년을 고려하십시오.
  • 나는 명시 적으로 DateTime.Nowor를 호출하는 대신 현재 시간을 알려주는 서비스 인 "시계와 같은 인터페이스"를 삽입하는 것이 좋습니다 DateTime.UtcNow. 단위 테스트를 더 쉽게 (실행 가능합니다!)
  • "지금"을 사용하여 여러 작업을 수행하는 경우 "지금"을 반복적으로 요청하지 말고 해당 날짜 / 시간을 한 번 가져와 기억하십시오. 그렇지 않으면 값이 호출 사이에 불행한 방식으로 변경 될 수 있습니다.
  • "모든 것이 UTC로 표시됩니까"가 항상 답이되는 것은 아닙니다. " '지금부터 2 주 후'가 정확히 언제 내 현지 시간대로 발생합니까?"를 알고 싶다면? 그런 다음 현지 날짜 / 시간과 시간대 를 저장해야합니다 .

2
@flq : 다시 말하지만 "윤년 안전"이라는 의미를 정확히 정의해야합니다. Azure에서 문제를 일으킨 것이 프레임 워크 버그인지 의심 됩니다. 프레임 워크를 제대로 사용하지 않았을 입니다.
존 소총

10
윤년 주제 (즉, 주제)에 대해 단 하나도없는 수많은 총알 포인트. 그리고 트위터에 부풀었다. 더 좋은 순간을 보낸 것 같아요, 존
윌 딘

8
@WillDean : 또한 질문은 George Stocker에 의해 편집되었습니다. 원래 제목은 "DateTime 버그에 대한 방어적인 프로그래밍"이었습니다.이 경우 제 게시물 완전히 관련 이 있다는 데 동의하실 것 입니다. (제목이 바뀌 었다는 것만 알아 챘습니다. 제가 응답을 시작했을 때 DateTime이라고 적혀 있습니다 ...)
Jon Skeet

2
Jon, 죄송합니다. 이전 타이틀을 보지 못했습니다! 아마 ... 모든 해답도 편집에 제목을 변경하는 사람에 현직을해야합니다
윌 딘

3
@WillDean : 예 ... 내가 다시 두 롤 제목 변화에 유혹 해요하거나 "날짜 시간 버그 (예를 들어, 윤년)"로 끝나는하게
존 소총

25

버그가 게시 한 것과 같은 줄로 인한 것이 아니라는 점은 주목할 가치가 있습니다.

DateTime.Now.AddYears(1)

그것은 잘못된 날짜를 생성하지 않습니다. 실행하는 경우 :

(new DateTime(2012, 2, 29)).AddYears(1)

2013 년 2 월 28 일을 받게됩니다. Azure의 게스트 에이전트가 무엇으로 작성되었는지 모르겠지만 실패한 다른 호출 이었음에 틀림 없습니다. .NET에서이 작업을 수행하는 나쁜 방법은 다음과 같습니다.

new DateTime(today.Year + 1, today.Month, today.Day)

today윤일 이면 예외 가 발생합니다 . 그러나 Azure 문제에 대한 Microsoft 블로그에 따르면 2013 년 2 월 29 일의 잘못된 날짜가 생성되었다고합니다 DateTime.

나는 그것을 말하는 게 아니에요 DateTime그리고 DateTimeOffset나는 그들이이 특정 문제가 발생하는 것 생각하지 않는다 단지, 오류가 발생하기 쉬운되지 않습니다.


나는 ++은 C 이루어졌다 같은데요
PhilPursglove

2
@PhilPursglove : 당신이 그렇게 생각하는 이유는 무엇입니까? Windows OS는 대부분 C 및 C ++로 작성되었으며 윤일을 적절하게 처리합니다. 이전 인증서 생성 프로세스에서 날짜 관련 오류와 관련이있을 수 있습니다.
In silico

문자열에서 날짜를 구문 분석 할 수 있습니까?
Fixer

그리고 네가 지적한대로 AddYears (1)에 대해 맞습니다. 내부적으로 무슨 일이 일어 났는지 잘 모르겠습니다. 블로그 게시물에 너무 깊이 들어 가지 않고 질문에 약간의 관점을 제공하려는 시도였습니다.
Fixer 2011 년

말이 되네요. 솔직히 이것이 사실인지 모르겠지만 믿을만합니다. MS가 포함 된 대기업의 불쾌한 코드를 본 적이 있습니다. 그러나 다시 말하지만, 우리는이 시점에서 많은 것을 할 수는 없지만 추측합니다.
Alpha

2

윤년 버그로부터 보호하기 위해 설계된 코딩 관행을 어떻게 개발할 수 있습니까? 어떤 코딩 관행이 이것을 막을 수 있었습니까?

John이 언급 한대로 단위 테스트 특정 날짜는 도움이 될 하나의 코드 실행이지만 내가 '수동 통합 테스트'로 정의한 것을 능가하는 것은 없습니다.

개발 / 테스트 베드 서버의 시계를 변경하고 시간이 지날 때 어떤 일이 일어나는지 확인하십시오.

이것이 '코딩 관행'인지에 대한 세부 사항에 얽매이지 마십시오-분명히 달력의 모든 날짜에 대해 이것을 할 수는 없습니다-관심있는 날짜를 선택하십시오, 2 월 29 일, 월말 날짜 또는 일광 절약 전환 날짜.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.