Converting ISO 8601-compliant String to java.util.Date
Преобразование строки, соответствующей стандарту ISO 8601, в java.util.Date
Я пытаюсь преобразовать строку в формате ISO 8601 в java.util.Date.
Я обнаружил, что шаблон yyyy-MM-dd'T'HH:mm:ssZ соответствует стандарту ISO8601, если используется с языковым стандартом (сравните образец).
Однако, используя java.text.SimpleDateFormat, я не могу преобразовать строку в правильном формате 2010-01-01T12:00:00+01:00. Сначала я должен преобразовать ее в 2010-01-01T12:00:00+0100, без двоеточия.
К сожалению, форматы часовых поясов, доступные в SimpleDateFormat (Java 6 и более ранних версий), не соответствуют стандарту ISO 8601. SimpleDateFormat понимает строки часового пояса, такие как "GMT + 01:00" или "+ 0100", последнее в соответствии с RFC # 822.
Даже если Java 7 добавила поддержку дескрипторов часовых поясов в соответствии с ISO 8601, SimpleDateFormat по-прежнему не может должным образом проанализировать полную строку даты, поскольку она не поддерживает необязательные части.
Переформатирование входной строки с помощью регулярного выражения, безусловно, является одной из возможностей, но правила замены не так просты, как в вашем вопросе:
Некоторые часовые пояса отключены не на все часы UTC, поэтому строка не обязательно заканчивается на ":00".
ISO8601 позволяет включать в часовой пояс только количество часов, поэтому "+ 01" эквивалентно "+01:00"
ISO8601 позволяет использовать "Z" для обозначения UTC вместо "+00:00".
Возможно, более простым решением является использование преобразователя типов данных в JAXB, поскольку JAXB должен уметь анализировать строку даты ISO8601 в соответствии со спецификацией XML-схемы. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z") даст вам Calendar объект, и вы можете просто использовать getTime() для него, если вам нужен Date объект.
Вероятно, вы могли бы также использовать Joda-Time, но я не знаю, почему вы должны беспокоиться об этом (обновление 2022; возможно, потому, что весь javax.xml.bind раздел отсутствует в javax.xml пакете Android).
Хорошо, на этот вопрос уже дан ответ, но я все равно оставлю свой ответ. Возможно, кому-то это поможет.
Я искал решение для Android (API 7).
О Joda не могло быть и речи - она огромна и страдает от медленной инициализации. Это также казалось серьезным излишеством для этой конкретной цели.
Ответы, связанные с javax.xml, не будут работать в Android API 7.
В итоге был реализован этот простой класс. Он охватывает только наиболее распространенную форму строк ISO 8601, но в некоторых случаях этого должно быть достаточно (когда вы совершенно уверены, что входные данные будут в этом формате).
/** * Helper class for handling a most common subset of ISO 8601 strings * (in the following format: "2008-03-01T13:00:00+01:00"). It supports * parsing the "Z" timezone, but many other less-used features are * missing. */ publicfinalclassISO8601 { /** Transform Calendar to ISO 8601 string. */ publicstatic String fromCalendar(final Calendar calendar) { Datedate= calendar.getTime(); Stringformatted=newSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") .format(date); return formatted.substring(0, 22) + ":" + formatted.substring(22); }
/** Get current date and time formatted as ISO 8601 string. */ publicstatic String now() { return fromCalendar(GregorianCalendar.getInstance()); }
/** Transform ISO 8601 string to Calendar. */ publicstatic Calendar toCalendar(final String iso8601string) throws ParseException { Calendarcalendar= GregorianCalendar.getInstance(); Strings= iso8601string.replace("Z", "+00:00"); try { s = s.substring(0, 22) + s.substring(23); // to get rid of the ":" } catch (IndexOutOfBoundsException e) { thrownewParseException("Invalid length", 0); } Datedate=newSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s); calendar.setTime(date); return calendar; } }
Примечание по производительности: Я каждый раз создаю новый SimpleDateFormat, чтобы избежать ошибки в Android 2.1. Если вы так же удивлены, как и я, посмотрите на эту загадку. Для других движков Java вы можете кэшировать экземпляр в частном статическом поле (используя ThreadLocal для потокобезопасности).
Ответ 4
java.time
java.time API (встроенный в Java 8 и более поздние версии) немного упрощает эту задачу.
Если вы знаете, что входные данные указаны в UTC, например, в Z (для Zulu) в конце, Instant класс может выполнить синтаксический анализ.
Если ваши входные данные могут представлять собой другие значения с смещением от UTC, а не с UTC, обозначенные Z (Zulu) в конце, используйте OffsetDateTime класс для синтаксического анализа.