roast_soul
roast_soul

Reputation: 3650

Parsing string to datetime in joda

I'm crazy about this parsing. Code as below:

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();
    } 

The error message is:

java.lang.IllegalArgumentException: Invalid format: "Sat Sep 23 23:08:37 CST 2017"

I tried:

dateTimeFormatter.withLocale(Locale.US);

It didn't work. How to fix it?

Upvotes: 0

Views: 1103

Answers (3)

user7605325
user7605325

Reputation:

I'm using Joda-Time 2.9.9 and your code runs fine ("CST" is parsed to America/Chicago timezone). But it's not guaranteed to work all the time, for all versions and timezones, and even the result I've got is controversial, because Chicago is currently in Daylight Saving Time, so it should be "CDT" (and even the javadoc says about the z pattern: Time zone names ('z') cannot be parsed).

That's because short timezone names (such as "CST" and "EST") are ambiguous and not standard. "CST" can be Central Standard Time, Cuba Standard Time and China Standard Time. In some API's, some names are mapped to an arbitrary default, but it's not guaranteed to work for all of them.

Even if we consider only US's CST, there's more than one region (more than one timezone) that uses it. The only unambiguous names are IANA timezones names (always in the format Region/City, like America/Chicago or Europe/Berlin), and you should prefer to use those whenever possible.

Considering your input (Sat Sep 23 23:08:37 CST 2017) and the time you posted the question (and also the fact that currently US's central region is in Daylight Saving Time, so they're actually in "CDT"), my guess is that this input refers to China (but I might be wrong, so you must verify in what timezone this input was generated).

Anyway, you can parse this String if you make an arbitrary choice about what's the timezone that corresponds to "CST", and use a org.joda.time.format.DateTimeFormatterBuilder to create a formatter. I also use a java.util.Locale to set the language to English (to parse the month and day of week). If you don't specify a locale, it'll use the JVM default, and it's not guaranteed to always be English:

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);

As I said, I've chosen Asia/Shanghai timezone, but you must check what's the correct timezone that the input corresponds to. You can get a list of all available zones (and choose the one that best suits your case) by calling DateTimeZone.getAvailableIDs().


Java new Date/Time API

Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".

If you can't (or don't want to) migrate from Joda-Time to the new API, you can ignore this section.

If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.

If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).

The code below works for both. The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.

The code is very similar to Joda's, and you'll also have to make an arbitrary choice about the timezone (due to ambiguity of "CST"). First I create a formatter, and then I parse the input to a ZonedDateTime (a class that represents a date and time in a timezone):

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);

Note that I don't need to say "CST is Asia/Shanghai". The API finds the short name (CST) and it decides among all the zones with that short name which one will be used, using the Set as reference (so Asia/Shanghai is picked).

Upvotes: 1

JensS
JensS

Reputation: 1151

JodaTime seems to expect only two letters of the weekday (if you use EEE); your code works for me if I use this:

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

(version: Joda-time 2.9.9)

Upvotes: 0

DobromirM
DobromirM

Reputation: 2027

I just tested your code and it compiles and runs correctly. I am using jodatime 1.0.3.

Make sure that you have your includes right:

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

Upvotes: 0

Related Questions