Java 字符串转日期格式

Java String to Date format

我尝试解析并格式化为 Sept 21 2021 的日期低于 String,但有 ParsingException:

String expiryDate ="Tue Sep 21 12:11:37 PHT 2021";
System.out.println(expiryDate);
Date formatter = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy").parse(expiryDate);
Exception in thread "main" java.text.ParseException:
Unparseable date: "Tue Sep 21 12:11:37 PHT 2021"
    at java.base/java.text.DateFormat.parse(DateFormat.java:395)

我想我解析的日期格式不正确,但找不到正确的格式。

我是新来的,如果我做错了什么请见谅。

“星期二”包含三个字符,格式应为

"EEE MMM dd HH:mm:ss z yyyy"

我认为你的问题是 SimpleDateFormat 中缺少 Locale。如果您没有明确设置一个,代码可能会使用您的默认 Locale,这可能不是 ENGLISH,而是其他东西,这可能位于菲律宾的计算机上。例如,它会尝试解析 Tue 的菲律宾语缩写,这会导致无法解析 String.

在获得与您相同的 Exception 后,以下是我的计算机(也不是 ENGLISH)的工作方式:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH)
                .parse(expiryDate);
System.out.println(date.toString());

这给出了以下输出:

Tue Sep 21 06:11:37 CEST 2021

这也适用于只有一个 E 的模式。


Java 8 - 10 解 java.time:

这在 Java 8 和 10 上成功运行,但根据 ,这在 Java 11 和可能以上版本中不起作用String expiryDate.

中的时区缩写

您可以在 java.time 中这样做:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu",
                                                            Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(expiryDate, parserDtf);
System.out.println("Something will expire at " + zdt);

它会输出

Something will expire at 2021-09-21T12:11:37+08:00[Asia/Manila]

可以通过另一个 DateTimeFormatter 更改输出格式,使用 built-in 作为 DateTimeFormatter.ISO_ZONED_DATE_TIME 或通过 .ofPattern(pattern, Locale.ENGLISH) 创建自定义格式或使用 DateTimeFormatterBuilder.

考虑到您只需要格式化和输出日期部分,您可以选择简单地提取日期部分(即 LocalDate)并将其格式化为 java.time:

String expiryDate = "Tue Sep 21 12:11:37 PHT 2021";
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu",
                                                            Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(expiryDate, parserDtf);
LocalDate expiryLocalDate = zdt.toLocalDate();
System.out.println("Something will expire at "
                    + expiryLocalDate.format(DateTimeFormatter.ofPattern("MMM dd uuuu",
                                                                        Locale.ENGLISH)));

会输出

Something will expire at Sep 21 2021

Trails 中阅读有关 java.time 的更多信息。

is brilliant but that fails with Java-11. A safe option will be to replace PHT with the corresponding Zone-Offset value.

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String expiryDate = "Tue Sep 21 12:11:37 PHT 2021".replace("PHT", "GMT+08:00");
        OffsetDateTime odt = OffsetDateTime.parse(expiryDate,
                DateTimeFormatter.ofPattern("EEE MMM d H:m:s ZZZZ u", Locale.ENGLISH));
        System.out.println(odt);

        // Custom format
        String formatted = odt.format(DateTimeFormatter.ofPattern("EEEE MMMM dd uuuu 'at' hh:mm:ss a", Locale.ENGLISH));
        System.out.println(formatted);
    }
}

输出:

2021-09-21T12:11:37+08:00
Tuesday September 21 2021 at 12:11:37 PM

注意: java.util date-time 类 已过时,error-prone 格式也已过时 API , SimpleDateFormat。我建议你应该完全停止使用它们并切换到 modern date-time API.

如果您正在为您的 Android 项目执行此操作,并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring and .

Trail: Date Time.

了解有关现代 date-time API 的更多信息

旧版 API:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Main {
    public static void main(String[] args) throws ParseException {
        String expiryDate = "Tue Sep 21 12:11:37 PHT 2021".replace("PHT", "GMT+08:00");
        Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZZ yyyy").parse(expiryDate);
        System.out.println(date);

        // Custom format
        String formatted = new SimpleDateFormat("EEEE MMMM dd yyyy 'at' hh:mm:ss a", Locale.ENGLISH).format(date);
        System.out.println(formatted);
    }
}

解释

菲律宾标准时间的缩写似乎是 PHT 到 Java 10,而 PST 从 Java 11 开始。一种查看方式是 运行 以下片段代码:

    DateTimeFormatter zf = DateTimeFormatter.ofPattern("z", Locale.ROOT);
    ZoneId zid = ZoneId.of("Asia/Manila");
    System.out.println(zf.format(ZonedDateTime.now(zid)));

Java9 上的输出:

PHT

Java11 上的输出:

PST

起初我以为是 CLDR(Unicode Common Locale Data Repository)版本不同的原因。但是当我使用 Java 的原始语言环境数据代替时 (运行 -Djava.locale.providers=COMPAT),我在行为上得到了相同的差异,所以我不太确定。

在任何情况下,如果有任何方法可以避免,您首先不应依赖三个字母的时区缩写。它们往往是模棱两可的,而且没有标准化。所以你真的不能确定你得到了什么。

除此之外,告诉您为格式化程序指定语言环境的评论和答案也是正确的。