Java SimpleDateFormat pattern for W3C XML dates with timezone [duplicate]
Asked Answered
B

9

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?

Byers answered 16/5, 2012 at 8:33 Comment(1)
Actually, that input string is in a format from the ISO 8601 standard (a family of date-time formats).Chartist
G
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);
    }
};
Gentry answered 16/5, 2012 at 8:51 Comment(3)
Clever, elegant and functional. Thanks!Byers
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).Byers
changed to yyyy-MM-dd'T'HH:mm:ss.SSSZ and it worked like a charm for miliseconds tooArgentine
G
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");
Goldbrick answered 16/5, 2012 at 8:46 Comment(5)
This is very nice to know. I'm still stuck with java 1.6- :(Portend
Same here about Java 6, but thanks for noting this.Byers
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').Byers
@Byers You are right - amended.Goldbrick
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 docs.oracle.com/javase/7/docs/api/java/text/… (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.Vein
G
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);
    }
};
Gentry answered 16/5, 2012 at 8:51 Comment(3)
Clever, elegant and functional. Thanks!Byers
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).Byers
changed to yyyy-MM-dd'T'HH:mm:ss.SSSZ and it worked like a charm for miliseconds tooArgentine
P
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.

Portend answered 16/5, 2012 at 8:44 Comment(0)
G
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();
Gwin answered 16/5, 2012 at 8:43 Comment(3)
JodaTime does not support all the patterns that Java SimpleDateFormat class supports.Byers
@Byers Yes but your were asking specifically about the ISO 8601 format.Gwin
Sure, I just pointed out the limitation. Otherwise, JodaTime would probably be the way to go.Byers
I
3

The best way is to Use the Joda's

org.joda.time.format.ISODateTimeFormat

Regards,

Impearl answered 16/5, 2012 at 9:19 Comment(0)
R
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;
              }
Retrieval answered 5/9, 2013 at 10:24 Comment(0)
C
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. :)

Cicerone answered 16/5, 2012 at 8:42 Comment(1)
I was after something simpler, but thanks for the effort. :-)Byers
I
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));
Industrious answered 16/5, 2012 at 9:6 Comment(0)
P
1

You can try something like:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
Date date = df.parse(stringDate.replaceAll("\\+", "GMT+"));
Pinot answered 16/5, 2012 at 9:22 Comment(1)
Sure, but I was wondering whether it can be done without preprocessing.Byers

© 2022 - 2024 — McMap. All rights reserved.