109


38

Javaで「時間前」を計算する方法は?

Ruby on Railsには、任意の日付を取得して、それがどのくらい前の日付であったかを出力できる機能があります。

例えば:

8 minutes ago
8 hours ago
8 days ago
8 months ago
8 years ago

Javaでこれを行う簡単な方法はありますか?

23 Answer


156


PrettyTimeライブラリをご覧ください。

使い方はとても簡単です。

import org.ocpsoft.prettytime.PrettyTime;

PrettyTime p = new PrettyTime();
System.out.println(p.format(new Date()));
// prints "moments ago"

国際化されたメッセージのロケールを渡すこともできます。

PrettyTime p = new PrettyTime(new Locale("fr"));
System.out.println(p.format(new Date()));
// prints "à l'instant"

コメントに記載されているように、Androidにはこの機能がhttp://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeTimeSpanString%28long%29 [`android.text.format.DateUtils`に組み込まれています]クラス。


68


TimeUnit列挙型を検討しましたか? この種のものにはかなり便利です

    try {
        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
        Date past = format.parse("01/10/2010");
        Date now = new Date();

        System.out.println(TimeUnit.MILLISECONDS.toMillis(now.getTime() - past.getTime()) + " milliseconds ago");
        System.out.println(TimeUnit.MILLISECONDS.toMinutes(now.getTime() - past.getTime()) + " minutes ago");
        System.out.println(TimeUnit.MILLISECONDS.toHours(now.getTime() - past.getTime()) + " hours ago");
        System.out.println(TimeUnit.MILLISECONDS.toDays(now.getTime() - past.getTime()) + " days ago");
    }
    catch (Exception j){
        j.printStackTrace();
    }


42


  public class TimeUtils {

      public final static long ONE_SECOND = 1000;
      public final static long SECONDS = 60;

      public final static long ONE_MINUTE = ONE_SECOND * 60;
      public final static long MINUTES = 60;

      public final static long ONE_HOUR = ONE_MINUTE * 60;
      public final static long HOURS = 24;

      public final static long ONE_DAY = ONE_HOUR * 24;

      private TimeUtils() {
      }

      /**
       * converts time (in milliseconds) to human-readable format
       *  " days,  hours,  minutes and (z) seconds"
       */
      public static String millisToLongDHMS(long duration) {
        StringBuffer res = new StringBuffer();
        long temp = 0;
        if (duration >= ONE_SECOND) {
          temp = duration / ONE_DAY;
          if (temp > 0) {
            duration -= temp * ONE_DAY;
            res.append(temp).append(" day").append(temp > 1 ? "s" : "")
               .append(duration >= ONE_MINUTE ? ", " : "");
          }

          temp = duration / ONE_HOUR;
          if (temp > 0) {
            duration -= temp * ONE_HOUR;
            res.append(temp).append(" hour").append(temp > 1 ? "s" : "")
               .append(duration >= ONE_MINUTE ? ", " : "");
          }

          temp = duration / ONE_MINUTE;
          if (temp > 0) {
            duration -= temp * ONE_MINUTE;
            res.append(temp).append(" minute").append(temp > 1 ? "s" : "");
          }

          if (!res.toString().equals("") && duration >= ONE_SECOND) {
            res.append(" and ");
          }

          temp = duration / ONE_SECOND;
          if (temp > 0) {
            res.append(temp).append(" second").append(temp > 1 ? "s" : "");
          }
          return res.toString();
        } else {
          return "0 second";
        }
      }


      public static void main(String args[]) {
        System.out.println(millisToLongDHMS(123));
        System.out.println(millisToLongDHMS((5 * ONE_SECOND) + 123));
        System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR));
        System.out.println(millisToLongDHMS(ONE_DAY + 2 * ONE_SECOND));
        System.out.println(millisToLongDHMS(ONE_DAY + ONE_HOUR + (2 * ONE_MINUTE)));
        System.out.println(millisToLongDHMS((4 * ONE_DAY) + (3 * ONE_HOUR)
            + (2 * ONE_MINUTE) + ONE_SECOND));
        System.out.println(millisToLongDHMS((5 * ONE_DAY) + (4 * ONE_HOUR)
            + ONE_MINUTE + (23 * ONE_SECOND) + 123));
        System.out.println(millisToLongDHMS(42 * ONE_DAY));
        /*
          output :
                0 second
                5 seconds
                1 day, 1 hour
                1 day and 2 seconds
                1 day, 1 hour, 2 minutes
                4 days, 3 hours, 2 minutes and 1 second
                5 days, 4 hours, 1 minute and 23 seconds
                42 days
         */
    }
}

more @http://www.rgagnon.com/javadetails/java-0585.html [ミリ秒単位で再生時間を人間が読める形式にフォーマットする]


39


RealHowToを取り、Ben Jが答えて自分のバージョンを作成します。

public class TimeAgo {
public static final List times = Arrays.asList(
        TimeUnit.DAYS.toMillis(365),
        TimeUnit.DAYS.toMillis(30),
        TimeUnit.DAYS.toMillis(1),
        TimeUnit.HOURS.toMillis(1),
        TimeUnit.MINUTES.toMillis(1),
        TimeUnit.SECONDS.toMillis(1) );
public static final List timesString = Arrays.asList("year","month","day","hour","minute","second");

public static String toDuration(long duration) {

    StringBuffer res = new StringBuffer();
    for(int i=0;i< TimeAgo.times.size(); i++) {
        Long current = TimeAgo.times.get(i);
        long temp = duration/current;
        if(temp>0) {
            res.append(temp).append(" ").append( TimeAgo.timesString.get(i) ).append(temp != 1 ? "s" : "").append(" ago");
            break;
        }
    }
    if("".equals(res.toString()))
        return "0 seconds ago";
    else
        return res.toString();
}
public static void main(String args[]) {
    System.out.println(toDuration(123));
    System.out.println(toDuration(1230));
    System.out.println(toDuration(12300));
    System.out.println(toDuration(123000));
    System.out.println(toDuration(1230000));
    System.out.println(toDuration(12300000));
    System.out.println(toDuration(123000000));
    System.out.println(toDuration(1230000000));
    System.out.println(toDuration(12300000000L));
    System.out.println(toDuration(123000000000L));
}}

以下を印刷します

0 second ago
1 second ago
12 seconds ago
2 minutes ago
20 minutes ago
3 hours ago
1 day ago
14 days ago
4 months ago
3 years ago


9


これはRealHowToの回答に基づいているため、気に入った場合は彼/彼女にも愛を与えてください。

このクリーンアップバージョンでは、興味のある時間の範囲を指定できます。

また、「」と「」の部分も少し異なります。 文字列を区切り文字で結合する場合、複雑なロジックをスキップして、最後の区切り文字を削除したほうが簡単な場合がよくあります。

import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

public class TimeUtils {

    /**
     * Converts time to a human readable format within the specified range
     *
     * @param duration the time in milliseconds to be converted
     * @param max      the highest time unit of interest
     * @param min      the lowest time unit of interest
     */
    public static String formatMillis(long duration, TimeUnit max, TimeUnit min) {
        StringBuilder res = new StringBuilder();

        TimeUnit current = max;

        while (duration > 0) {
            long temp = current.convert(duration, MILLISECONDS);

            if (temp > 0) {
                duration -= current.toMillis(temp);
                res.append(temp).append(" ").append(current.name().toLowerCase());
                if (temp < 2) res.deleteCharAt(res.length() - 1);
                res.append(", ");
            }

            if (current == min) break;

            current = TimeUnit.values()[current.ordinal() - 1];
        }

        // clean up our formatting....

        // we never got a hit, the time is lower than we care about
        if (res.lastIndexOf(", ") < 0) return "0 " + min.name().toLowerCase();

        // yank trailing  ", "
        res.deleteCharAt(res.length() - 2);

        //  convert last ", " to " and"
        int i = res.lastIndexOf(", ");
        if (i > 0) {
            res.deleteCharAt(i);
            res.insert(i, " and");
        }

        return res.toString();
    }
}

それを旋回させる小さなコード:

import static java.util.concurrent.TimeUnit.*;

public class Main {

    public static void main(String args[]) {
        long[] durations = new long[]{
            123,
            SECONDS.toMillis(5) + 123,
            DAYS.toMillis(1) + HOURS.toMillis(1),
            DAYS.toMillis(1) + SECONDS.toMillis(2),
            DAYS.toMillis(1) + HOURS.toMillis(1) + MINUTES.toMillis(2),
            DAYS.toMillis(4) + HOURS.toMillis(3) + MINUTES.toMillis(2) + SECONDS.toMillis(1),
            DAYS.toMillis(5) + HOURS.toMillis(4) + MINUTES.toMillis(1) + SECONDS.toMillis(23) + 123,
            DAYS.toMillis(42)
        };

        for (long duration : durations) {
            System.out.println(TimeUtils.formatMillis(duration, DAYS, SECONDS));
        }

        System.out.println("\nAgain in only hours and minutes\n");

        for (long duration : durations) {
            System.out.println(TimeUtils.formatMillis(duration, HOURS, MINUTES));
        }
    }

}

以下が出力されます:

0 seconds
5 seconds
1 day and 1 hour
1 day and 2 seconds
1 day, 1 hour and 2 minutes
4 days, 3 hours, 2 minutes and 1 second
5 days, 4 hours, 1 minute and 23 seconds
42 days

Again in only hours and minutes

0 minutes
0 minutes
25 hours
24 hours
25 hours and 2 minutes
99 hours and 2 minutes
124 hours and 1 minute
1008 hours

そして、誰かがそれを必要とする場合に備えて、上記のhttp://bit.ly/g08X0B [ミリ秒に戻す]のような文字列を変換するクラスがあります。 読みやすいテキストでさまざまなもののタイムアウトを指定できるようにするのに非常に便利です。


9


これを行う簡単な方法があります:

20分前の時間が欲しいとしましょう:

Long minutesAgo = new Long(20);
Date date = new Date();
Date dateIn_X_MinAgo = new Date (date.getTime() - minutesAgo*60*1000);

それでおしまい..


6


java.time

Java 8以降に組み込まれているhttp://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html[java.time]フレームワークを使用します。

LocalDateTime t1 = LocalDateTime.of(2015, 1, 1, 0, 0, 0);
LocalDateTime t2 = LocalDateTime.now();
Period period = Period.between(t1.toLocalDate(), t2.toLocalDate());
Duration duration = Duration.between(t1, t2);

System.out.println("First January 2015 is " + period.getYears() + " years ago");
System.out.println("First January 2015 is " + period.getMonths() + " months ago");
System.out.println("First January 2015 is " + period.getDays() + " days ago");
System.out.println("First January 2015 is " + duration.toHours() + " hours ago");
System.out.println("First January 2015 is " + duration.toMinutes() + " minutes ago");


5


  • _ビルトイン_ソリューションについて:*

Javaは、Java-8とその新しいパッケージ `java.time`ではなく、相対時間のフォーマットをサポートしていません。 英語のみが必要で、それ以外は何も必要ない場合は、手作りのソリューションが受け入れられる場合があります[email protected]の回答をご覧ください(ただし、インスタントデルタの現地時間への変換のタイムゾーンを考慮しないことには大きな欠点があります)単位!)。 とにかく、特に他のロケールで自家製の複雑な回避策を避けたい場合は、外部ライブラリが必要です。

後者の場合、ライブラリhttps://github.com/MenoData/Time4J[Time4J](またはAndroidのTime4A)を使用することをお勧めします。 *最高の柔軟性とほとんどのi18n-power *を提供します。 クラスhttp://time4j.net/javadoc-en/net/time4j/PrettyTime.html[net.time4j.PrettyTime]には、この目的のために `printRelativeTime …​(…​)`という7つのメソッドがあります。 時刻源としてテストクロックを使用する例:

TimeSource<?> clock = () -> PlainTimestamp.of(2015, 8, 1, 10, 24, 5).atUTC();
Moment moment = PlainTimestamp.of(2015, 8, 1, 17, 0).atUTC(); // our input
String durationInDays =
  PrettyTime.of(Locale.GERMAN).withReferenceClock(clock).printRelative(
    moment,
    Timezone.of(EUROPE.BERLIN),
    TimeUnit.DAYS); // controlling the precision
System.out.println(durationInDays); // heute (german word for today)

入力として `java.time.Instant`を使用する別の例:

String relativeTime =
  PrettyTime.of(Locale.ENGLISH)
    .printRelativeInStdTimezone(Moment.from(Instant.EPOCH));
System.out.println(relativeTime); // 45 years ago

このライブラリは、最新バージョン(v4.17)* 80言語*および一部の国固有のロケール(特にスペイン語、英語、アラビア語、フランス語)をサポートしています。 i18nデータは、主に*最新のCLDRバージョンv29 に基づいています。 このライブラリを使用する他の重要な理由は、*複数規則のサポート(他のロケールでは英語と異なる場合が多い)、省略形式スタイル(たとえば、「1秒前」)、および*アカウントのタイムゾーン*。 Time4Jは、相対時間の計算で*うるう秒*などのエキゾチックな詳細を認識しています(実際には重要ではありませんが、予想期間に関連するメッセージを形成します)。 「Java-8との互換性」は、「java.time.Instant」や「java.time.Period」などの型の変換メソッドを簡単に使用できるために存在します。

欠点はありますか? 2つだけ。

  • ライブラリは小さくありません(また、その大きなi18nデータのため 倉庫)。

  • APIはあまり知られていないので、コミュニティの知識とサポートはそうではありません 入手可能ですが、提供されているドキュメントは非常に詳細で包括的なものです。

(コンパクト)選択肢:

小規模なソリューションを探していて、それほど多くの機能を必要とせず、i18n-dataに関連する品質問題の可能性を容認する場合:

  • * ocpsoft / PrettyTime *(実際には32 `java.util.Date`のみでの作業に適した言語(まもなく34?)[email protected]の回答を参照してください)。 大きなコミュニティの背景を持つ業界標準のCLDR(Unicodeコンソーシアム)は、残念ながらi18nデータのベースではないため、データのさらなる拡張または改善にはしばらく時間がかかることがあります…​

  • Androidを使用している場合は、ヘルパークラス

  • android.text.format.DateUtils *は、組み込みのスリムな代替手段です(他のコメントと回答を参照してください。年と月のサポートがないという欠点があります)。 そして、このヘルパークラスのAPIスタイルを好む人は非常に少ないと確信しています。

  • * Joda-Time *のファンなら、そのクラスを見ることができます PeriodFormat(リリースv2.9.4の14言語のサポート、一方、Joda-Timeも確かにコンパクトではないため、ここでは完全を期すために言及します)。 相対時間はまったくサポートされていないため、このライブラリは本当の答えではありません。 少なくともリテラル「前」を追加する必要があります(そして生成されたリスト形式からすべての下位ユニットを手動で除去します-厄介です)。 Time4JやAndroid-DateUtilsとは異なり、略語や相対時間から絶対時間表現への自動切り替えの特別なサポートはありません。 PrettyTimeのように、Javaコミュニティのプライベートメンバーのi18nデータへの未確認の貢献に完全に依存しています。


5


単純な「今日」、「昨日」、または「x日前」を探している場合。

private String getDaysAgo(Date date){
    long days = (new Date().getTime() - date.getTime()) / 86400000;

    if(days == 0) return "Today";
    else if(days == 1) return "Yesterday";
    else return days + " days ago";
}


4


jquery-timeagoプラグインの単純なhttps://github.com/kevinsawicki/java-timeago[Java timeago]ポートを作成して、あなたが何をするかを説明します。を求めています。

TimeAgo time = new TimeAgo();
String minutes = time.timeAgo(System.currentTimeMillis() - (15*60*1000)); // returns "15 minutes ago"