如何在Java中计算“时间之前”?

147
在Ruby on Rails中,有一种功能可以将任何日期打印出多久以前的时间。例如:
8 minutes ago
8 hours ago
8 days ago
8 months ago
8 years ago

有没有在Java中简单的方法来做到这一点?


1
请参考以下链接:https://dev59.com/b3VD5IYBdhLWcg3wXamd 这是C#的代码,但我相信你可以轻松转换它。 - Brandon
33个回答

6
如果您需要简单的“今天”,“昨天”或“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
我创建了一个简单的 Java timeago 端口,基于 jquery-timeago 插件,可以实现你所要求的功能。
TimeAgo time = new TimeAgo();
String minutes = time.timeAgo(System.currentTimeMillis() - (15*60*1000)); // returns "15 minutes ago"

4

对于 Android:

只需使用以下方法:

public static String getTimeAgoFormat(long timestamp) {
    return android.text.format.DateUtils.getRelativeTimeSpanString(timestamp).toString();
}

(来自评论)


4
如果您正在为Android开发应用程序,它提供了一个名为DateUtils的实用类来满足所有这些要求。请看一下DateUtils#getRelativeTimeSpanString()的实用方法。
从以下文档中获得: CharSequence getRelativeTimeSpanString (long time, long now, long minResolution) 返回一个字符串来描述“time”相对于“now”的时间。过去的时间跨度被格式化为“42分钟前”。未来的时间跨度被格式化为“在42分钟内”。
您将把您的timestamp作为time和System.currentTimeMillis()作为now传递。 minResolution允许您指定最小的时间跨度报告。
例如,如果将其设置为MINUTE_IN_MILLIS,则三秒钟之前的时间将报告为“0分钟前”。传递0、MINUTE_IN_MILLIS、HOUR_IN_MILLIS、 DAY_IN_MILLIS、WEEK_IN_MILLIS等中的一个。

3

joda-time包含Periods的概念。您可以对Periods和DateTimes进行算术运算。

来自文档

public boolean isRentalOverdue(DateTime datetimeRented) {
  Period rentalPeriod = new  Period().withDays(2).withHours(12);
  return datetimeRented.plus(rentalPeriod).isBeforeNow();
}

3
private const val SECOND_MILLIS = 1
private const val MINUTE_MILLIS = 60 * SECOND_MILLIS
private const val HOUR_MILLIS = 60 * MINUTE_MILLIS
private const val DAY_MILLIS = 24 * HOUR_MILLIS

object TimeAgo {

fun timeAgo(time: Int): String {

    val now = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())
    if (time > now || time <= 0) {
        return "in the future"
    }

    val diff = now - time
    return when {
        diff < MINUTE_MILLIS -> "Just now"
        diff < 2 * MINUTE_MILLIS -> "a minute ago"
        diff < 60 * MINUTE_MILLIS -> "${diff / MINUTE_MILLIS} minutes ago"
        diff < 2 * HOUR_MILLIS -> "an hour ago"
        diff < 24 * HOUR_MILLIS -> "${diff / HOUR_MILLIS} hours ago"
        diff < 48 * HOUR_MILLIS -> "yesterday"
        else -> "${diff / DAY_MILLIS} days ago"
    }
}

使用 Kotlin 调用

val String = timeAgo(unixTimeStamp)

来获取 Unix 时间戳之前的时间


昨天的准确度应该基于日期因素,因为48小时可以在3天之间,而在第1天完成的任务将被标记为昨天,而实际上是第3天或(3天前)。 - MDT

3
你可以使用这个函数来计算时间的过去。
 private String timeAgo(long time_ago) {
        long cur_time = (Calendar.getInstance().getTimeInMillis()) / 1000;
        long time_elapsed = cur_time - time_ago;
        long seconds = time_elapsed;
        int minutes = Math.round(time_elapsed / 60);
        int hours = Math.round(time_elapsed / 3600);
        int days = Math.round(time_elapsed / 86400);
        int weeks = Math.round(time_elapsed / 604800);
        int months = Math.round(time_elapsed / 2600640);
        int years = Math.round(time_elapsed / 31207680);

        // Seconds
        if (seconds <= 60) {
            return "just now";
        }
        //Minutes
        else if (minutes <= 60) {
            if (minutes == 1) {
                return "one minute ago";
            } else {
                return minutes + " minutes ago";
            }
        }
        //Hours
        else if (hours <= 24) {
            if (hours == 1) {
                return "an hour ago";
            } else {
                return hours + " hrs ago";
            }
        }
        //Days
        else if (days <= 7) {
            if (days == 1) {
                return "yesterday";
            } else {
                return days + " days ago";
            }
        }
        //Weeks
        else if (weeks <= 4.3) {
            if (weeks == 1) {
                return "a week ago";
            } else {
                return weeks + " weeks ago";
            }
        }
        //Months
        else if (months <= 12) {
            if (months == 1) {
                return "a month ago";
            } else {
                return months + " months ago";
            }
        }
        //Years
        else {
            if (years == 1) {
                return "one year ago";
            } else {
                return years + " years ago";
            }
        }
    }

1) 这里的 time_ago 单位是微秒


2

如果我们考虑性能,这段代码会更好。它减少了计算的次数。 原因 只有在秒数大于60时才计算分钟,在分钟数大于60时才计算小时,依此类推...

class timeAgo {

static String getTimeAgo(long time_ago) {
    time_ago=time_ago/1000;
    long cur_time = (Calendar.getInstance().getTimeInMillis())/1000 ;
    long time_elapsed = cur_time - time_ago;
    long seconds = time_elapsed;
   // Seconds
    if (seconds <= 60) {
        return "Just now";
    }
    //Minutes
    else{
        int minutes = Math.round(time_elapsed / 60);

        if (minutes <= 60) {
            if (minutes == 1) {
                return "a minute ago";
            } else {
                return minutes + " minutes ago";
            }
        }
        //Hours
        else {
            int hours = Math.round(time_elapsed / 3600);
            if (hours <= 24) {
                if (hours == 1) {
                    return "An hour ago";
                } else {
                    return hours + " hrs ago";
                }
            }
            //Days
            else {
                int days = Math.round(time_elapsed / 86400);
                if (days <= 7) {
                    if (days == 1) {
                        return "Yesterday";
                    } else {
                        return days + " days ago";
                    }
                }
                //Weeks
                else {
                    int weeks = Math.round(time_elapsed / 604800);
                    if (weeks <= 4.3) {
                        if (weeks == 1) {
                            return "A week ago";
                        } else {
                            return weeks + " weeks ago";
                        }
                    }
                    //Months
                    else {
                        int months = Math.round(time_elapsed / 2600640);
                        if (months <= 12) {
                            if (months == 1) {
                                return "A month ago";
                            } else {
                                return months + " months ago";
                            }
                        }
                        //Years
                        else {
                            int years = Math.round(time_elapsed / 31207680);
                            if (years == 1) {
                                return "One year ago";
                            } else {
                                return years + " years ago";
                            }
                        }
                    }
                }
            }
        }
    }

}

}

1
如果你正在开发Android应用,可以使用以下代码:android.text.format.DateUtils.getRelativeTimeSpanString(milliseconds) - Wajid

2

java.time

您可以使用java.time.Durationjava.time.Period,它们是基于ISO-8601标准建模的,并且作为JSR-310实现的一部分在Java-8中引入。在Java-9中还引入了一些更方便的方法。

  1. 使用Duration计算基于时间的数量或时间量。它可以使用基于持续时间的单位(例如纳秒、秒、分钟和小时)访问。此外,可以使用DAYS单位,它被视为完全等于24小时,因此忽略夏令时效应。
  2. 使用Period计算基于日期的时间量。它可以使用基于周期的单位(例如天、月和年)访问。

演示:

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Month;

public class Main {
    public static void main(String[] args) {
        // An arbitrary local date and time
        LocalDateTime startDateTime = LocalDateTime.of(2020, Month.DECEMBER, 10, 15, 20, 25);

        // Current local date and time
        LocalDateTime endDateTime = LocalDateTime.now();

        Duration duration = Duration.between(startDateTime, endDateTime);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDays(), duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
                duration.toNanos() % 1000000000);
        System.out.println(formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
                duration.toNanosPart());
        System.out.println(formattedElapsedTime);
        // ##############################################################################
    }
}

输出:

PT1395H35M7.355288S
58 days, 3 hours, 35 minutes, 7 seconds, 355288000 nanoseconds ago
58 days, 3 hours, 35 minutes, 7 seconds, 355288000 nanoseconds ago

如果你有两个在UTC的时间点,你可以使用Instant而不是LocalDateTime。例如:

import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        // Current moment at UTC
        Instant now = Instant.now();

        // An instant in the past
        Instant startDateTime = now.minus(58, ChronoUnit.DAYS)
                                .minus(2, ChronoUnit.HOURS)
                                .minus(54, ChronoUnit.MINUTES)
                                .minus(24, ChronoUnit.SECONDS)
                                .minus(808624000, ChronoUnit.NANOS);

        Duration duration = Duration.between(startDateTime, now);
        // Default format
        System.out.println(duration);

        // Custom format
        // ####################################Java-8####################################
        String formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDays(), duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
                duration.toNanos() % 1000000000);
        System.out.println(formattedElapsedTime);
        // ##############################################################################

        // ####################################Java-9####################################
        formattedElapsedTime = String.format("%d days, %d hours, %d minutes, %d seconds, %d nanoseconds ago",
                duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
                duration.toNanosPart());
        System.out.println(formattedElapsedTime);
        // ##############################################################################
    }
}

输出:

PT1394H54M24.808624S
58 days, 2 hours, 54 minutes, 24 seconds, 808624000 nanoseconds ago
58 days, 2 hours, 54 minutes, 24 seconds, 808624000 nanoseconds ago

Period演示:

import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        // Replace ZoneId.systemDefault() with the applicable timezone ID e.g.
        // ZoneId.of("Europe/London"). For LocalDate in the JVM's timezone, simply use
        // LocalDate.now()
        LocalDate endDate = LocalDate.now(ZoneId.systemDefault());

        // Let's assume the start date is 1 year, 2 months, and 3 days ago
        LocalDate startDate = endDate.minusYears(1).minusMonths(2).minusDays(3);

        Period period = Period.between(startDate, endDate);
        // Default format
        System.out.println(period);

        // Custom format
        String formattedElapsedPeriod = String.format("%d years, %d months, %d days ago", period.getYears(),
                period.getMonths(), period.getDays());
        System.out.println(formattedElapsedPeriod);
    }
}

输出:

P1Y2M3D
1 years, 2 months, 3 days ago

日期时间教程中了解现代日期时间API。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接