4

Using SimpleDateFormat, how can you parse the String: "2013-05-23T09:18:07 p.m..380+0000"

All my SimpleDateFormat Strings are tripping up on the "p.m." part.

Thanks in advance.

EDIT: We have no control over the format coming in.

I've tried:

"yyyy-MM-dd'T'HH:mm:ss a.a..SSSZ"

"yyyy-MM-dd'T'HH:mm:ss aaaa.SSSZ"

"yyyy-MM-dd'T'HH:mm:ss a.'m'..SSSZ"

"yyyy-MM-dd'T'HH:mm:ss a.'m.'.SSSZ"

"yyyy-MM-dd'T'HH:mm:ss a.'m..'SSSZ"

"yyyy-MM-dd'T'HH:mm:ss aa'm'..SSSZ"

"yyyy-MM-dd'T'HH:mm:ss aa'm.'.SSSZ"

"yyyy-MM-dd'T'HH:mm:ss aaa'..'SSSZ"

"yyyy-MM-dd'T'HH:mm:ss aaa.'.'SSSZ"

"yyyy-MM-dd'T'HH:mm:ss aaa'.'.SSSZ"
djechlin
  • 59,258
  • 35
  • 162
  • 290
mtical
  • 299
  • 4
  • 15
  • 1
    Well that suggests you've tried *some* things - what have you tried? (That's a fairly odd looking format, I have to say. I assume you don't have any control over it?) – Jon Skeet May 23 '13 at 22:10
  • What have you tried to solve this? The [`java.text.SimpleDateFormat`](http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html) javadoc explains how to handle this. – Luiggi Mendoza May 23 '13 at 22:10
  • 1
    can you translate the strings before passing them to the SimpleDateFormat? e.g. replace "p.m." with "PM" and "a.m." with "AM"? – DannyMo May 23 '13 at 22:16
  • What is this part? 380+0000 ???? – Menelaos May 23 '13 at 22:16
  • So if I answer this it's just going to be me regurgitating the SimpleDateFormat documentation to you, then you'll tell me that you tried that already and it didn't work. So let's just skip ahead to you telling me what you tried. What are your simple format strings? – djechlin May 23 '13 at 22:17
  • Why the downvote? There is literally no best practice on the INTERNET for this particular scenario. – mtical May 23 '13 at 22:18
  • Are you 1) doing this leniently? How did the strings fail? – djechlin May 23 '13 at 22:19
  • 1
    Question... do you really care about the seconds and miliseconds? Also the p.m. part is redundant. You can remove via string manipulation... – Menelaos May 23 '13 at 22:19
  • This? http://stackoverflow.com/questions/3618676/unable-to-parse-datetime-string-with-am-pm-marker – djechlin May 23 '13 at 22:20
  • Can you explain the 380+0000 part? does it work when you remove it? Really weird that you're mixing am/pm time with GMT offset. International but... not. – djechlin May 23 '13 at 22:25
  • I haven't DV'ed since this does seem to be an original question as far as SO is concerned, but I'm witholding upvote since there's too many questions I would need answered here that you could have tried, namely, chopping off parts of the format to know what interaction is going badly. Do this research and I would upvote. – djechlin May 23 '13 at 22:27
  • It's quite obvious what OP has tried... passing given strings to SimpleDateFormat – Danubian Sailor May 24 '13 at 07:49

4 Answers4

13

It's not clear what the "380+0000" part is meant to be, but you can fix the AM/PM part, by setting the DateFormatSymbols for the SimpleDateFormat. Here's an example:

import java.util.*;
import java.text.*;

public class Test {
    public static void main(String[] args) throws Exception {
        String text = "2013-05-23T09:18:07 p.m..380+0000";
        String pattern = "yyyy-MM-dd'T'hh:mm:ss aa'.380+0000'";

        SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("UTC"));

        DateFormatSymbols symbols = format.getDateFormatSymbols();
        symbols = (DateFormatSymbols) symbols.clone();
        symbols.setAmPmStrings(new String[] { "a.m.", "p.m."});
        format.setDateFormatSymbols(symbols);

        Date date = format.parse(text);
        System.out.println(date);
    }
}  

I don't know whether you have to clone the DateFormatSymbols before mutating it - it's not clear, to be honest... the documentation points two ways:

DateFormatSymbols objects are cloneable. When you obtain a DateFormatSymbols object, feel free to modify the date-time formatting data. For instance, you can replace the localized date-time format pattern characters with the ones that you feel easy to remember. Or you can change the representative cities to your favorite ones.

Given that it's mentioning cloning, that suggests you should clone - but then the subsequent paragraph suggests not :(

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I know SimpleDateFormat is not threadsafe and Date should have been immutable, so I suspect working in patterns that do not assume concurrency done right is better. So I vote clone. – djechlin May 23 '13 at 22:28
  • @meewoK and `+0000` a timezone offset. Basically it's a 12-hour clock version of ISO8601 – Ian Roberts May 23 '13 at 22:34
  • @Ian Robert interesting... why the 4 digits though?? – Menelaos May 23 '13 at 22:36
  • @meewoK that's how [ISO8601](http://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC) specifies it, as an offset from UTC in hours and minutes (e.g. India is `+0530`). – Ian Roberts May 23 '13 at 22:40
  • 2
    @meewoK: Wow - putting milliseconds after an am/pm designator is *truly* bizarre. This is a very odd format... – Jon Skeet May 24 '13 at 01:33
  • DateFormatUtils are already cloned in getDateFormatSymbols and setDateFormatSymbols, so your code actually clones 3 times.. The whole code from Sun is very chaotic, but I'm already used to it. – Danubian Sailor May 24 '13 at 07:54
  • It is a bizarre format, since it breaks the golden rule of ISO 8601 that, within the same timezone, lexicographic order is consistent with chronological order. I doubt it was intentional, probably a coding error (maybe years back) in the original producer code using the wrong date formatter which has now stuck... – Ian Roberts May 24 '13 at 08:11
2

Here's a implementation using Java 8's new java.time package, so you can ditch java.util.Date and java.text.SimpleDateFormat:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.HashMap;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        String text = "2013-05-23T09:18:07 p.m..380+0000";
        Map<Long, String> map = new HashMap<>();
        map.put(0L, "a.m.");
        map.put(1L, "p.m.");
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendPattern("yyyy-MM-dd'T'hh:mm:ss ")
                .appendText(ChronoField.AMPM_OF_DAY, map)
                .appendPattern(".SSSZ").toFormatter();
        OffsetDateTime dateTime = OffsetDateTime.parse(text, formatter);
        System.out.println(dateTime);
    }
}

Running it yields:

2013-05-23T21:18:07.380Z
dhalsim2
  • 936
  • 2
  • 12
  • 35
0

Just remove the p.m. part via string manipulation. It is redundant.

Than use a simple SimpleDateFormat to do the parsing.

Something along these lines:

String whatever = "2013-05-23T09:18:07 p.m..380+0000";
        whatever = whatever.replaceAll(" p.m..", ":").replaceAll(" a.m..", ":");
        System.out.println(whatever);

        S   

        String pattern = "yyyy-MM-dd'T'hh:mm:ss:SSS'Z'";

        SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
        Date date;
        try {
            date = format.parse(whatever);
             System.out.println(date);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

Update

As pointed about by IAN, I missed out that the hours are not in 24hour format. I did however get the millisecond part correct, and added the timezone part to Jon Skeet's answer to get:

String text = "2013-05-23T09:18:07 p.m..380+0000";  
String pattern = "yyyy-MM-dd'T'hh:mm:ss aa'.'SSSZ";
SimpleDateFormat format = new SimpleDateFormat(pattern);

DateFormatSymbols symbols = format.getDateFormatSymbols();
symbols = (DateFormatSymbols) symbols.clone();
symbols.setAmPmStrings(new String[] { "a.m.", "p.m."});
format.setDateFormatSymbols(symbols);

Date date = format.parse(text);
System.out.println(date);
Menelaos
  • 23,508
  • 18
  • 90
  • 155
  • But if you treat "09" as a 24-hour clock time when the original string said p.m. you're going to get the wrong result. – Ian Roberts May 23 '13 at 22:31
0

Do it like this

String time="2013-05-23T09:18:07 p.m..380+0000";
        int index1=time.indexOf("");
        int index2 = time.indexOf(".."); // or you can give p.m. as argument if you want it to stop before pm

        String result = time.substring(index1,index2);
        System.out.print(result);

This has the following result

2013-05-23T09:18:07 p.m 

I hope this helps

malcolm the4
  • 347
  • 2
  • 5
  • 15
  • You just call the method for date and put the result into the String time. After that you use the substring method to get what you want – malcolm the4 May 23 '13 at 22:44