繁体   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