Разбор строк времени типа "1 ч 30 мин" - PullRequest
35 голосов
/ 19 июня 2011

Любой знает библиотеку Java, которая может анализировать временные строки, такие как «30 минут» или «2 часа 15 минут» или «2 дня 15 часов 30 минут», как миллисекунды (или некоторый объект Duration).Может ли Joda-Time сделать что-то подобное?

(у меня есть ужасный длинный метод поддержки, который выполняет такой анализ и хотел бы избавиться от него / заменить его чем-то, что делает лучше).

Ответы [ 5 ]

32 голосов
/ 19 июня 2011

Возможно, вам придется немного подправить это для своего собственного формата, но попробуйте что-то вроде этого:

PeriodFormatter formatter = new PeriodFormatterBuilder()
    .appendDays().appendSuffix("d ")
    .appendHours().appendSuffix("h ")
    .appendMinutes().appendSuffix("min")
    .toFormatter();

Period p = formatter.parsePeriod("2d 5h 30min");

Обратите внимание, что appendSuffix принимает параметр variants, если вам нужно сделать его более гибким.

Обновление : с тех пор Joda Time добавила Period.toStandardDuration(), и оттуда вы можете использовать getStandardSeconds(), чтобы получить истекшее время в секундах как long.

Если вы используете старую версию без этих методов, вы все равно можете самостоятельно рассчитать временную метку, приняв стандартное значение 24 часа в день, 60 минут в час и т. Д. (В этом случае воспользуйтесь константами в DateTimeConstants класс, чтобы избежать необходимости в магических числах.)

25 голосов
/ 17 марта 2014

Разбор продолжительности теперь включен в Java 8 . Используйте стандартный ISO 8601 формат с Duration.parse.

Duration d = Duration.parse("PT1H30M")

Вы можете преобразовать эту продолжительность в общую длину в миллисекундах. Помните, что Duration имеет разрешение наносекунд, поэтому потеря данных может составить от наносекунд до миллисекунд .

long milliseconds = d.toMillis();

Формат немного отличается от того, что вы описываете, но может быть легко переведен с одного на другой.

14 голосов
/ 07 февраля 2014

Я хотел сделать день, час и минуту необязательными, и, похоже, это работает. Обратите внимание, что вызовы appendSuffix () не имеют пробела после символа.

Использование Joda 2.3.

PeriodParser parser = new PeriodFormatterBuilder()
        .appendDays().appendSuffix("d").appendSeparatorIfFieldsAfter(" ")
        .appendHours().appendSuffix("h").appendSeparatorIfFieldsAfter(" ")
        .appendMinutes().appendSuffix("min")
        .toParser();

Приведенный выше код проходит эти тесты.

@Test
public void testConvert() {
    DurationConverter c = new DurationConverter();

    Duration d;
    Duration expected;

    d = c.convert("1d");
    expected = Duration.ZERO
            .withDurationAdded(Duration.standardDays(1),1);
    assertEquals(d, expected);

    d = c.convert("1d 1h 1min");
    expected = Duration.ZERO
            .withDurationAdded(Duration.standardDays(1),1)
            .withDurationAdded(Duration.standardHours(1),1)
            .withDurationAdded(Duration.standardMinutes(1),1);
    assertEquals(d, expected);


    d = c.convert("1h 1min");
    expected = Duration.ZERO
            .withDurationAdded(Duration.standardHours(1),1)
            .withDurationAdded(Duration.standardMinutes(1),1);
    assertEquals(d, expected);

    d = c.convert("1h");
    expected = Duration.ZERO
            .withDurationAdded(Duration.standardHours(1),1);
    assertEquals(d, expected);

    d = c.convert("1min");
    expected = Duration.ZERO
            .withDurationAdded(Duration.standardMinutes(1),1);
    assertEquals(d, expected);

}
0 голосов
/ 31 мая 2019

FYI, только что написал это для часа + периодов, использует только java.time.*, довольно просто понять и настроить для любых нужд;

Эта версия работает с такими строками, как;3d12h, 2y, 9m10d и т. Д.

import java.time.Duration;
import java.time.Instant;
import java.time.Period;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Locale;
private static final Pattern periodPattern = Pattern.compile("([0-9]+)([hdwmy])");

public static Long parsePeriod(String period){
    if(period == null) return null;
    period = period.toLowerCase(Locale.ENGLISH);
    Matcher matcher = periodPattern.matcher(period);
    Instant instant=Instant.EPOCH;
    while(matcher.find()){
        int num = Integer.parseInt(matcher.group(1));
        String typ = matcher.group(2);
        switch (typ) {
            case "h":
                instant=instant.plus(Duration.ofHours(num));
                break;
            case "d":
                instant=instant.plus(Duration.ofDays(num));
                break;
            case "w":
                instant=instant.plus(Period.ofWeeks(num));
                break;
            case "m":
                instant=instant.plus(Period.ofMonths(num));
                break;
            case "y":
                instant=instant.plus(Period.ofYears(num));
                break;
        }
    }
    return instant.toEpochMilli();
}

0 голосов
/ 19 июня 2011

Нет, Joda по умолчанию принимает только Длительность, Мгновенные интервалы и объекты.Для последнего он принимает такие вещи, как Dates или SOAP ISO формат.Здесь вы можете добавить свой собственный конвертер для класса Duration, и, по общему признанию, он будет скрывать весь ваш уродливый код.

...