새로운 SimpledateFormat 객체에 잘못된 연도의 캘린더가 포함되어있는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1258441

문제

나는 아직도 호기심을 느끼고 아직 만족스러운 설명 없이도 이상한 행동을 취했다.

단순화를 위해 다음 코드로 알아 차린 증상을 줄였습니다.

import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;

public class CalendarTest {
    public static void main(String[] args) {
        System.out.println(new SimpleDateFormat().getCalendar());
        System.out.println(new GregorianCalendar());
    }
}

이 코드를 실행하면 다음 출력과 매우 유사한 것을 얻습니다.

java.util.GregorianCalendar[time=-1274641455755,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=1929,MONTH=7,WEEK_OF_YEAR=32,WEEK_OF_MONTH=2,DAY_OF_MONTH=10,DAY_OF_YEAR=222,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=8,HOUR_OF_DAY=20,MINUTE=55,SECOND=44,MILLISECOND=245,ZONE_OFFSET=-28800000,DST_OFFSET=0]
java.util.GregorianCalendar[time=1249962944248,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Los_Angeles",offset=-28800000,dstSavings=3600000,useDaylight=true,transitions=185,lastRule=java.util.SimpleTimeZone[id=America/Los_Angeles,offset=-28800000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2009,MONTH=7,WEEK_OF_YEAR=33,WEEK_OF_MONTH=3,DAY_OF_MONTH=10,DAY_OF_YEAR=222,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=1,HOUR=8,HOUR_OF_DAY=20,MINUTE=55,SECOND=44,MILLISECOND=248,ZONE_OFFSET=-28800000,DST_OFFSET=3600000]

(유효한 형식 문자열을 제공하면 동일한 일이 발생합니다. "yyyy-MM-dd" 단순화하기 위해.)

끔찍한 랩핑 라인을 용서하지만 두 가지를 비교하는 가장 쉬운 방법입니다. 약 2/3의 길이로 스크롤하면 캘린더의 연도 값이 각각 1929 년과 2009 년입니다. (연도, 요일 및 DST 오프셋과 같은 몇 가지 다른 차이점이 있습니다.) 둘 다 분명히 GregorianCalendar의 사례이지만, 다른 이유는 수수께끼입니다.

내가 말할 수있는 것에서 Formatter는 날짜 객체를 형식화 할 때 정확하게 생성됩니다. 분명히, 올바른 기능은 올바른 참조 연도보다 중요하지만 불일치는 당황 스럽습니다. 나는 현재 연도를 얻기 위해 새로운 날짜 Formatter에 달력을 설정해야한다고 생각하지 않을 것입니다 ...

Java 5 (OS X 10.4, PowerPC) 및 Java 6 (OS X 10.6, Intel)으로 Mac에서 동일한 결과를 테스트했습니다. 이것은 Java 라이브러리 API이므로 모든 플랫폼에서 동일하게 작동한다고 가정합니다. 여기에 무엇이 나오는지에 대한 통찰력이 있습니까?

(메모: 이렇게 질문 다소 관련이 있지만 동일하지는 않습니다.)


편집하다:

아래의 답변은이 행동을 설명하는 데 도움이되었습니다. Javadocs가 그게 밝혀졌습니다 SimpledateFormat 실제로 이것을 어느 정도 문서화하십시오.

"약어 연도 패턴 ("Y "또는"YY ")으로 구문 분석을 위해 SimpledateFormat은 몇 세기에 비해 약식 연도를 해석해야합니다. 단순화 된 인스턴스가 80 년 이내에 및 20 년 이내에 날짜를 조정함으로써이를 수행합니다. 만들어졌습니다. "

따라서, 날짜가 구문 분석 된 해에 화려하지 않고, 그들은 기본적으로 내부 달력을 80 년으로 되돌 렸습니다. 그 부분은 그 자체로 문서화되어 있지 않지만, 당신이 그것에 대해 알면, 조각은 모두 함께 맞습니다.

도움이 되었습니까?

해결책

톰이 왜 "직렬화와 관련이있는 것"이라고 말하는지 잘 모르겠지만, 그는 올바른 줄을 가지고 있습니다.

private void initializeDefaultCentury() {
    calendar.setTime( new Date() );
    calendar.add( Calendar.YEAR, -80 );
    parseAmbiguousDatesAsAfter(calendar.getTime());
}

SimpledateFormat.java의 813 행은 프로세스에서 매우 늦었습니다. 그 시점까지 올해는 정확합니다 (나머지 날짜 부분과 마찬가지로)은 80으로 줄어 듭니다.

아하!

전화 parseAmbiguousDatesAsAfter() 동일한 개인 기능입니다 set2DigitYearStart() 전화 :

/* Define one-century window into which to disambiguate dates using
 * two-digit years.
 */
private void parseAmbiguousDatesAsAfter(Date startDate) {
    defaultCenturyStart = startDate;
    calendar.setTime(startDate);
    defaultCenturyStartYear = calendar.get(Calendar.YEAR);
}

/**
 * Sets the 100-year period 2-digit years will be interpreted as being in
 * to begin on the date the user specifies.
 *
 * @param startDate During parsing, two digit years will be placed in the range
 * <code>startDate</code> to <code>startDate + 100 years</code>.
 * @see #get2DigitYearStart
 * @since 1.2
 */
public void set2DigitYearStart(Date startDate) {
    parseAmbiguousDatesAsAfter(startDate);
}

이제 무슨 일이 일어나고 있는지 봅니다. 피터는 "사과와 오렌지"에 대한 그의 의견에서 옳았습니다! SimpledateFormat의 해는 "기본 세기"의 첫해이며, 2 자리 문자열 (예 : "1/12/14")이 해석되는 범위입니다. 보다 http://java.sun.com/j2se/1.4.2/docs/api/java/text/simpledateformat.html#get2digityearstart%28%29 :

따라서 명확성에 대한 "효율성"의 승리로, SimpledateFormat의 연도는 "올해의 연도가 아닌 2 자리 기간의 시작"을 저장하는 데 사용됩니다!

고마워요, 이것은 재미 있었고 마침내 JDK 소스를 설치하게되었습니다 (나는 4GB 총 공간 만 내 내에 있습니다. / 분할.)

다른 팁

당신은 내부 행동을 조사하고 있습니다. 이것이 게시 된 API 밖으로 나가면 정의되지 않은 물건을보고 있으면 신경 쓰지 않아야합니다.

그 외에는 1929 년이 2 자리 연도를 20xx 대신 19xx에있는 것으로 해석 할시기를 고려하는 데 사용된다고 생각합니다.

SimpledateFormat의 내부 상태가 있습니다. 이것이 내가 전염병처럼 피하는 이유입니다 (추천합니다 조다 시간). 이 내부 캘린더는 아마도 날짜를 구문 분석하는 과정에서 사용될 수 있지만 날짜를 구문 분석하기 전에 특히 초기화 될 이유가 없습니다.

설명 할 코드는 다음과 같습니다.

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;

public class DateTest {
    public static void main(String[] args) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
        System.out.println("sdf cal: " + simpleDateFormat.getCalendar());
        System.out.println("new cal: " + new GregorianCalendar());
        System.out.println("new date: " + simpleDateFormat.format(new Date()));
        System.out.println("sdf cal: " + simpleDateFormat.getCalendar());
    }
}

simpledateformat를 살펴보면 직렬화와 관련된 것 같습니다.

/* Initialize the fields we use to disambiguate ambiguous years. Separate
 * so we can call it from readObject().
 */
private void initializeDefaultCentury() {
    calendar.setTime( new Date() );
    calendar.add( Calendar.YEAR, -80 );
    parseAmbiguousDatesAsAfter(calendar.getTime());
}
System.out.println(new SimpleDateFormat().getCalendar());
System.out.println(new GregorianCalendar());

위의 코드를 비교하는 것은 사과와 배를 비교하는 것입니다

첫 번째는 날짜로 문자열을 구문 분석하는 도구를 제공하고 그 반대의 경우 두 번째는 날짜를 조작 할 수있는 데이트 혜택입니다.

실제로 비슷한 출력을 제공 해야하는 이유는 없습니다.

다음과 비교하십시오

System.out.println(new String() );
System.out.println(new Date().toString() );

두 줄 모두 문자열을 출력하지만 논리적으로 동일한 결과를 기대하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top