How to parse a UTC offset dateformat string into the resulting date separated by | symbol
Asked Answered
O

2

3

I have a very peculiar question where I am trying to parse "2019-12-25T17:00:00-05:00" such that it should give me the result DEC 12 | Thursday | 5:00pm

I tried the following code by using DateTimeFormatter and LocalDate

DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssz", Locale.US);
                DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MM d | E | hh:mm a", Locale.US);
                LocalDate date = LocalDate.parse("2019-12-25T17:00:00-05:00", inputFormatter);
                String formattedDate = outputFormatter.format(date);
                contentTextView.setText(formattedDate);

but it crashes with DateTimeParseException: Text '2019-12-25T17:00:00-05:00' could not be parsed at index 19

Any idea why it's crashing and if my output will render the expected result? Thanks!

Overreach answered 24/7, 2019 at 1:56 Comment(5)
try with this one "yyyy-MM-dd'T'HH:mm'Z'" DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'", Locale.US)Peak
with that change , I get this crash : DateTimeParseException: Text '2019-12-25T17:00:00-05:00' could not be parsed at index 16Overreach
how about this "yyyy-MM-dd'T'HH:mm:ss:SSSXXX" or "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"Peak
same issue with that one : DateTimeParseException: Text '2019-12-25T17:00:00-05:00' could not be parsed at index 19Overreach
I'm wondering close votes on this question, is this really unclear?Cogitate
C
7

Your String 2019-12-25T17:00:00-05:00 represents UTC timezone with offset UTC offset, so use OffsetDateTime for parsing that string

OffsetDateTime odt = OffsetDateTime.parse("2019-12-25T17:00:00-05:00");

System.out.println(odt.format(DateTimeFormatter.ofPattern("MMM d | E | hh:mm a", Locale.US)));

If you want to set particular time zone you can use atZoneSameInstant to pass ZoneId for eaxmple

ZoneId zone = ZoneId.of("America/Chicago");
ZonedDateTime zdt = odt.atZoneSameInstant(zone);
Cogitate answered 24/7, 2019 at 2:24 Comment(7)
this seems to work, however ,I get the result : 112 25 | Wed | 05:00 PM, instead of the Month Dec , is MM the right format for this?Overreach
awesome, just one last issue, is there a way to convert AM | PM To lowercase am | pm, without using replace?Overreach
i do see only upper case here `docs.oracle.com/javase/8/docs/api/java/time/format/…, is that a problem? @AngelaHeelyCogitate
not a big issue, just curious, as the ideal format I was looking for was "DEC 12|Wed| 5:00 pm" where am /pm is in lowercase and month is in uppercase. if its not straightforward, no big dealOverreach
I don't think there is a direct way until you replace in output string #13582108 @AngelaHeelyCogitate
Good link, @Deadpool. In particular this answer.Muhammadan
any idea about this one? : #57695743Overreach
M
3

A way to format uppercase DEC and lowercase pm

I’m just giving a small supplement to @Deadpool’s good answer. A way of getting the month abbreviation in all caps like DEC and am/pm in lowercase is a DateTimeFormatterBuilder and its two-arg appendText​(TemporalField, Map<Long,String>) method.

    Locale userLocale = Locale.US;
    Map<Long, String> monthNames = new HashMap<>();
    for (Month m : Month.values()) {
        monthNames.put(Long.valueOf(m.getValue()),
                m.getDisplayName(TextStyle.SHORT, userLocale).toUpperCase(userLocale));
    }
    Map<Long, String> amPmNames = new HashMap<>(3);
    amPmNames.put(0L, "am");
    amPmNames.put(1L, "pm");
    DateTimeFormatter outputFormatter = new DateTimeFormatterBuilder()
            .appendText(ChronoField.MONTH_OF_YEAR, monthNames)
            .appendPattern(" d | E | hh:mm ")
            .appendText(ChronoField.AMPM_OF_DAY, amPmNames)
            .toFormatter(userLocale);

    OffsetDateTime odt = OffsetDateTime.parse("2019-12-25T17:00:00-05:00");
    String formattedDate = odt.format(outputFormatter);
    System.out.println(formattedDate);

Output:

DEC 25 | Wed | 05:00 pm

I have assumed that you are programming for Android under API level 26 and using ThreeTenABP, so I have tested on my desktop Java 7 with ThreeTen Backport. From Java 8 and on newer API levels and even more from Java 9 more elegant ways to populate the two maps exist.

What went wrong in your code?

The lowercase z that comes last in your format pattern string matches a time zone name. The documentation gives examples Pacific Standard Time and PST. It doesn’t match an offset like -05:00. If you ever need a format pattern letter for this, use x, X or uppercase Z (they are different and all well documented). However, as already shown in Deadpool’s answer, you need no explicit formatter and no format pattern string in this case.

Another issue in your code: The LocalDate class that you used in the question is a date without time of day. You can parse your string into a LocalDate, but the time of day and offset get lost. Hence you cannot format the LocalDate into a string that contains time of day. For that you need a class that has DateTime in its name, for example OffsetDateTime used in the two answers.

Link

DateTimeFormatter documentation spelling out all the possible format pattern letters.

Muhammadan answered 24/7, 2019 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.