Java 如何获取两个日历实例之间的天数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19462912/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 17:29:05  来源:igfitidea点击:

How to get number of days between two calendar instance?

javaandroiddatecalendar

提问by Akram

I want to find the difference between two Calendarobjects in number of days if there is date change like If clock ticked from 23:59-0:00 there should be a day difference.

Calendar如果有日期更改,我想找到两个对象之间的天数差异,例如如果时钟从 23:59-0:00 打勾,应该有天差。

i wrote this

我写了这个

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

but its not working as it only gives difference between days if there is month difference its worthless.

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

采纳答案by Mohamed Anees A

In Java 8 and later, we could simply use the java.timeclasses.

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

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

daysBetween = ChronoUnit.DAYS.between(calendarObj.toInstant(), calendarObj.toInstant());

回答by Jk1

Try the following approach:

尝试以下方法:

public static long daysBetween(Calendar startDate, Calendar endDate) {
    long end = endDate.getTimeInMillis();
    long start = startDate.getTimeInMillis();
    return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start));
}

回答by stackoverflowuser2010

This function computes the number of days between two Calendars as the number of calendar days of the month that are between them, which is what the OP wanted. The calculation is performed by counting how many multiples of 86,400,000 milliseconds are between the calendars after both have been set to midnight of their respective days.

此函数计算两个日历之间的天数作为它们之间的月份日历天数,这是 OP 想要的。计算是通过计算日历之间有多少 86,400,000 毫秒的倍数被设置为各自日期的午夜来执行的。

For example, my function will compute 1 day's difference between a Calendar on January 1, 11:59PM and January 2, 12:01AM.

例如,我的函数将计算日历在 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()));
}

回答by stackoverflowuser2010

Calendar day1 = Calendar.getInstance();

日历 day1 = Calendar.getInstance();

Calendar day2 = Calendar.getInstance();

日历 day2 = Calendar.getInstance();

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

回答by Basil Bourque

UPDATEThe Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses. See the Answerby Anees A for the calculation of elapsed hours, and see my new Answerfor using java.timeto calculate elapsed days with respect for the calendar.

UPDATE乔达时间的项目,现在在维护模式,建议迁移到java.time类。请参阅Anees A的答案以了解经过的小时数的计算,并参阅我的新答案以使用java.time计算与日历相关的经过天数。

Joda-Time

乔达时间

The old java.util.Date/.Calendar classes are notoriously troublesome and should be avoided.

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

Instead use the Joda-Timelibrary. Unless you have Java 8 technology in which case use its successor, the built-in java.time framework (not in Android as of 2015).

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

Since you only care about "days" defined as dates (not 24-hour periods), let's focus on dates. Joda-Time offers the class LocalDateto represent a date-only value without time-of-day nor time zone.

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

While lacking a time zone, note that time zone is crucialin determining a date such as "today". A new day dawns earlier to the east than to the west. So the date is not the same around the world at one moment, the date depends on your time zone.

虽然缺少时区,但请注意时区对于确定“今天”等日期至关重要。新的一天在东方比西方更早的到来。因此,某一时刻世界各地的日期都不相同,日期取决于您所在的时区。

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

Let's count the number of days until next week, which should of course be seven.

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

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

The getDayson the end extracts a plain intnumber from the Daysobject returned by daysBetween.

getDays对端提取纯int从数Days由返回的对象daysBetween

Dump to console.

转储到控制台。

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

today: 2015-12-22 to weekLater: 2015-12-29 is days: 7

今天:2015-12-22 到星期以后:2015-12-29 是天:7

You have Calendar objects. We need to convert them to Joda-Time objects. Internally the Calendar objects have a longinteger tracking the number of milliseconds since the epoch of first moment of 1970 in UTC. We can extract that number, and feed it to Joda-Time. We also need to assign the desired time zone by which we intend to determine a date.

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

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

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

Convert from DateTime objects to LocalDate.

从 DateTime 对象转换为 LocalDate。

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

Now do the same elapsed calculation we saw earlier.

现在做我们之前看到的同样的经过计算。

int elapsed = Days.daysBetween ( start , stop ).getDays ();

回答by Arpit

I have the similar (not exact same) approach given above by https://stackoverflow.com/a/31800947/3845798.

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

And have written test cases around the api, for me it failed if I passed 8th march 2017 - as the start date and 8th apr 2017 as the end date.

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

There are few dates where you will see the difference by 1day. Therefore, I have kind of made some small changes to my api and my current api now looks something like this

很少有日期会相差 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;}

I am not using TimeUnit.MILLISECONDS.toDays that were causing me some issues.

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

回答by Steve Lukis

Extension to @JK1 great answer :

扩展@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));
}

回答by Александр Бабич

Kotlin solution, purely relies on Calendar. At the end gives exact number of days difference. Inspired by @Jk1

Kotlin 解决方案,纯粹依赖 Calendar。最后给出了确切的天数差异。灵感来自@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)
    }

回答by Basil Bourque

java.time

时间

The Answer by Mohamed Anees Ais correct for hours but wrong for days. Counting days requires a time zone. That other Answer uses the Instantwhich is a moment in UTC, always in UTC. So you are notgetting the correct number of calendardays elapsed.

Mohamed Anees A答案在几小时内是正确的,但在几天内是错误的。计算天数需要一个时区。另一个答案使用InstantUTC 中的时刻,始终使用 UTC。所以你没有得到正确的日历天数。

To count days by the calendar, convert your legacy Calendarto a ZonedDateTime, then feed to ChronoUnit.DAYS.between.

要按日历计算天数,请将您的遗产转换CalendarZonedDateTime,然后馈入ChronoUnit.DAYS.between

Time zone

时区

A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris Franceis a new day while still “yesterday” in Montréal Québec.

时区对于确定日期至关重要。对于任何给定时刻,日期因地区而异。例如,在法国巴黎午夜过后几分钟是新的一天,而在魁北克蒙特利尔仍然是“昨天” 。

If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any momentduring runtime(!), so your results may vary. Better to specify your desired/expected time zone explicitly as an argument. If critical, confirm the zone with your user.

如果未指定时区,JVM 会隐式应用其当前默认时区。该默认值可能会在运行时随时更改(!),因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。如果关键,请与您的用户确认该区域。

Specify a proper time zone namein the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as ESTor ISTas they are nottrue time zones, not standardized, and not even unique(!).

以、、 或等格式指定正确的时区名称。永远不要使用 2-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。Continent/RegionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;           // Capture the current date as seen through the wall-clock time used by the people of a certain region (a time zone).

If you want to use the JVM's current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.

如果您想使用 JVM 的当前默认时区,请询问它并作为参数传递。如果省略,代码读起来会变得模棱两可,因为我们不确定您是否打算使用默认值,或者您是否像许多程序员一样没有意识到这个问题。

ZoneId z = ZoneId.systemDefault() ;              // Get JVM's current default time zone.

Convert from GregorianCalendarto ZonedDateTime

转换GregorianCalendarZonedDateTime

The terrible GregorianCalendaris likely the concrete class behind your Calendar. If so, convert from that legacy class to the modern class, ZonedDateTime.

可怕的GregorianCalendar是你的Calendar. 如果是这样,请从该遗留类转换为现代类,ZonedDateTime.

GregorianCalendar gc = null ;                    // Legacy class representing a moment in a time zone. Avoid this class as it is terribly designed.
if( myCal instanceof GregorianCalendar ) {       // See if your `Calendar` is backed by a `GregorianCalendar` class.
    gc = (GregorianCalendar) myCal ;             // Cast from the more general class to the concrete class.
    ZonedDateTime zdt = gc.toZonedDateTime() ;   // Convert from legacy class to modern class.
}

The resulting ZonedDateTimeobject carries a ZoneIdobject for the time zone. With that zone in place, you can then calculate elapsed calendar days.

生成的ZonedDateTime对象带有ZoneId时区的对象。设置好该区域后,您就可以计算经过的日历天数。

Calculate elapsed days

计算经过的天数

To calculate the elapsed time in terms of years-months-days, use Periodclass.

要以年-月-日为单位计算经过的时间,请使用Periodclass。

Period p = Period.between( zdtStart , zdtStop ) ;

If you want total number of days as the elapsed time, use ChronoUnit.

如果您想要总天数作为经过的时间,请使用eChronoUnit

 long days = ChronoUnit.DAYS.between( zdtStart , zdtStop ) ;

Table of types of date-time classes in modern java.time versus legacy

现代 java.time 与遗留中日期时间类的类型表



About java.time

关于java.time

The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.

现在处于维护模式Joda-Time项目建议迁移到java.time类。

You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*classes.

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

Where to obtain the java.time classes?

从哪里获得 java.time 类?

The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多

回答by Jay

Here's my solution using good old Calendar objects:

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

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

This assumes d0 is later than d1. If that's not guaranteed, you could always test and swap them.

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

Basic principle is to take the difference between the day of the year of each. If they're in the same year, that would be it.

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

But they might be different years. So I loop through all the years between them, adding the number of days in a year. Note that getActualMaximum returns 366 in leap years and 365 in non-leap years. That's why we need a loop, you can't just multiply the difference between the years by 365 because there might be a leap year in there. (My first draft used getMaximum, but that doesn't work because it returns 366 regardless of the year. getMaximum is the maximum for ANY year, not this particular year.)

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

As this code makes no assumptions about the number of hours in a day, it is not fooled by daylight savings time.

由于此代码不对一天中的小时数进行假设,因此不会被夏令时所迷惑。