web-dev-qa-db-ja.com

Javaでタイムスパンを計算し、出力をフォーマットするにはどうすればよいですか?

2回(エポックからの秒数で)を取り、2つの違いを次のような形式で示したいと思います。

  • 2分
  • 1時間15分
  • 3時間9分
  • 1分前
  • 1時間2分前

どうすればこれを達成できますか?

42
Jeremy Logan

みんなが「YOODAA !!!」と叫ぶのでしかし、誰も具体的な例を投稿しません、ここに私の貢献があります。

Joda-Time でこれを行うこともできます。 Period を使用して、期間を表します。目的の人間表現で期間をフォーマットするには、 PeriodFormatter を使用します。これは PeriodFormatterBuilder で作成できます。

キックオフの例は次のとおりです。

DateTime myBirthDate = new DateTime(1978, 3, 26, 12, 35, 0, 0);
DateTime now = new DateTime();
Period period = new Period(myBirthDate, now);

PeriodFormatter formatter = new PeriodFormatterBuilder()
    .appendYears().appendSuffix(" year, ", " years, ")
    .appendMonths().appendSuffix(" month, ", " months, ")
    .appendWeeks().appendSuffix(" week, ", " weeks, ")
    .appendDays().appendSuffix(" day, ", " days, ")
    .appendHours().appendSuffix(" hour, ", " hours, ")
    .appendMinutes().appendSuffix(" minute, ", " minutes, ")
    .appendSeconds().appendSuffix(" second", " seconds")
    .printZeroNever()
    .toFormatter();

String elapsed = formatter.print(period);
System.out.println(elapsed + " ago");

もっと明確で簡潔ですね。

これまでに印刷

 32年、1か月、1週間、5日間、6時間、56分、24秒前

(咳、古い、咳)

68
BalusC
    Date start = new Date(1167627600000L); // JANUARY_1_2007
    Date end = new Date(1175400000000L); // APRIL_1_2007


    long diffInSeconds = (end.getTime() - start.getTime()) / 1000;

    long diff[] = new long[] { 0, 0, 0, 0 };
    /* sec */diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
    /* min */diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
    /* hours */diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
    /* days */diff[0] = (diffInSeconds = (diffInSeconds / 24));

    System.out.println(String.format(
        "%d day%s, %d hour%s, %d minute%s, %d second%s ago",
        diff[0],
        diff[0] > 1 ? "s" : "",
        diff[1],
        diff[1] > 1 ? "s" : "",
        diff[2],
        diff[2] > 1 ? "s" : "",
        diff[3],
        diff[3] > 1 ? "s" : ""));
45
Timour

うん、私が持っている死者を目覚めさせましたが、ここに@mtim投稿コードに基づいた改善された実装があります。このスレッドは検索のほぼ最上位にあるので、眠い空洞をいじっています。

    public static String getFriendlyTime(Date dateTime) {
    StringBuffer sb = new StringBuffer();
    Date current = Calendar.getInstance().getTime();
    long diffInSeconds = (current.getTime() - dateTime.getTime()) / 1000;

    /*long diff[] = new long[]{0, 0, 0, 0};
    /* sec *  diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
    /* min *  diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
    /* hours *  diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
    /* days * diff[0] = (diffInSeconds = (diffInSeconds / 24));
     */
    long sec = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);
    long min = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds;
    long hrs = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds;
    long days = (diffInSeconds = (diffInSeconds / 24)) >= 30 ? diffInSeconds % 30 : diffInSeconds;
    long months = (diffInSeconds = (diffInSeconds / 30)) >= 12 ? diffInSeconds % 12 : diffInSeconds;
    long years = (diffInSeconds = (diffInSeconds / 12));

    if (years > 0) {
        if (years == 1) {
            sb.append("a year");
        } else {
            sb.append(years + " years");
        }
        if (years <= 6 && months > 0) {
            if (months == 1) {
                sb.append(" and a month");
            } else {
                sb.append(" and " + months + " months");
            }
        }
    } else if (months > 0) {
        if (months == 1) {
            sb.append("a month");
        } else {
            sb.append(months + " months");
        }
        if (months <= 6 && days > 0) {
            if (days == 1) {
                sb.append(" and a day");
            } else {
                sb.append(" and " + days + " days");
            }
        }
    } else if (days > 0) {
        if (days == 1) {
            sb.append("a day");
        } else {
            sb.append(days + " days");
        }
        if (days <= 3 && hrs > 0) {
            if (hrs == 1) {
                sb.append(" and an hour");
            } else {
                sb.append(" and " + hrs + " hours");
            }
        }
    } else if (hrs > 0) {
        if (hrs == 1) {
            sb.append("an hour");
        } else {
            sb.append(hrs + " hours");
        }
        if (min > 1) {
            sb.append(" and " + min + " minutes");
        }
    } else if (min > 0) {
        if (min == 1) {
            sb.append("a minute");
        } else {
            sb.append(min + " minutes");
        }
        if (sec > 1) {
            sb.append(" and " + sec + " seconds");
        }
    } else {
        if (sec <= 1) {
            sb.append("about a second");
        } else {
            sb.append("about " + sec + " seconds");
        }
    }

    sb.append(" ago");


    /*String result = new String(String.format(
    "%d day%s, %d hour%s, %d minute%s, %d second%s ago",
    diff[0],
    diff[0] > 1 ? "s" : "",
    diff[1],
    diff[1] > 1 ? "s" : "",
    diff[2],
    diff[2] > 1 ? "s" : "",
    diff[3],
    diff[3] > 1 ? "s" : ""));*/
    return sb.toString();
}

明らかに改善できます。基本的には、タイムスパンをより友好的にしようとしますが、いくつかの制限があります。つまり、経過した時間(パラメータ)が将来であり、日、時間、秒のみ(月および年ではなく他の誰かができるように処理;-)。

サンプル出力は次のとおりです。

  • 少し前
  • 8分34秒前
  • 1時間4分前
  • 一日前
  • 29日前
  • 1年3ヶ月前

、乾杯:D

編集:今月と年をサポートしています:P

18

HumanTime をご覧になることをお勧めします

12
Peter Lindholm

レガシーの日時クラスを避ける

他の回答は正しいかもしれませんが、古くなっています。 Javaの厄介な古い日時クラスは、Java.timeクラスに取って代わられたレガシーです。

同様に、 Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。

Java.timeを使用する

Instant

2回(エポックからの秒数で)

Java.timeでは、UTCのタイムライン上の瞬間をInstantとして表します。あなたのエポックは、UTCで1970年の最初の瞬間であるJava.timeのエポックと同じであると仮定します(1970-01-01T00:00:00Z)。 Instantの解像度はナノ秒であることに注意してください。質問にあるように、コンビニエンスファクトリメソッドは、秒全体からInstantを構築します。

Instant start = Instant.ofEpochSecond( … );
Instant stop = Instant.ofEpochSecond( … );

ここでは、現在の瞬間と数分後に使用します。

Instant start = Instant.now() ;
Instant stop = start.plusSeconds( TimeUnit.MINUTES.toSeconds( 7L ) ) ;  // Seven minutes as a number of seconds.

Duration

Java.timeでは、タイムラインに関連付けられていない期間は2つの方法で表されます。年月日には、Periodがあります。時間分秒の場合、Durationがあります。

Duration duration = Duration.between( start , stop );

半開き

経過時間は、ハーフオープンアプローチで計算されます。このアプローチでは、開始はclusiveで、終了はexclusiveです。このアプローチは、一般的に日時作業で使用されます。このアプローチをコードベース全体で一貫して使用すると、あいまいさによるエラーや誤解を排除し、プログラミングの認知的負荷を軽減できると考えています。

ISO 8601

ISO 8601 標準は、日時値をテキストとして表すための多くの実用的なフォーマットを定義しています。これらの形式は、あいまいさを避け、機械で簡単に解析でき、文化を超えて人間が直感的に読み取れるように設計されています。

Java.timeクラスは、文字列を解析および生成するときにデフォルトでこれらの形式を使用します。

タイムラインに関連付けられていない期間、 標準はフォーマットを定義します of PnYnMnDTnHnMnSここで、Pは開始を示し、Tは年を区切ります-任意の時間、分、秒からの月日。したがって、1時間半はPT1H30M

7分を使用したサンプルコードでは:

String outputStandard = duration.toString();

PT7M

上記の例を参照してください IdeOne.comでライブ実行中のコード

できる限りこれらの形式を使用すること、日時データの交換またはシリアル化を行うことをお勧めしますが、必要に応じてユーザーインターフェイスで使用することも検討してください。

時刻の形式は完全にあいまいであるため、時刻形式(例:時半の場合は01:30)を使用するneverをお勧めします。

パーツを取得して文字列を作成する

質問で見られるように期間を綴る必要がある場合は、テキストを自分で作成する必要があります。

  • Period の場合、 getYearsgetMonths、およびgetDaysを呼び出して各部分を取得します。
  • 奇妙なことに、Durationクラスには Java 8 ではそのようなゲッターがありませんでしたが、 Java 9 以降では toDaysParttoHoursParttoMinutesParttoSecondsPart、およびtoNanosPart

簡単で基本的なコード例をいくつか紹介します。

int days = duration.toDaysPart() ;
int hours = duration.toHoursPart() ;
int minutes = duration.toMinutesPart() ;
int seconds = duration.toSecondsPart() ;
int nanos = duration.toNanosPart() ;

StringBuilder sb = new StringBuilder( 100 );

if( days != 0 ) { 
    sb.append( days + " days" ) ;
};

if( hours != 0 ) { 
    sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ;  // Append comma if any existing text.
    sb.append( hours + " hours" ) ;
};

if( minutes != 0 ) { 
    sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ;  // Append comma if any existing text.
    sb.append( minutes + " minutes" ) ;
};

if( seconds != 0 ) { 
    sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ;  // Append comma if any existing text.
    sb.append( seconds + " seconds" ) ;
};

if( nanos != 0 ) { 
    sb.append( ( sb.length = 0 ) ? ( "" ) : ( ", " ) ) ;  // Append comma if any existing text.
    sb.append( nanos + " nanos" ) ;
};

String output = sb.toString();

あるいは、 DateTimeFormatterBuilder を使用して、 The Balus Cによる回答 のJoda-Timeで示されている方法で、スリッカーコードを記述することもできます。


Java.timeについて

Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、面倒な古い legacy のような日時クラスに取って代わります- Java.util.DateCalendar 、& SimpleDateFormat

Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracle Tutorial を参照してください。また、Stack Overflowで多くの例と説明を検索してください。指定は JSR 31 です。

Java.timeクラスはどこで入手できますか?

ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 IntervalYearWeekYearQuarter などの便利なクラスがあります。 、andfz more

9
Basil Bourque

私はJavaの専門家ではありませんが、t1-t2 = t3(秒単位)を実行し、それを60で割ると分になり、さらに60で割ると秒になります。次に、必要な分割数を把握するだけです。

それが役に立てば幸い。

1
TuxMeister

タイムスパンが夏時間(夏時間)の境界を超える場合、日数を報告しますか?

たとえば、翌日の23:00から23:00は常に1日ですが、夏時間の移行を通過するかどうかによって、23時間、24時間、または25時間になる場合があります。

あなたがそれを気にするなら、あなたの選択にそれを考慮に入れてください。

1
Adrian Pronk

日付の書式設定と時間前に再生するコード。

SimpleDateFormat curFormater = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss"); 
    try {
        Date dateObj = curFormater.parse(pubDate);

        SimpleDateFormat postFormater = new SimpleDateFormat("MMMM dd, yyyy ss:mm:hh");              
        String newDateStr = postFormater.format(dateObj); 
        Log.v("THE NEW DATE IS",newDateStr);            
        long pubdateinmilis = dateObj.getTime();            
        pubDate = (String) DateUtils.getRelativeTimeSpanString(pubdateinmilis, System.currentTimeMillis(),DateUtils.HOUR_IN_MILLIS,DateUtils.FORMAT_ABBREV_RELATIVE);

    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
1
OWADVL

この質問は古く、すでに答えがありますが、より良い解決策があります。日付ユーティリティからrelativeSpanを使用する

                dateHere.setText(DateUtils.getRelativeTimeSpanString(timeInMillis,
                        System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS));

それは引数を取ります:long/int時間、現在の時間とあなたがそれを望む方法、_month、minute、secondなど

0
Lucem

私はいつも Joda Time で始めます。 Javaで日付と時刻を操作することは常に「楽しい」ですが、Joda Timeは負担を取り除きます。

彼らはあなたが探しているものの半分を行う間隔と期間のクラスを持っています。ただし、読み取り可能な形式で出力する機能があるかどうかはわかりません。私は探し続けます。

HTH

0
mr_urf

Calendar クラスは、ほとんどの日付関連の数学を処理できます。 compareTo の結果を取得し、自分でフォーマットを出力する必要があります。あなたが探しているものを正確に実行する標準ライブラリはありませんが、サードパーティのライブラリがあるかもしれません。

0
Ben S

最近、所要時間を印刷する基本的な方法が必要な場合と同じ要件がありました。サードパーティのライブラリを使用するオプションがありませんでした。そのため、@ mtimのアイデアをさらに改良しました。

public static void main(String[] args) throws IOException, ParseException {
        String since = "2017-02-24T04:44:05.601Z";
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        TimeZone utc = TimeZone.getTimeZone("UTC");
        dateFormat.setTimeZone(utc);

        Date sinceDate = dateFormat.parse(since);
        Date now = new Date();
        long durationInSeconds  = TimeUnit.MILLISECONDS.toSeconds(now.getTime() - sinceDate.getTime());

        long SECONDS_IN_A_MINUTE = 60;
        long MINUTES_IN_AN_HOUR = 60;
        long HOURS_IN_A_DAY = 24;
        long DAYS_IN_A_MONTH = 30;
        long MONTHS_IN_A_YEAR = 12;

        long sec = (durationInSeconds >= SECONDS_IN_A_MINUTE) ? durationInSeconds % SECONDS_IN_A_MINUTE : durationInSeconds;
        long min = (durationInSeconds /= SECONDS_IN_A_MINUTE) >= MINUTES_IN_AN_HOUR ? durationInSeconds%MINUTES_IN_AN_HOUR : durationInSeconds;
        long hrs = (durationInSeconds /= MINUTES_IN_AN_HOUR) >= HOURS_IN_A_DAY ? durationInSeconds % HOURS_IN_A_DAY : durationInSeconds;
        long days = (durationInSeconds /= HOURS_IN_A_DAY) >= DAYS_IN_A_MONTH ? durationInSeconds % DAYS_IN_A_MONTH : durationInSeconds;
        long months = (durationInSeconds /=DAYS_IN_A_MONTH) >= MONTHS_IN_A_YEAR ? durationInSeconds % MONTHS_IN_A_YEAR : durationInSeconds;
        long years = (durationInSeconds /= MONTHS_IN_A_YEAR);

        String duration = getDuration(sec,min,hrs,days,months,years);
        System.out.println(duration);
    }
    private static String getDuration(long secs, long mins, long hrs, long days, long months, long years) {
        StringBuffer sb = new StringBuffer();
        String EMPTY_STRING = "";
        sb.append(years > 0 ? years + (years > 1 ? " years " : " year "): EMPTY_STRING);
        sb.append(months > 0 ? months + (months > 1 ? " months " : " month "): EMPTY_STRING);
        sb.append(days > 0 ? days + (days > 1 ? " days " : " day "): EMPTY_STRING);
        sb.append(hrs > 0 ? hrs + (hrs > 1 ? " hours " : " hour "): EMPTY_STRING);
        sb.append(mins > 0 ? mins + (mins > 1 ? " mins " : " min "): EMPTY_STRING);
        sb.append(secs > 0 ? secs + (secs > 1 ? " secs " : " secs "): EMPTY_STRING);
        sb.append("ago");
        return sb.toString();
    }

出力は、単語で印刷されたタイムギャップ(期間)です。 1 day 2 hours 51 mins 41 secs ago

0
i_am_zero

OK、APIを少し読んだ後、次のことができるようです:-

  1. 開始時間と終了時間を表すいくつかのReadableInstantsを作成します。
  2. Hours.hoursBetweenを使用して時間数を取得します
  3. minutes.minutesBetweenを使用して分数を取得します
  4. 分にmod 60を使用して残りの分を取得します
  5. 出来上がり!

HTH

0
mr_urf

「Abduliam Rehmanius」のソリューションはかなりいいようです。または、上記のライブラリを使用するか、新しいシンプルなものを作成することができます。JSソリューションを参照してください: http://www.datejs.com/ 。 Java lang :-)に変換するのは難しくありません

私のリンクがあなたの役に立つことを願っています!

0
Tam Vo

フォーマット期間はJava ETLまたはDBプルで頻繁にポップアップします。次のコードスニペットは、操作のパルスを取得する方法です。

    SimpleDateFormat ymdhms=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    DecimalFormat formatter = new DecimalFormat("#,###"); /* ("#,###.00"); gives you the decimal fractions */
    int counter=0;
    Date beginTime0=new Date();
    while (<some end condition>) {

        <some time consuming operation>

        /*// uncomment this section durring initial exploration of the time consumer
        if(counter>100000){
            System.out.println("debug exiting due to counter="+counter);
            System.exit(0);
        }
        */

        if(0==counter%1000){
            Date now = new Date();
            long diffInSeconds = (now.getTime() - beginTime0.getTime()) / 1000;
            long diff[] = new long[] { 0, 0, 0, 0 };
            diff[3] = (diffInSeconds >= 60 ? diffInSeconds % 60 : diffInSeconds);                        /* sec   */ 
            diff[2] = (diffInSeconds = (diffInSeconds / 60)) >= 60 ? diffInSeconds % 60 : diffInSeconds; /* min   */ 
            diff[1] = (diffInSeconds = (diffInSeconds / 60)) >= 24 ? diffInSeconds % 24 : diffInSeconds; /* hours */ 
            diff[0] = (diffInSeconds = (diffInSeconds / 24));                                            /* days  */ 
            String delta = String.format(
                "%s%s%s%s"
                ,(diff[0]>0?String.format("%d day%s "    ,diff[0],(diff[0]!=1?"s":"")):"")
                ,(diff[1]>0?String.format("%2d hour%s "  ,diff[1],(diff[1]!=1?"s":" ")):"")
                ,(diff[2]>0?String.format("%2d minute%s ",diff[2],(diff[2]!=1?"s":" ")):"")
                ,           String.format("%2d second%s ",diff[3],(diff[3]!=1?"s":" "))
            );
            System.out.println(String.format(
                "%12s %s delta= %s"
                ,formatter.format(counter)
                ,ymdhms.format(new Date())
                ,delta
                )
            );
        }
        counter++;
    }
0
teserecter

PrettyTimeのようなものを探していると思います
PrettyTimeは、オープンソースの時刻フォーマットライブラリです。完全にカスタマイズ可能で、人間が読める相対的なタイムスタンプを作成し、Digg、Twitter、Facebookで見られるようなものです。30以上で利用可能です言語!
リンク: https://github.com/ocpsoft/prettytime

Android too

例えば

System.out.println(p.format(new Date(System.currentTimeMillis() + 1000*60*10)));
        //prints: "10 minutes from now"
0
Habel Philip