简体   繁体   English

为什么SimpleDateFormat会更改日期?

[英]Why is SimpleDateFormat changing the date?

Given the following code: 给出以下代码:

[...]

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

[...]

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

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

Why is the date changed? 为什么日期改变了?

The upper case Y is for "week year" , which has 364 or 371 days instead of the usual 365 or 366. With lower case y (which is used by Date#toString ) everything works as expected: 大写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());
}

Output: 输出:

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

See on ideone.com 请参阅ideone.com

As mentioned in the comments, make sure to include Locale.US when parsing the dateString , as that is hardcoded in Date#toString . 正如评论中所提到的,确保在解析dateString时包含Locale.US ,因为它在Date#toString中是硬编码的。 See this question for details. 有关详情,请参阅此问题

The first of all I would say that I completely agree with Marvins answer but I hope someone will be interested in more technical details. 首先,我会说我完全同意Marvins的回答,但我希望有人会对更多技术细节感兴趣。

Following java doc for SimpleDateFormat you can't find example with YYYY . 在使用SimpleDateFormat java doc之后 ,您无法找到YYYY示例。 But it works and validation is passed. 但它有效,验证通过。 Checking deeper: 深入检查:

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 + "'");
        }
        ...
    }
    ...
}

Checking allowed pattern symbols (that used in validation condition) DateFormatSymbols.patternChars : 检查允许的模式符号(在验证条件中使用) DateFormatSymbols.patternChars

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

Y is valid pattern element, what's it means (lets check constants in same DateFormatSymbols class)? 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

and here you can find the Y pattern element (the name is readable clear): 在这里你可以找到Y模式元素(名称可读清晰):

static final int PATTERN_WEEK_YEAR            = 19; // Y

*_WEEK_YEAR provides some confuse if we expecting single YEAR (following naming convention PATTERN_YEAR ). *_WEEK_YEAR如果我们期望单个YEAR (遵循命名约定PATTERN_YEAR ), *_WEEK_YEAR提供一些混淆。 Also we can find 我们也可以找到

static final int PATTERN_YEAR                 =  1; // y

Difference of meaning we can search in internet (in wiki for example). 我们可以在互联网上搜索的意义差异(例如在wiki中)。 But what is the difference of using it in code? 但是在代码中使用它有什么区别? Continuing the check of using constants in SimpleDateFormat we can detect that PATTERN_WEEK_YEAR and PATTERN_YEAR are used in similar way for almost all cases. 继续检查在SimpleDateFormat中使用常量,我们可以检测到几乎所有情况都以类似的方式使用PATTERN_WEEK_YEARPATTERN_YEAR But with small logical difference (just find elements using in DateFormatSymbols.java )... and as result we'll be sure that code provides same to wiki terming meaning. 但是逻辑差异很小(只是在DateFormatSymbols.java找到元素)......结果我们将确保代码提供相同的wiki术语含义。


...following this java investigation way (using java doc and sources) we can clarify almost all questions without additional help with getting deep JDK knowledges. ...遵循这种java调查方式(使用java doc和sources),我们可以澄清几乎所有问题,而无需获得深入的JDK知识的额外帮助。

It is actually the same date, British Summer Time (BST) is exactly one hour ahead of GMT. 实际上是同一天,英国夏令时(BST)比格林威治标准时间提前一小时。

Note also that 'Y' is the Week of the year, What you want to use is 'y' 另请注意,'Y'是一年中的一周,您想要使用的是'y'

https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html 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