0

I'm writing some code to store metadata from uploaded images in the database. One of those fields is the photo Capture Date. The API I'm using returns the Capture Date in the String format

Sat Nov 01 20:08:07 UTC 2014

However, Joda Time throws an IllegalArgumentException when creating a DateTime or LocalDateTime. Conversely, java.util.Date accepts the string formatting and creates a Date object with no issue.

One solution is to do

Date tempDate = new Date("Sat Nov 01 20:08:07 UTC 2014");
DateTime captureDate = new DateTime(tempDate);

but this requires creating two separate objects to persist one. Given the string format above, is it possible to convince JodaTime to create a DateTime object without an intermediary Date initialization?

Jason
  • 11,263
  • 21
  • 87
  • 181
  • Are you currently just calling `new DateTime(text)`? – Jon Skeet Nov 27 '14 at 15:40
  • Correct. This question is a specialized followup to http://stackoverflow.com/questions/27136877/joda-time-datetime-invalid-format-with-spring. – Jason Nov 27 '14 at 15:42
  • 1
    Right. It's always useful to give an example of the code that isn't working within your question... – Jon Skeet Nov 27 '14 at 15:45

2 Answers2

3

The Joda Time DateTime and LocalDate constructors which take Object have documentation including:

The String formats are described by ISODateTimeFormat.dateTimeParser().

The text you're providing is not in an ISO format.

Instead, you should create a DateTimeFormatter for the format you're using, e.g. via DateTimeFormat.forPattern, specifying the locale, time zone etc. (It's not clear from your example whether it's always going to be in UTC, or whether you need time zone handling.)

For example:

private static final DateTimeFormatter DATETIME_PARSER =
    DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss 'UTC' yyyy")
        .withLocale(Locale.US)
        .withZoneUTC();

...

DateTime dateTime = DATETIME_PARSER.parseDateTime(text);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Hmm, interesting. I came across similar code snippets looking for a solution, but the missing piece was the pattern for the formatter, particularly the EEE and 'UTC' inclusions. – Jason Nov 27 '14 at 15:48
  • @Jason: Well `EEE` is just the documented "short day of week as text"; The `'UTC'` is an escaped literal. – Jon Skeet Nov 27 '14 at 15:51
  • Exactly, but due to not uncovering a concrete example implementation combined with missing these specifics in the documentation resulted in me backtracking to a regular Date object. Appreciate the help. – Jason Nov 27 '14 at 15:55
  • I’d certainly prefer to parse the time zone abbreviation as such using the pattern `EEE MMM dd HH:mm:ss zzz yyyy`. The we no longer need `.withZoneUTC()`. Also when this works for very few time zone abbreviation. And also when Arvind Kumar Avinash is right in the other answer: we should be migrating our Joda-Time code to java.time by now. – Ole V.V. Jul 10 '21 at 05:29
1

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Also, quoted below is a notice from the home page of Joda-Time:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

Do not use a fixed text for the timezone:

Do not use a fixed text (e.g. 'UTC') for the timezone because that approach may fail for other locales.

Solution using java.time, the modern Date-Time API:

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

public class Main {
    public static void main(String[] args) {
        String strDateTime = "Sat Nov 01 20:08:07 UTC 2014";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM d H:m:s z u", Locale.ENGLISH);
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
        System.out.println(zdt);
    }
}

Output:

2014-11-01T20:08:07Z[Etc/UTC]

ONLINE DEMO

For any reason, if you need to convert this object of ZonedDateTime to an object of java.util.Date, you can do so as follows:

Date date = Date.from(zdt.toInstant());

Learn more about the modern Date-Time API from Trail: Date Time.

Just for the sake of completeness

Just for the sake of completeness, I have written the following solution using Joda Date-Time API:

import java.util.Locale;

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

public class Main {
    public static void main(String[] args) {
        String strDateTime = "Sat Nov 01 20:08:07 UTC 2014";
        DateTimeFormatter dtf = DateTimeFormat.forPattern("E MMM d H:m:s z y").withLocale(Locale.ENGLISH);
        DateTime dt = dtf.parseDateTime(strDateTime);
        System.out.println(dt);
    }
}

Output:

2014-11-01T20:08:07.000Z

* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110