Преобразование строки, соответствующей ISO 8601, в java.util.Date

У вас тяжелая работа. Теперь вы можете просто использовать Map для подсчета вхождений:

Map<String, Integer> occurrences = new HashMap<String, Integer>();

for ( String word : splitWords ) {
   Integer oldCount = occurrences.get(word);
   if ( oldCount == null ) {
      oldCount = 0;
   }
   occurrences.put(word, oldCount + 1);
}

Используя map.get(word), вы будете много раз говорить о слове. Вы можете построить новый список, итерации через map.keySet():

for ( String word : occurrences.keySet() ) {
  //do something with word
}

Обратите внимание, что порядок того, что вы получаете из keySet, произволен. Если вам нужны слова для сортировки, когда они впервые появляются в вашей строке ввода, вы должны использовать вместо этого LinkedHashMap.

608
задан wittich 12 July 2018 в 08:31
поделиться

3 ответа

К сожалению, форматы часовых поясов, доступные для 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 (), если вам нужен Дата объекта.

Вы, вероятно, могли бы также использовать Joda-Time , но я не знаю, зачем вам это нужно.

451
ответ дан 22 November 2019 в 21:53
поделиться

Вот является Kotlin базирующимся подходом с помощью Java 7. Можно передать пользовательские шаблоны или просто использовать шаблон ISO8601 по умолчанию. Вероятно, необходимо обработать ошибки анализа все же.

object DateUtil {

    private const val ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSX"

    fun convertDateToTimestamp(date: Date, pattern: String = ISO_8601_PATTERN): String {
        val df = SimpleDateFormat(pattern, Locale.getDefault()).apply {
            timeZone = TimeZone.getTimeZone("UTC")
        }
        return df.format(date)
    }

    fun convertTimestampToDate(timestamp: String, pattern: String = ISO_8601_PATTERN): Date {
        val formatter = SimpleDateFormat(pattern, Locale.getDefault()).apply {
            timeZone = TimeZone.getTimeZone("UTC")
        }
        return formatter.parse(timestamp) ?: Date(0)
    }
}
0
ответ дан 22 November 2019 в 21:53
поделиться

Немного теста, который показывает, как проанализировать дату в ISO8601 и что LocalDateTime не обрабатывает DSTs.

 @Test
    public void shouldHandleDaylightSavingTimes() throws ParseException {

        //ISO8601 UTC date format
        SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

        // 1 hour of difference between 2 dates in UTC happening at the Daylight Saving Time
        Date d1 = utcFormat.parse("2019-10-27T00:30:00.000Z");
        Date d2 = utcFormat.parse("2019-10-27T01:30:00.000Z");

        //Date 2 is before date 2
        Assert.assertTrue(d1.getTime() < d2.getTime());
        // And there is 1 hour difference between the 2 dates
        Assert.assertEquals(1000*60*60, d2.getTime() - d1.getTime());

        //Print the dates in local time
        SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm z Z", Locale.forLanguageTag("fr_CH"));
        localFormat.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));

        //Both dates are at 02h30 local time (because of DST), but one is CEST +0200 and the other CET +0100 (clock goes backwards)
        Assert.assertEquals("2019-10-27 02:30 CEST +0200", localFormat.format(d1));
        Assert.assertEquals("2019-10-27 02:30 CET +0100", localFormat.format(d2));

        //Small test that shows that LocalDateTime does not handle DST (and should not be used for storing timeseries data)
        LocalDateTime ld1 = LocalDateTime.ofInstant(d1.toInstant(), ZoneId.of("Europe/Zurich"));
        LocalDateTime ld2 = LocalDateTime.ofInstant(d2.toInstant(), ZoneId.of("Europe/Zurich"));

        //Note that a localdatetime does not handle DST, therefore the 2 dates are the same
        Assert.assertEquals(ld1, ld2);

        //They both have the following local values
        Assert.assertEquals(2019, ld1.getYear());
        Assert.assertEquals(27, ld1.getDayOfMonth());
        Assert.assertEquals(10, ld1.getMonthValue());
        Assert.assertEquals(2, ld1.getHour());
        Assert.assertEquals(30, ld1.getMinute());
        Assert.assertEquals(0, ld1.getSecond());

    }
0
ответ дан 22 November 2019 в 21:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: