Java String to Date格式

问题描述

我有String以下的日期要解析并格式化为Sept 21 2021,但有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)

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

解决方法

我认为您的问题是您的Locale中缺少SimpleDateFormat。如果未明确设置,则代码可能会使用默认的Locale,然后可能不是ENGLISH,而是默认的,可能是在菲律宾人的计算机上。例如,它将尝试解析 Tue 的菲律宾语缩写,从而导致无法解析的String

以下是与您相同的ENGLISH后在我的计算机上工作的(也是Exception不能工作的情况)

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.time的Java 8-10解决方案:

此代码可在Java 8和10上成功运行,但根据the answer by @ArvindKumarAvinash,由于{{1中的时区缩写, }}。

您可以在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,也可以通过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",parserDtf);
LocalDate expiryLocalDate = zdt.toLocalDate();
System.out.println("Something will expire at "
                    + expiryLocalDate.format(DateTimeFormatter.ofPattern("MMM dd uuuu",Locale.ENGLISH)));

Trails中了解有关Something will expire at Sep 21 2021 的更多信息。

,

answer by deHaar很出色,但是Java-11失败了。一个安全的选择是用corresponding Zone-Offset value代替PHT。

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日期时间类已过时且容易出错,其格式API SimpleDateFormat也是如此。我建议您应该完全停止使用它们,并切换到modern date-time API

如果您正在为自己的Android项目执行此操作,并且您的Android API级别仍不符合Java-8,请选中Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

通过 Trail: 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);
    }
}
,

我是新来的,如果做错了事,对不起。

“ Tue”包含三个字符,格式应为

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

说明

菲律宾标准时间的缩写似乎是Java 10之前的PHT,而Java 11之前是PST。一种查看此代码的方法是运行以下代码:

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

Java 9上的输出:

PHT

Java 11上的输出:

PST

我起初以为是CLDR的不同版本(Unicode通用语言环境数据存储库)是原因。但是,当我改用Java的原始语言环境数据(以-Djava.locale.providers=COMPAT运行)时,我在行为上会有相同的区别,所以我不确定。

在任何情况下,如果可以避免的话,您都不应首先依赖三个字母的时区abbreviaitons。它们往往是模棱两可的,并且不是标准化的。因此,您真的不确定自己会得到什么。

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