我在一个奇怪的行为就已经离开我好奇,没有一个令人满意的解释呢。

为了简单起见,我已经减少我注意到下面的代码的症状:

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"到的SimpleDateFormat。)

原谅的可怕非卷绕线,但它是比较两种最简单的方法。如果您在滚动的方式约2 /三分之二,你会看到日历有1929年分别和2009年YEAR值。 (有一些其他方面的差异,如一年的一周,一周中的一天,和DST偏移量)。这是明显的GregorianCalendar的实例,但他们为什么不同的原因令人费解。

从我可以告诉格式传递给它的Date对象时,格式化产生准确的。显然,正确的功能比正确的基准年比较重要的,但差异仍然是令人不安。我不认为我必须要在一个全新的日期格式的日历刚刚获得本年度...

我与Java 5(OS X 10.4,PowerPC的)和Java 6(OS X 10.6,英特尔)具有相同的结果测试了这个在Mac。由于这是一个Java库API,我认为它的行为在所有平台上相同。关于怎么在这里正在酝酿任何见解?

(注意:这太问题是有点关系,但不相同)


修改

下面所有的答案有助于解释这种行为。事实证明的Javadoc 的SimpleDateFormat 实际上说明这在一定程度上:

  

“对于与缩写年图案解析(” Y”或‘YY’),的SimpleDateFormat必须解释缩写相对于一些世纪年份。它通过调整日期是在80年前,时间20年后SimpleDateFormat的实例被创建。“

所以,与其让花哨与日期的年份被解析,他们只是设置内部日历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的年是“默认世纪”的第一年,在其中一个两位数的年份的字符串(例如,“14年1月12日”)被解释的范围是。请参见 HTTP:/ /java.sun.com/j2se/1.4.2/docs/api/java/text/SimpleDateFormat.html#get2DigitYearStart%28%29

因此,在“效率”上清晰的胜利,在SimpleDateFormat的一年是用来存放“在100年周期为两个数字的年份进行解析的开始”,而不是目前的一年!

谢谢,这是有趣的 - 终于让我安装JDK源(我只对我的/分区4GB的总空间)

其他提示

您正在调查内部行为。这样下去公布的API之外,那么你看到的东西不确定,你不应该关心它。

除此之外,我相信的是,1929年被用于当考虑到两位数年解释为在19XX代替20XX之中。

的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());

上面的代码进行比较的比较苹果和梨

在第一提供你解析字符串成日期和反之亦然的工具 第二种是DateUtility,允许你操纵日期

有不是一个真正的原因应提供类似的输出。

用下面的比较它

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

将输出一个字符串,但logicly你不会期待同样的结果两行

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top