33

I am trying to parse a W3C XML Schema date like the following

"2012-05-15T07:08:09+03:00"

which complies with the ISO 8601 version of the W3C XML Schema dateTime specification.

In the above date, the timezone identifier is "+03:00", but no SimpleDateFormat pattern apparently exists to represent it.

If the timezone were "+0300", then Z (uppercase) would be applicable and the SimpleDateFormat pattern would be

yyyy-MM-dd'T'HH:mm:ssZ

Similarly, if the timezone were "GMT+03:00", then z (lowercase) would be applicable and the SimpleDateFormat pattern would be

yyyy-MM-dd'T'HH:mm:ssz

(uppercase 'Z' also works, by the way).

So, is there a SimpleDateFormat pattern or workaround to represent the above date without preprocessing of the date string?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
PNS
  • 19,295
  • 32
  • 96
  • 143
  • Actually, that input string is in a format from the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard (a family of date-time formats). – Basil Bourque Sep 05 '16 at 21:15

9 Answers9

38

If you use Java 7+, this pattern should work (X is for the ISO 8601 time zone):

SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
assylias
  • 321,522
  • 82
  • 660
  • 783
  • This is very nice to know. I'm still stuck with java 1.6- :( – Alvin May 16 '12 at 08:57
  • 1
    Same here about Java 6, but thanks for noting this. – PNS May 16 '12 at 09:01
  • 1
    The correct pattern for the date example of this question should probably be "yyyy-MM-dd'T'HH:mm:ssX" (i.e., just one 'X'). – PNS May 16 '12 at 14:24
  • @PNS You are right - amended. – assylias May 16 '12 at 14:31
  • 13
    If only one `X` is used, you'll get a truncated time zone, e.g., `2014-03-03-T16:00:00-08`. From my reading of http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html (and testing), you want `XXX` in order to get a properly formatted time zone (at least in terms of what the OP points to, specifically section 3.2.7.3), e.g., `"yyyy-MM-dd'T'HH:mm:ssXXX"`, which gives you `2014-03-03-T16:00:00-08:00`. Note the colon-separated time zone info. – Ted M. Young Mar 04 '14 at 00:05
26

How about something like:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"){ 
    public Date parse(String source,ParsePosition pos) {    
        return super.parse(source.replaceFirst(":(?=[0-9]{2}$)",""),pos);
    }
};
Vlad
  • 18,195
  • 4
  • 41
  • 71
  • Clever, elegant and functional. Thanks! – PNS May 16 '12 at 11:46
  • 1
    Whoever needs to use the ParsePosition after parse() returns, you may need to adjust the index by one inside parse(), since the source is actually 1 longer, i.e. do something like pos.setIndex(pos.getIndex()+1). – PNS May 16 '12 at 11:49
  • 2
    changed to `yyyy-MM-dd'T'HH:mm:ss.SSSZ` and it worked like a charm for miliseconds too – EpicPandaForce Jul 06 '15 at 12:06
  • Great, thanks for sharing and +1. :-) – PNS Jul 06 '15 at 23:27
11

Hmmm the date format looks like XML datetime datatype format? If it is XML datetime datatype format you can use javax.xml.datatype.DatatypeFactory to create XMLGregorianCalendar

DatatypeFactory
  .newInstance()
  .newXMLGregorianCalendar("2012-05-15T07:08:09+03:00");

The above call returns instance of XMLGregorianCalendar you can use the object to convert to other Java datetime objects like GregorianCalendar.

Alvin
  • 10,308
  • 8
  • 37
  • 49
3

No, there is no workaround to make SimpleDateFormat understand this format without preprocessing the string (for example by removing the : from the string). (edit: except if you're using Java 7 or newer as noted by assylias).

It looks like you're trying to parse strings in the standard XML format for dates and times (ISO 8601). I would recommend using the Joda Time library which has support for this format.

If you can't or don't want to use Joda Time for some reason, then you can use classes from the package javax.xml.datatype to parse and format timestamps in this format. For example:

DatatypeFactory factory = DatatypeFactory.newInstance();

// Parses a string in ISO 8601 format to an XMLGregorianCalendar
XMLGregorianCalendar xmlCal = factory.newXMLGregorianCalendar("2012-05-16T10:39:00+03:00");

// Convert it to a regular java.util.Calendar
Calendar cal = xmlCal.toGregorianCalendar();
Jesper
  • 202,709
  • 46
  • 318
  • 350
3

The best way is to Use the Joda's

org.joda.time.format.ISODateTimeFormat

Regards,

Grim
  • 1,938
  • 10
  • 56
  • 123
3

use Apache commons DateUtils with possible patterns. Ex:

private static final String[] DATE_FORMATS = new String[] {
            "yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ssz",
            "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-ddz", "yyyy-MM-ddZ" };


    public Date parse(String date) {

        Date parsedDate = null;
        try {
            parsedDate = DateUtils.parseDate(date, DATE_FORMATS);
        } catch (ParseException e) {
            logger.error("dates should be in valid format" + e);
            return null;
        }
               return parsedDate;
              }
1

I am not quite sure whether this will work for you or not. But here the code I have tried while converting date from one timezone to another timezone. May some part of the code can help you.

public Date convertToUserTimezone(long dateToConvert, String timezoneOffset){
        java.text.DateFormat format = SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);/*new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");*/
        // java.util.Calendar cal = Calendar.getInstance(new
        // SimpleTimeZone(0, "GMT+05:30"));
        TimeZone gmtTime = TimeZone.getTimeZone("GMT"+timezoneOffset);


        format.setTimeZone(gmtTime);
        java.util.Date date1 = new Date(format.format(new Date(dateToConvert)));

        return date1;
    }

Hope this helps you. Cheers. :)

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
Japan Trivedi
  • 4,445
  • 2
  • 23
  • 44
1

With regards to SimpleDateFormat you have already mentioned the format patterns that are available and they are defined in: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

If you want to do more with your Date then GregorianCalendar gives you more options, e.g.:

TimeZone zone = TimeZone.getTimeZone(TimeZone.getTimeZone("GMT-8").getID());
GregorianCalendar calendar = new GregorianCalendar(zone);
calendar.setTime(new Date(SomeDate));
Marky Mark
  • 98
  • 1
  • 1
  • 5
1

You can try something like:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
Date date = df.parse(stringDate.replaceAll("\\+", "GMT+"));
tibtof
  • 7,857
  • 1
  • 32
  • 49