web-dev-qa-db-ja.com

「1時間30分」のような時間文字列の解析

Java "30min"、 "2h 15min"、 "2d 15h 30min"などの時間文字列をミリ秒(またはある種のDurationオブジェクト)として解析できるライブラリを知っている人は誰でも知っています。時間はこのようなことをしますか?

(私はそのような解析を行う維持するための醜い長い方法があり、それを取り除きたい/より良い仕事をする何かで置き換えたいです。)

36
Jonik

あなたはおそらくあなた自身のフォーマットのためにこれを少し微調整する必要があるでしょうが、これらの線に沿って何かを試してください:

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

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

より柔軟にする必要がある場合は、appendSuffixパラメータを取るvariantsがあることに注意してください。

Update:Joda Timeが追加された Period.toStandardDuration() 、そしてそこから getStandardSeconds() 経過時間を秒単位でlongとして取得します。

これらのメソッドのない古いバージョンを使用している場合でも、1日24時間、60分/時間などの標準を想定して、自分でタイムスタンプを計算できます(この場合、DateTimeConstantsクラスを使用して、マジックナンバーの必要性を回避します。

34
Brad Mace

継続時間の解析が Java 8 に含まれるようになりました。標準 ISO 8601 フォーマットを Duration.parse

Duration d = Duration.parse("PT1H30M")

この期間を変換する をミリ秒単位の全長に変換できます。 Durationの分解能はナノ秒であるため、 nanoseconds から milliseconds へのデータ損失が発生する可能性があることに注意してください。

long milliseconds = d.toMillis();

形式は、あなたが説明したものとは少し異なりますが、簡単に変換できます。

26
Andrejs

日、時間、分をオプションにしたかったのですが、これでうまくいくようです。 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);

}
14
Victor

参考までに、これを1時間以上の期間について記述しただけで、Java.time.*、理解し、必要に応じてカスタマイズするのはかなり簡単です。

このバージョンは次のような文字列で動作します。 3d12h2y9m10dなど.

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

1
bekce

いいえ、Jodaはデフォルトで、期間、インスタント間隔、およびオブジェクトのみを取得します。後者の場合、日付やSOAP ISO形式など)を受け入れます。Durationクラス用に独自のコンバータをここに追加できます。これにより、醜いコードをすべて隠すことができます。

0
MJB