簡體   English   中英

為什么SimpleDateFormat會更改日期?

[英]Why is SimpleDateFormat changing the date?

給出以下代碼:

[...]

    public void testFormatDateString() throws ParseException {

        String dateString = new java.util.Date().toString();

        System.out.println(dateString);

        SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss z YYYY", Locale.ENGLISH);

        Date date = format.parse(dateString);

        System.out.println(date.toString());
    }

[...]

之前: Sat Aug 19 18:26:11 BST 2017

之后: Sat Jan 07 17:26:11 GMT 2017

為什么日期改變了?

大寫Y代表“周年” ,它有364或371天而不是通常的365或366.小寫y (由Date#toString )一切都按預期工作:

public void testFormatDateString() throws ParseException {

    String dateString = new java.util.Date().toString();

    System.out.println(dateString);

    // Force to Locale.US as this is hardcoded in Date#toString
    SimpleDateFormat format = new SimpleDateFormat(
            "EEE MMM dd HH:mm:ss z yyyy", Locale.US);

    Date date = format.parse(dateString);

    System.out.println(date.toString());
}

輸出:

Sat Aug 19 17:50:39 GMT 2017
Sat Aug 19 17:50:39 GMT 2017

請參閱ideone.com

正如評論中所提到的,確保在解析dateString時包含Locale.US ,因為它在Date#toString中是硬編碼的。 有關詳情,請參閱此問題

首先,我會說我完全同意Marvins的回答,但我希望有人會對更多技術細節感興趣。

在使用SimpleDateFormat java doc之后 ,您無法找到YYYY示例。 但它有效,驗證通過。 深入檢查:

public class SimpleDateFormat extends DateFormat {
//....
/**
 * Returns the compiled form of the given pattern. The syntax of
 * the compiled pattern is:
 * <blockquote>
 * CompiledPattern:
 *     EntryList
 * EntryList:
 *     Entry
 *     EntryList Entry
 * Entry:
 *     TagField
 *     TagField data
 * TagField:
 *     Tag Length
 *     TaggedData
 * Tag:
 *     pattern_char_index
 *     TAG_QUOTE_CHARS
 * Length:
 *     short_length
 *     long_length
 * TaggedData:
 *     TAG_QUOTE_ASCII_CHAR ascii_char
 *
 * </blockquote>
 * ....
 *
 * @exception NullPointerException if the given pattern is null
 * @exception IllegalArgumentException if the given pattern is invalid
 */
    private char[] compile(String pattern) {
        ...
        if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
            throw new IllegalArgumentException("Illegal pattern character " +
                                               "'" + c + "'");
        }
        ...
    }
    ...
}

檢查允許的模式符號(在驗證條件中使用) DateFormatSymbols.patternChars

public class DateFormatSymbols implements Serializable, Cloneable {
    ...
    static final String  patternChars = "GyMdkHmsSEDFwWahKzZYuXL";
    ...
}

Y是有效的模式元素,它意味着什么(讓我們在同一個DateFormatSymbols類中檢查常量)?

static final int PATTERN_ERA                  =  0; // G
static final int PATTERN_YEAR                 =  1; // y
static final int PATTERN_MONTH                =  2; // M
static final int PATTERN_DAY_OF_MONTH         =  3; // d
static final int PATTERN_HOUR_OF_DAY1         =  4; // k
static final int PATTERN_HOUR_OF_DAY0         =  5; // H
static final int PATTERN_MINUTE               =  6; // m
static final int PATTERN_SECOND               =  7; // s
static final int PATTERN_MILLISECOND          =  8; // S
static final int PATTERN_DAY_OF_WEEK          =  9; // E
static final int PATTERN_DAY_OF_YEAR          = 10; // D
static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
static final int PATTERN_WEEK_OF_YEAR         = 12; // w
static final int PATTERN_WEEK_OF_MONTH        = 13; // W
static final int PATTERN_AM_PM                = 14; // a
static final int PATTERN_HOUR1                = 15; // h
static final int PATTERN_HOUR0                = 16; // K
static final int PATTERN_ZONE_NAME            = 17; // z
static final int PATTERN_ZONE_VALUE           = 18; // Z
static final int PATTERN_WEEK_YEAR            = 19; // Y
static final int PATTERN_ISO_DAY_OF_WEEK      = 20; // u
static final int PATTERN_ISO_ZONE             = 21; // X
static final int PATTERN_MONTH_STANDALONE     = 22; // L

在這里你可以找到Y模式元素(名稱可讀清晰):

static final int PATTERN_WEEK_YEAR            = 19; // Y

*_WEEK_YEAR如果我們期望單個YEAR (遵循命名約定PATTERN_YEAR ), *_WEEK_YEAR提供一些混淆。 我們也可以找到

static final int PATTERN_YEAR                 =  1; // y

我們可以在互聯網上搜索的意義差異(例如在wiki中)。 但是在代碼中使用它有什么區別? 繼續檢查在SimpleDateFormat中使用常量,我們可以檢測到幾乎所有情況都以類似的方式使用PATTERN_WEEK_YEARPATTERN_YEAR 但是邏輯差異很小(只是在DateFormatSymbols.java找到元素)......結果我們將確保代碼提供相同的wiki術語含義。


...遵循這種java調查方式(使用java doc和sources),我們可以澄清幾乎所有問題,而無需獲得深入的JDK知識的額外幫助。

實際上是同一天,英國夏令時(BST)比格林威治標准時間提前一小時。

另請注意,'Y'是一年中的一周,您想要使用的是'y'

https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM