41

如果日期发生变化,我想找出两个Calendar对象之间的天数差异,例如如果时钟从 23:59-0:00 滴答作响,则应该存在天数差异。

我写了这个

public static int daysBetween(Calendar startDate, Calendar endDate) {  
    return Math.abs(startDate.get(Calendar.DAY_OF_MONTH)-endDate.get(Calendar.DAY_OF_MONTH));  
} 

但它不起作用,因为如果有月差,它只会在天之间产生差异,它毫无价值。

4

12 回答 12

38

尝试以下方法:

public static long daysBetween(Calendar startDate, Calendar endDate) {
    long end = endDate.getTimeInMillis();
    long start = startDate.getTimeInMillis();
    return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start));
}
于 2013-10-19T06:29:12.230 回答
33

在 Java 8 及更高版本中,我们可以简单地使用java.time类。

hoursBetween = ChronoUnit.HOURS.between(calendarObj.toInstant(), calendarObj.toInstant());

daysBetween = ChronoUnit.DAYS.between(calendarObj.toInstant(), calendarObj.toInstant());
于 2016-12-21T14:24:44.740 回答
11

此函数将两个日历之间的天数计算为它们之间一个月的日历天数,这正是 OP 想要的。计算是通过计算日历之间的 86,400,000 毫秒的倍数在两个日历都设置为各自日期的午夜之后执行的。

例如,我的函数将计算 1 月 1 日晚上 11:59 和 1 月 2 日上午 12:01 的日历之间 1 天的差异。

import java.util.concurrent.TimeUnit;

/**
 * Compute the number of calendar days between two Calendar objects. 
 * The desired value is the number of days of the month between the
 * two Calendars, not the number of milliseconds' worth of days.
 * @param startCal The earlier calendar
 * @param endCal The later calendar
 * @return the number of calendar days of the month between startCal and endCal
 */
public static long calendarDaysBetween(Calendar startCal, Calendar endCal) {

    // Create copies so we don't update the original calendars.

    Calendar start = Calendar.getInstance();
    start.setTimeZone(startCal.getTimeZone());
    start.setTimeInMillis(startCal.getTimeInMillis());

    Calendar end = Calendar.getInstance();
    end.setTimeZone(endCal.getTimeZone());
    end.setTimeInMillis(endCal.getTimeInMillis());

    // Set the copies to be at midnight, but keep the day information.

    start.set(Calendar.HOUR_OF_DAY, 0);
    start.set(Calendar.MINUTE, 0);
    start.set(Calendar.SECOND, 0);
    start.set(Calendar.MILLISECOND, 0);

    end.set(Calendar.HOUR_OF_DAY, 0);
    end.set(Calendar.MINUTE, 0);
    end.set(Calendar.SECOND, 0);
    end.set(Calendar.MILLISECOND, 0);

    // At this point, each calendar is set to midnight on 
    // their respective days. Now use TimeUnit.MILLISECONDS to
    // compute the number of full days between the two of them.

    return TimeUnit.MILLISECONDS.toDays(
            Math.abs(end.getTimeInMillis() - start.getTimeInMillis()));
}
于 2015-08-04T04:53:40.090 回答
5

扩展到@JK1 很好的答案:

public static long daysBetween(Calendar startDate, Calendar endDate) {

    //Make sure we don't change the parameter passed
    Calendar newStart = Calendar.getInstance();
    newStart.setTimeInMillis(startDate.getTimeInMillis());
    newStart.set(Calendar.HOUR_OF_DAY, 0);
    newStart.set(Calendar.MINUTE, 0);
    newStart.set(Calendar.SECOND, 0);
    newStart.set(Calendar.MILLISECOND, 0);

    Calendar newEnd = Calendar.getInstance();
    newEnd.setTimeInMillis(endDate.getTimeInMillis());
    newEnd.set(Calendar.HOUR_OF_DAY, 0);
    newEnd.set(Calendar.MINUTE, 0);
    newEnd.set(Calendar.SECOND, 0);
    newEnd.set(Calendar.MILLISECOND, 0);

    long end = newEnd.getTimeInMillis();
    long start = newStart.getTimeInMillis();
    return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start));
}
于 2017-12-17T08:27:28.970 回答
3

更新Joda-Time项目现在处于维护模式,建议迁移到java.time类。有关经过时间的计算,请参见Anees A的答案,并参见我的新答案,了解使用java.time计算日历的经过天数。

乔达时间

旧的 java.util.Date/.Calendar 类是出了名的麻烦,应该避免。

而是使用Joda-Time库。除非您拥有 Java 8 技术,在这种情况下使用它的后继者,即内置的 java.time 框架(截至 2015 年在 Android 中没有)。

由于您只关心定义为日期的“天”(不是 24 小时周期),因此让我们关注日期。Joda-Time 提供类LocalDate来表示没有时间和时区的仅日期值。

虽然缺少时区,但请注意时区对于确定诸如“今天”之类的日期至关重要。新的一天在东方比西方更早地黎明。所以世界各地的日期在某一时刻是不一样的,日期取决于你所在的时区。

DateTimeZone zone = DateTimeZone.forID ( "America/Montreal" );
LocalDate today = LocalDate.now ( zone );

让我们数一数下周之前的天数,当然应该是七天。

LocalDate weekLater = today.plusWeeks ( 1 );
int elapsed = Days.daysBetween ( today , weekLater ).getDays ();

最后的 . 从返回的对象getDays中提取一个纯int数字。DaysdaysBetween

转储到控制台。

System.out.println ( "today: " + today + " to weekLater: " + weekLater + " is days: " + days );

今天:2015-12-22 到 weekLater:2015-12-29 是天:7

您有日历对象。我们需要将它们转换为 Joda-Time 对象。在内部, Calendar 对象有一个整数,用于跟踪自 1970 年UTClong第一时刻以来的毫秒数。我们可以提取该数字,并将其提供给 Joda-Time。我们还需要分配我们打算确定日期的所需时区。

long startMillis = myStartCalendar.getTimeInMillis();
DateTime startDateTime = new DateTime( startMillis , zone );

long stopMillis = myStopCalendar.getTimeInMillis();
DateTime stopDateTime = new DateTime( stopMillis , zone );

从 DateTime 对象转换为 LocalDate。

LocalDate start = startDateTime.toLocalDate();
LocalDate stop = stopDateTime.toLocalDate();

现在进行我们之前看到的相同的经过计算。

int elapsed = Days.daysBetween ( start , stop ).getDays ();
于 2015-12-22T22:43:34.100 回答
3
于 2019-03-10T22:59:15.693 回答
2

这是我使用好的旧日历对象的解决方案:

public static int daysApart(Calendar d0,Calendar d1)
{
    int days=d0.get(Calendar.DAY_OF_YEAR)-d1.get(Calendar.DAY_OF_YEAR);
    Calendar d1p=Calendar.getInstance();
    d1p.setTime(d1.getTime());
    for (;d1p.get(Calendar.YEAR)<d0.get(Calendar.YEAR);d1p.add(Calendar.YEAR,1))
    {
        days+=d1p.getActualMaximum(Calendar.DAY_OF_YEAR);
    }
    return days;
}

这假设 d0 晚于 d1。如果不能保证,您可以随时测试和交换它们。

基本原则是取每一年的天数之间的差异。如果他们在同一年,那就是这样。

但他们可能是不同的年份。所以我循环遍历它们之间的所有年份,加上一年中的天数。请注意,getActualMaximum 在闰年返回 366,在非闰年返回 365。这就是为什么我们需要一个循环,你不能只是将年份之间的差异乘以 365,因为那里可能有闰年。(我的初稿使用了 getMaximum,但这不起作用,因为无论年份如何,它都会返回 366。getMaximum 是任何年份的最大值,而不是这个特定的年份。)

由于此代码没有对一天中的小时数做出任何假设,因此它不会被夏令时所迷惑。

于 2019-03-22T02:20:57.910 回答
0

我有上面给出的类似(不完全相同)的方法https://stackoverflow.com/a/31800947/3845798

并围绕 api 编写了测试用例,对我来说,如果我通过 2017 年 3 月 8 日作为开始日期和 2017 年 4 月 8 日作为结束日期,它就会失败。

很少有日期可以在 1 天之前看到差异。因此,我对我的 api 做了一些小改动,我当前的 api 现在看起来像这样

   public long getDays(long currentTime, long endDateTime) {

Calendar endDateCalendar;
Calendar currentDayCalendar;


//expiration day
endDateCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
endDateCalendar.setTimeInMillis(endDateTime);
endDateCalendar.set(Calendar.MILLISECOND, 0);
endDateCalendar.set(Calendar.MINUTE, 0);
endDateCalendar.set(Calendar.HOUR, 0);
endDateCalendar.set(Calendar.HOUR_OF_DAY, 0);

//current day
currentDayCalendar = Calendar.getInstance(TimeZone.getTimeZone("EST"));
currentDayCalendar.setTimeInMillis(currentTime);
currentDayCalendar.set(Calendar.MILLISECOND, 0);
currentDayCalendar.set(Calendar.MINUTE, 0);
currentDayCalendar.set(Calendar.HOUR,0);
currentDayCalendar.set(Calendar.HOUR_OF_DAY, 0);


long remainingDays = (long)Math.ceil((float) (endDateCalendar.getTimeInMillis() - currentDayCalendar.getTimeInMillis()) / (24 * 60 * 60 * 1000));

return remainingDays;}

我没有使用导致我出现一些问题的 TimeUnit.MILLISECONDS.toDays。

于 2017-04-13T10:09:53.397 回答
0

Kotlin 解决方案,完全依赖于日历。最后给出确切的天数差异。灵感来自@Jk1

 private fun daysBetween(startDate: Calendar, endDate: Calendar): Long {
        val start = Calendar.getInstance().apply {
            timeInMillis = 0
            set(Calendar.DAY_OF_YEAR, startDate.get(Calendar.DAY_OF_YEAR))
            set(Calendar.YEAR, startDate.get(Calendar.YEAR))
        }.timeInMillis
        val end = Calendar.getInstance().apply {
            timeInMillis = 0
            set(Calendar.DAY_OF_YEAR, endDate.get(Calendar.DAY_OF_YEAR))
            set(Calendar.YEAR, endDate.get(Calendar.YEAR))
        }.timeInMillis
        val differenceMillis = end - start
        return TimeUnit.MILLISECONDS.toDays(differenceMillis)
    }
于 2019-03-10T16:10:20.727 回答
0

如果您的项目不支持新的 Java 8 类(作为选择的答案),您可以添加此方法来计算天数,而不受时区或其他事实的影响。

它不像其他方法那样快(时间复杂度更高),但它是可靠的,无论如何日期比较很少超过数百或数千年。

(科特林)

/**
     * Returns the number of DAYS between two dates. Days are counted as calendar days
     * so that tomorrow (from today date reference) will be 1 ,  the day after 2 and so on
     * independent on the hour of the day.
     *
     * @param date - reference date, normally Today
     * @param selectedDate - date on the future
     */
fun getDaysBetween(date: Date, selectedDate: Date): Int {

            val d = initCalendar(date)
            val s = initCalendar(selectedDate)
            val yd = d.get(Calendar.YEAR)
            val ys = s.get(Calendar.YEAR)

            if (ys == yd) {
                return s.get(Calendar.DAY_OF_YEAR) - d.get(Calendar.DAY_OF_YEAR)
            }

            //greater year
            if (ys > yd) {
                val endOfYear = Calendar.getInstance()
                endOfYear.set(yd, Calendar.DECEMBER, 31)
                var daysToFinish = endOfYear.get(Calendar.DAY_OF_YEAR) - d.get(Calendar.DAY_OF_YEAR)
                while (endOfYear.get(Calendar.YEAR) < s.get(Calendar.YEAR)-1) {
                    endOfYear.add(Calendar.YEAR, 1)
                    daysToFinish += endOfYear.get(Calendar.DAY_OF_YEAR)
                }
                return daysToFinish + s.get(Calendar.DAY_OF_YEAR)
            }

            //past year
            else {
                val endOfYear = Calendar.getInstance()
                endOfYear.set(ys, Calendar.DECEMBER, 31)
                var daysToFinish = endOfYear.get(Calendar.DAY_OF_YEAR) - s.get(Calendar.DAY_OF_YEAR)
                while (endOfYear.get(Calendar.YEAR) < d.get(Calendar.YEAR)-1) {
                    endOfYear.add(Calendar.YEAR, 1)
                    daysToFinish += endOfYear.get(Calendar.DAY_OF_YEAR)
                }
                return daysToFinish + d.get(Calendar.DAY_OF_YEAR)
            }
        }

单元测试,你可以改进它们我不需要消极的日子,所以我没有测试那么多:

@Test
    fun `Test days between on today and following days`() {
        val future = Calendar.getInstance()
        calendar.set(2019, Calendar.AUGUST, 26)

        future.set(2019, Calendar.AUGUST, 26)
        Assert.assertEquals(0, manager.getDaysBetween(calendar.time, future.time))

        future.set(2019, Calendar.AUGUST, 27)
        Assert.assertEquals(1, manager.getDaysBetween(calendar.time, future.time))

        future.set(2019, Calendar.SEPTEMBER, 1)
        Assert.assertEquals(6, manager.getDaysBetween(calendar.time, future.time))

        future.set(2020, Calendar.AUGUST, 26)
        Assert.assertEquals(366, manager.getDaysBetween(calendar.time, future.time)) //leap year

        future.set(2022, Calendar.AUGUST, 26)
        Assert.assertEquals(1096, manager.getDaysBetween(calendar.time, future.time))

        calendar.set(2019, Calendar.DECEMBER, 31)
        future.set(2020, Calendar.JANUARY, 1)
        Assert.assertEquals(1, manager.getDaysBetween(calendar.time, future.time))
    }

    @Test
    fun `Test days between on previous days`() {
        val future = Calendar.getInstance()
        calendar.set(2019, Calendar.AUGUST, 26)

        future.set(2019,Calendar.AUGUST,25)
        Assert.assertEquals(-1, manager.getDaysBetween(calendar.time, future.time))
    }

    @Test
    fun `Test days between hour doesn't matter`() {
        val future = Calendar.getInstance()
        calendar.set(2019, Calendar.AUGUST, 26,9,31,15)

        future.set(2019,Calendar.AUGUST,28, 7,0,0)
        Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))

        future.set(2019,Calendar.AUGUST,28, 9,31,15)
        Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))

        future.set(2019,Calendar.AUGUST,28, 23,59,59)
        Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))
    }

    @Test
    fun `Test days between with time saving change`() {
        val future = Calendar.getInstance()
        calendar.set(2019, Calendar.OCTOBER, 28)

        future.set(2019, Calendar.OCTOBER,29)
        Assert.assertEquals(1, manager.getDaysBetween(calendar.time, future.time))

        future.set(2019, Calendar.OCTOBER,30)
        Assert.assertEquals(2, manager.getDaysBetween(calendar.time, future.time))
    }
于 2019-09-03T17:57:13.867 回答
0
public int getIntervalDays(Calendar c1,Calendar c2){
    Calendar first = cleanTimePart(c1);
    Calendar second = cleanTimePart(c2);
    Long intervalDays = (first.getTimeInMillis() - second.getTimeInMillis())/(1000*3600*24);
    return intervalDays.intValue();
}

private Calendar cleanTimePart(Calendar dateTime){
    Calendar newDateTime = (Calendar)dateTime.clone();
    newDateTime.set(Calendar.HOUR_OF_DAY,0);
    newDateTime.set(Calendar.MINUTE,0);
    newDateTime.set(Calendar.SECOND,0);
    newDateTime.set(Calendar.MILLISECOND,0);
    return newDateTime;
}
于 2022-02-21T12:41:12.567 回答
-5

日历 day1 = Calendar.getInstance();

日历 day2 = Calendar.getInstance();

int diff = day1.get(Calendar.DAY_OF_YEAR) - day2.get(Calendar.DAY_OF_YEAR);

于 2015-12-22T10:58:21.653 回答