在joda中将字符串解析为日期时间

时间:2017-09-23 15:35:03

标签: java datetime timezone jodatime datetime-parsing

我为这个解析感到疯狂。 代码如下:

try {
    String if_modified_since = "Sat Sep 23 23:08:37 CST 2017";
    DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss zzz yyyy");

    DateTime dt_if_modified_since = DateTime.parse(if_modified_since, dateTimeFormatter);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 

错误消息是:

  

java.lang.IllegalArgumentException:格式无效:“星期六9月23日23:08:37 CST 2017”

我试过了:

dateTimeFormatter.withLocale(Locale.US);

它不起作用。 如何解决?

3 个答案:

答案 0 :(得分:1)

我正在使用Joda-Time 2.9.9并且您的代码运行正常(“CST”被解析为America/Chicago时区)。但它是not guaranteed to work all the time,对于所有版本和时区,甚至我得到的结果都是有争议的,因为芝加哥目前处于夏令时,所以它应该是“CDT”(甚至是javadoc关于z模式说:时区名称('z')无法解析)。

这是因为短时区名称(例如“CST”和“EST”)是ambiguous and not standard。 “CST”可以是Central Standard TimeCuba Standard TimeChina Standard Time。在某些API中,某些名称会映射到任意默认值,但不能保证它们适用于所有这些名称。

即使我们只考虑美国的CST,也有不止一个区域(多个时区)使用它。唯一明确的名称是IANA timezones names(始终采用Region/City格式,如America/ChicagoEurope/Berlin),您应该尽可能使用这些名称。

考虑您的输入(Sat Sep 23 23:08:37 CST 2017)和发布问题的时间(以及目前美国中部地区处于夏令时的事实,they're actually in "CDT"),我的猜测是这个输入是指中国(但我可能错了,所以你必须验证这个输入产生的时区)。

无论如何,如果您对与“CST”对应的时区做出任意选择,则可以解析此String,并使用org.joda.time.format.DateTimeFormatterBuilder创建格式化程序。我还使用java.util.Locale将语言设置为英语(解析月份和星期几)。如果您没有指定语言环境,它将使用JVM默认值,并且不保证始终为英语:

String if_modified_since = "Sat Sep 23 23:08:37 CST 2017";

// map of my arbritrary choices for timezones
Map<String, DateTimeZone> preferredZones = new HashMap<String, DateTimeZone>();
// CST maps to a Chinese timezone
preferredZones.put("CST", DateTimeZone.forID("Asia/Shanghai"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // date/time
    .appendPattern("EEE MMM dd HH:mm:ss ")
    // zone name - use my map of arbitrary choices
    .appendTimeZoneShortName(preferredZones)
    // year
    .appendPattern(" yyyy")
    // create formatter with English locale
    .toFormatter().withLocale(Locale.US);

DateTime dt = DateTime.parse(if_modified_since, fmt);

正如我所说,我选择了Asia/Shanghai时区,但你必须检查输入对应的正确时区是什么。您可以致电DateTimeZone.getAvailableIDs()获取所有可用区域的列表(并选择最适合您情况的区域)。

Java新日期/时间API

Joda-Time处于维护模式,正在被新的API取代,因此我不建议使用它来启动新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“即可。

如果您不能(或不想)从Joda-Time迁移到新API,则可以忽略此部分。

如果您使用的是 Java 8 ,请考虑使用new java.time API。它更容易,less bugged and less error-prone than the old APIs

如果您使用的是 Java&lt; = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,您还需要ThreeTenABP(更多关于如何使用它here)。

以下代码适用于两者。 唯一的区别是包名称(在Java 8中为java.time,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp),但类和方法名称是相同的

代码与Joda的代码非常相似,您还必须对时区做出任意选择(由于“CST”的模糊性)。首先,我创建一个格式化程序,然后将输入解析为ZonedDateTime(表示时区中的日期和时间的类):

String if_modified_since = "Sat Sep 23 23:08:37 CST 2017";

// set of preferred zones
Set<ZoneId> preferredZones = new HashSet<ZoneId>();
// my arbitrary choice for CST
preferredZones.add(ZoneId.of("Asia/Shanghai"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // date/time
    .appendPattern("EEE MMM dd HH:mm:ss ")
    // zone name - use my arbitrary choices
    .appendZoneText(TextStyle.SHORT, preferredZones)
    // year
    .appendPattern(" yyyy")
    // create formatter with English locale
    .toFormatter(Locale.US);
ZonedDateTime z = ZonedDateTime.parse(if_modified_since, fmt);

请注意,我不需要说“CST是亚洲/上海”。 API找到短名称(CST),并使用Set作为参考(因此选择Asia/Shanghai),在具有该短名称的所有区域中决定使用哪个区域。

答案 1 :(得分:0)

我刚测试了你的代码,它编译并正确运行。我正在使用jodatime 1.0.3。

确保您拥有包含权:

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; 

答案 2 :(得分:0)

JodaTime似乎只期望工作日的两个字母(如果你使用EEE);如果我使用它,你的代码对我有用:

String if_modified_since = "Sa Sep 23 23:08:37 CST 2017";

(版本:Joda-time 2.9.9)