【问题标题】:Why is SimpleDateFormat changing the date?为什么 SimpleDateFormat 会更改日期?
【发布时间】:2023-03-06 22:42:02
【问题描述】:

给定以下代码:

[...]

    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

为什么更改日期?

【问题讨论】:

  • 你甚至没有第二次写信给dateString。你确定没有错过dateString = date.toString();吗?
  • 我已经更正了这个例子。

标签: java date formatting simpledateformat


【解决方案1】:

大写的Y 代表"week year",它有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

See on ideone.com

如 cmets 中所述,请确保在解析 dateString 时包含 Locale.US,因为这是在 Date#toString 中硬编码的。详情请见this question

【讨论】:

  • 不知何故,我从 OP 的代码中得到了 ParseException。知道为什么吗?
  • 大写 Y 仅支持 JDK 7+。您使用的是旧版本吗?
  • 其实你的代码也会抛出异常。我正在使用 JDK 8。我在不同的语言环境中。你认为这重要吗? Locale.getDefault() 返回 ja_JP。
  • 有趣。你的dateString 是什么样的?
  • Sat Aug 19 18:56:28 BST 2017 你认为我应该发布一个关于这种行为的问题吗?
【解决方案2】:

首先我要说我完全同意 Marvins answer 但我希望有人会对更多技术细节感兴趣。

java doc 之后,SimpleDateFormat 你找不到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)会产生一些混淆。我们也可以找到

static final int PATTERN_YEAR                 =  1; // y

我们可以在互联网上搜索的含义差异(例如在 wiki 中)。但是在代码中使用它有什么区别呢?继续检查在SimpleDateFormat 中使用常量,我们可以发现PATTERN_WEEK_YEARPATTERN_YEAR 在几乎所有情况下都以类似的方式使用。但逻辑上的差异很小(只需使用DateFormatSymbols.java 查找元素)...因此我们将确保代码提供与 wiki 术语含义相同的含义。


...按照这种 java 调查方式(使用 java doc 和源代码),我们可以澄清几乎所有问题,而无需额外帮助来深入了解 JDK 知识。

【讨论】:

  • 在您链接的 javadoc 中,is 实际上是 Y 的解释和示例。
【解决方案3】:

实际上是同一天,英国夏令时 (BST) 正好比格林威治标准时间早一小时。

还要注意'Y'是一年中的第几周,你想要使用的是'y'

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

【讨论】:

  • 除了那个月份和日期也被改变了。所以不是同一个日期。
  • 哦,我错过了。
  • 不要将“一年中的一周”与“一周年”混淆。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-20
相关资源
最近更新 更多