[java] Java Calendar에서 1 월 달이 0 인 이유는 무엇입니까?

에서 java.util.Calendar, 1 월은 0으로 정의하지 달 1. 것과 특정의 이유가 있나요?

많은 사람들이 그것에 대해 혼란스러워하는 것을 보았습니다 …



답변

Java 날짜 / 시간 API 인 끔찍한 혼란의 일부일뿐입니다. 무엇이 잘못되었는지 나열하는 데는 시간이 오래 걸릴 것입니다 (그리고 문제의 절반을 모른다고 확신합니다). 날짜와 시간으로 작업하는 것은 까다로울 수 있지만 어쨌든 매우 큽니다.

호의를 가지고 대신 Joda Time 또는 JSR-310을 사용하십시오 .

편집 : 이유에 관해서는-다른 답변에서 언급했듯이 오래된 C API 또는 0부터 시작하는 일반적인 느낌으로 인해 발생할 수 있습니다. 당일은 물론 1로 시작합니다. 원래 구현 팀 외부의 누군가가 실제로 이유를 밝힐 수 있는지 의심 스럽지만 독자 는 잘못된 결정의 전체 영역을 살펴보기 위해 잘못된 결정을 내린 이유 에 대해 너무 걱정하지 말 것을 촉구합니다 .java.util.Calendar 더 나은 것을 찾기 위해 .

0 기반 인덱스를 사용하는 것을 선호 하는 한 가지 점 “이름 배열”과 같은 것을 쉽게 만든다는 것입니다.

// I "know" there are 12 months
String[] monthNames = new String[12]; // and populate...
String name = monthNames[calendar.get(Calendar.MONTH)];

물론, 이것은 13 개월의 달력을 얻 자마자 실패하지만 적어도 지정된 크기는 예상 개월 수입니다.

이것은 아니다 좋은 이유,하지만 그건 이유 …

편집 : 주석 종류의 날짜 / 캘린더에서 내가 잘못 생각하는 것에 대한 몇 가지 아이디어를 요청합니다.

  • 놀라운 기준 (날짜의 연도 기준은 1900, 더 이상 사용되지 않는 생성자에 대해서는 인정, 둘 다의 월 기준은 0)
  • 변경 가능-불변 유형을 사용하면 실제로 효과적인 으로 작업 하는 것이 훨씬 간단 해집니다.
  • 불충분 한 유형의 집합 : 가지고 Date있고 좋은Calendar 여러 가지 있지만 값이없는 “존”대 “로컬”의 분리로, 같은 시간 대 날짜 대 날짜 / 시간
  • 명확하게 명명 된 메소드 대신 매직 상수를 사용하여 못생긴 코드를 생성하는 API
  • 추론하기 매우 어려운 API-일이 재 계산되는시기에 관한 모든 사업 등
  • 매개 변수가없는 생성자를 기본적으로 “지금”으로 설정하면 테스트하기 어려운 코드가 생성됨
  • Date.toString()항상 (의 지금 전에 많은 스택 오버플로 사용자를 혼동 것을) 시스템 로컬 시간대를 사용하여 구현

답변

몇 달 동안 수학하는 것이 훨씬 쉬우니까요.

12 월 이후 1 개월은 1 월이지만 일반적으로이를 파악하려면 월 번호를 가져 와서 수학을 수행해야합니다.

12 + 1 = 13 // What month is 13?

알아! 모듈러스 12를 사용하여이 문제를 빠르게 해결할 수 있습니다.

(12 + 1) % 12 = 1

이것은 11 월까지 11 개월 동안 잘 작동합니다 …

(11 + 1) % 12 = 0 // What month is 0?

월을 추가하기 전에 1을 빼고 다시 모듈로 계산 한 다음 다시 1을 다시 추가하면이 문제를 모두 해결할 수 있습니다.

((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!

이제 0-11 개월의 문제에 대해 생각해 봅시다.

(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January

모든 달은 동일하게 작동하며 해결 방법이 필요하지 않습니다.


답변

C 기반 언어는 C를 어느 정도 복사합니다. 에 tm정의 된 구조 는 (주석) 범위가 0-11 time.h인 정수 필드 tm_mon를 갖습니다 .

C 기반 언어는 인덱스 0에서 배열을 시작합니다. 따라서 인덱스로 월 이름 배열로 문자열을 출력하는 데 편리했습니다 tm_mon.


답변

이에 대한 답변이 많이 있었지만 어쨌든 주제에 대한 견해를 밝힐 것입니다. 앞에서 언급 한 것처럼이 이상한 동작의 원인은 POSIX C time.h에서 나온 것입니다. POSIX C 는 0-11 범위의 정수로 저장됩니다. 이유를 설명하려면 다음과 같이보십시오. 연도 및 일수는 구어 숫자로 간주되지만 월은 고유 한 이름을 갖습니다. 따라서 1 월은 첫 달이므로 첫 번째 배열 요소 인 오프셋 0으로 저장됩니다. monthname[JANUARY]될 것 "January"입니다. 연도의 첫 달은 첫 달 배열 요소입니다.

반면 요일 숫자는 이름이 없으므로 0-30으로 int에 저장하면 혼란 스러울 수 있으며 day+1출력에 대한 많은 지시 사항을 추가하고 물론 많은 버그가 발생하기 쉽습니다.

그러나 불일치는 혼란 스럽습니다. 특히 자바 스크립트 (이 기능을 상속받은 자바 스크립트)에서 언어와는 거리가 먼 곳에 추상화되어야하는 스크립팅 언어입니다.

TL; DR : 월은 이름이 있고 월은 없습니다.


답변

Java 8에는 새로운 Date / Time API JSR 310 이 있습니다. 사양 리드는 JodaTime의 기본 작성자와 동일하며 많은 유사한 개념과 패턴을 공유합니다.


답변

게으름을 말하고 싶습니다. 배열은 0에서 시작합니다 (모두 알고 있음). 일년 중 몇 달은 배열이므로 Sun의 일부 엔지니어는이 작은 코드를 Java 코드에 넣는 것을 귀찮게하지 않았다고 생각합니다.


답변

아마도 C의 “struct tm”도 마찬가지이기 때문입니다.