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

随声附和 提交于 2019-11-26 22:06:27

问题


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!


回答1:


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);



回答2:


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.



来源:https://stackoverflow.com/questions/57174218/how-to-parse-a-utc-offset-dateformat-string-into-the-resulting-date-separated-by

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!