在Java中将字符串解析为日期

6

我正在尝试将一个字符串解析为日期,这是我的代码:

SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zZ (zzzz)");
Date date = new Date();
try {
    date = sdf.parse(time);
} catch (ParseException e) {
    e.printStackTrace();
}

需要解析的字符串是:

Sun Jul 15 2012 12:22:00 GMT+0300 (FLE Daylight Time)

我按照http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html的说明操作,但是出现了ParseException错误提示。
java.text.ParseException: Unparseable date: 
"Sun Jul 15 2012 12:22:00 GMT+0300 (FLE Daylight Time)"

我做错了什么?我尝试过的模式:

EEE MMM dd yyyy HH:mm:ss zzz
EEE MMM dd yyyy HH:mm:ss zZ (zzzz)

1
我认为应该是 "... zz (zzzz),你把一个 Z 大写了。 - Joachim Sauer
@JoachimSauer 很不幸问题仍然存在。 - Jaanus
这里是:D 我认为那个覆盖了你所需的:D - ioreskovic
time 字符串从哪里来? - Keppil
5个回答

11

看起来你混淆了zZ的模式。如果你忽略(FLE Daylight Time),因为这是与GMT+0300相同的信息,问题就在于SimpleDateFormat需要GMT +0300GMT+03:00格式。可以像这样解析最后一种变体:

String time = "Sun Jul 15 2012 12:22:00 GMT+03:00 (FLE Daylight Time)";
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zzz");
Date date = sdf.parse(time);

[编辑]
鉴于其他帖子中提到他们的时间字符串有效,这可能是因为您的时间字符串包含冲突信息或混合格式。


你需要在时间字符串中添加“:”才能使其正常工作。 - Keppil
你确定使用的是:EEE MMM dd yyyy HH:mm:ss zzz,当我将其打印出来:Date date = new Date();,然后显示格式:System.out.println(sdf.format(date));,它会打印出:Thu Jul 12 2012 10:47:09 EEST - Jaanus
实际上我已经这样做了,而且它有效... time = time.substring(0, 31) + ":" + time.substring(31);。看起来很奇怪,没有更简单的方法吗? - Jaanus
就像我说的那样,似乎您的“时间”字符串在不幸的情况下使用了混合格式,这会给“SimpleDateFormat”带来麻烦,因此,如果您有任何方法以更友好的模式生成它,那肯定会有所帮助。 - Keppil
问题出现在不同的时区GMT或EEET,所以我只将它缩减到我需要的部分,即分钟和秒。time = time.substring(0, 21); - Jaanus

2

java.time

我将为您提供现代答案。在处理日期和时间时,请使用java.time,这是现代的Java日期和时间API。

首先,定义一个解析格式:

private static final DateTimeFormatter PARSER = DateTimeFormatter
        .ofPattern("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (", Locale.ROOT);

那么就这样解析:

    String time = "Sun Jul 15 2012 12:22:00 GMT+0300 (FLE Daylight Time)";
    
    TemporalAccessor parsed = PARSER.parse(time, new ParsePosition(0));
    OffsetDateTime dateTime = OffsetDateTime.from(parsed);
    
    System.out.println(dateTime);

输出结果为:

2012年7月15日12:22+03:00

我没有解析你整个字符串,但已经足够确定一个时间点和与GMT(或UTC)的偏移量。Java无法解析时区名称“FLE Daylight Time”,这是Microsoft发明的,Java不认识。因此,我从包含“FLE”之前的圆括号解析该字符串的部分内容以进行验证。为了指示DateTimeFormatter无需解析整个字符串,我使用带有ParsePosition作为第二个参数的重载parse方法。

来自维基百科:

有时由于其在 Microsoft Windows 上的使用,FLE标准时间(适用于芬兰、立陶宛、爱沙尼亚,或者有时适用于芬兰、拉脱维亚、爱沙尼亚)...被用来指代东欧时间。

如果您必须使用Date对象,通常是为了遗留API,现在不能升级到java.time,请按以下方式进行转换:

    Date oldfashionedDate = Date.from(dateTime.toInstant());
    System.out.println(oldfashionedDate);

在欧洲/塔林时区运行时的输出:

2012年7月15日星期日12:22:00 EEST

你的代码出了什么问题?

您的SimpleDateFormat成功地将GMT+03解析为与格式模式字符串中的小写z匹配的“时区”。然后,它尝试将剩余的00解析为与大写Z匹配的偏移量。由于偏移量需要一个符号,因此失败了。

我做错了什么?

正如其他人所说,您不应尝试将GMT解析为时区缩写。 GMT可以用作时区缩写;但是您的时间不在GMT中。所以你不想要那个。这只会让人产生误解。如果你成功了,你可能会冒险得到错误的结果,因为你已经解析了一个对你的目的来说不正确的时区。

链接


1

试着这样做...

System.out.println(new SimpleDateFormat(
                "EEE MMM dd yyyy HH:mm:ss zZ (zzzz)").format(new Date()));

我得到的输出:

Thu Jul 12 2012 12:41:35 IST+0530 (India Standard Time)

它使用的是我的母语,而不是英语,天哪,“2012年7月12日10:19:35 EEST + 0300(东欧夏令时)”。 - Jaanus
使用 SimpleDateFormat(String pattern, Locale.US) - Subs
@Subs使用了语言环境,但仍然出现异常。 - Jaanus

1
您可以尝试打印日期格式字符串:
/**
 * @param args
 */
public static void main(String[] args) {
    SimpleDateFormat sdf = new SimpleDateFormat(
            "EEE MMM dd yyyy HH:mm:ss zZ (zzzz)");
    Date date = new Date();
    try {
        //
        System.out.println(sdf.format(date));
        date = sdf.parse(time);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

它正在使用我的语言,我想让它使用英语。2012年7月12日10:18 EEST + 0300(东欧夏令时) - Jaanus

1
如果您在本地化方面遇到问题,您可以为整个应用程序设置默认语言环境。
Locale.setDefault(Locale.ENGLISH);

或者在您的SimpleDateFormat中使用英文本地化。

SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zZ (zzzz)", Locale.ENGLISH);

您还可以使用 Locale.USLocale.UK


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接