Получение времени из строки

Возможно ли реализовать такую штуку: есть строка. В ней может быть написано 1year/1month/1week/1day/1hour/1minute/1second или несколько вместе. Например: 1week5day. И мы должны получить время в миллисекундах, которое занимает данный промежуток времени. Если возможно, то подтолкните, а то я сам не догоняю.


Ответы (2 шт):

Автор решения: gil9red

Сложную задачу нужно делить по частям:

  1. Парсинг текста. Для получения количества и единицы измерения времени (year, month, ...). Мне кажется, в вашем случае, самое удобное это через регулярные выражения.
  2. Сопоставление единицы измерения времени к количеству миллисекунд
  3. Суммирование миллисекунд

Покажу примеры шагов, но с неполной реализацией

  1. Тут в регулярном выражении я указываю, что ожидается число и единица измерения (остальные сами добавите, разделяя их вертикальной чертой)

    String text = "1week5day10hour";
    
    Matcher m = Pattern.compile("(\\d+)(week|day|hour)").matcher(text);
    while (m.find()) {
        int number = Integer.parseInt(m.group(1));
        String kind = m.group(2);
        System.out.println(number + " " + kind);
    }
    

    Результатом будет:

    1 week
    5 day
    10 hour
    
  2. Можно это сделать через if/switch, но я сделаю через словарь. Кст, в этом случае удобно сделать регулярное выражение от ключей словаря, чтобы не повторяться в словаре и в шаблоне регулярки.

    Map<String, Long> kindByMs = new HashMap<String, Long>() {{
        put("week", 604800000L);
        put("day", 86400000L);
        put("hour", 3600000L);
    }};
    
    Matcher m = <регулярка>
    while (m.find()) {
        int number = Integer.parseInt(m.group(1));
        String kind = m.group(2);
        long ms = kindByMs.get(kind);
        System.out.println(kind + " = " + ms + " ms");
    }
    

    Результат:

    week = 604800000 ms
    day = 86400000 ms
    hour = 3600000 ms
    
  3. Для сложения используйте переменную с типом long, но, возможно, лучше через большие числа, т.е. через BigInteger

→ Ссылка
Автор решения: Alexey R.

Можно еще при помощи сканера, стримов и таймюнитов (последнее для упрощения конвертации):

public static void main(String[] args) {
    Scanner scanner = new Scanner("1hour10minute");
    System.out.println(
            scanner
            .findAll("(\\d+)(second|minute|hour|day|week|month|year)")
            .map(matchResult ->
                Long
                        .valueOf(TimeUnit.valueOf((matchResult.group(2) + "s")
                                .toUpperCase())
                                .toMillis(Integer.valueOf(matchResult.group(1))))
            ).reduce((aLong, aLong2) -> aLong + aLong2).orElse(0L)
    );
}

Что тут происходит?

  • findAll разбивает строку на токены "число-период" и приводит всё это к стриму.
  • map приводит каждый элемент стрима к миллисекундам. Для этого он использует стандартную сущность TimeUnit. Т.к. таймюниты из задачи отличаются от нужного представления только единственным числом, мы просто добавляем s в конец.
  • reduce схлопывает наш стрим в число через сложение отдельных элементов.
→ Ссылка