如果有日期更改,我想找到两个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));
}
但是它不起作用,因为它只会在天数差异之间给出差异,如果有月份差异则毫无价值。
答案 0 :(得分:27)
尝试以下方法:
public static long daysBetween(Calendar startDate, Calendar endDate) {
long end = endDate.getTimeInMillis();
long start = startDate.getTimeInMillis();
return TimeUnit.MILLISECONDS.toDays(Math.abs(end - start));
}
答案 1 :(得分:20)
在Java 8及更高版本中,我们可以简单地使用java.time类。
hoursBetween = ChronoUnit.HOURS.between(calendarObj.toInstant(), calendarObj.toInstant());
daysBetween = ChronoUnit.DAYS.between(calendarObj.toInstant(), calendarObj.toInstant());
答案 2 :(得分:8)
此函数计算两个日历之间的天数,作为它们之间的月份日历天数,这是OP想要的。计算是通过计算两个日历设置为各自日期的午夜之后的日历之间的86,400,000毫秒的倍数来执行的。
例如,我的函数将计算1月1日晚上11点59分和1月2日12:01 AM之间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()));
}
答案 3 :(得分:3)
更新现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。有关经过时间的计算,请参阅Anees A的the Answer,并查看我的new Answer使用 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
返回的Days
对象中提取纯daysBetween
个数字。
转储到控制台。
System.out.println ( "today: " + today + " to weekLater: " + weekLater + " is days: " + days );
今天:2015-12-22至周时间:2015-12-29是天:7
您有日历对象。我们需要将它们转换为Joda-Time对象。在内部,Calendar对象有一个long
整数,跟踪自UTC中1970年第一个时刻以来的毫秒数。我们可以提取该数字,并将其提供给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 ();
答案 4 :(得分:2)
Extension to @JK1 great answer :
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));
}
答案 5 :(得分:0)
我有https://stackoverflow.com/a/31800947/3845798给出的类似(不完全相同)的方法。
并且已经围绕api编写了测试用例,对我来说,如果我通过它就失败了 2017年3月8日 - 作为开始日期和2017年8月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。
答案 6 :(得分:0)
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)
}
答案 7 :(得分:0)
Answer by Mohamed Anees A在几个小时内是正确的,但在几天内是错误的。数天需要time zone。另一个答案使用Instant
,这是UTC中的时刻,始终是UTC中的时刻。因此,您不是获得了正确的日历天数。
要按日历计算天数,请将旧式Calendar
转换为ZonedDateTime
,然后馈入ChronoUnit.DAYS.between
。
时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,Paris France午夜之后的几分钟是新的一天,而Montréal Québec仍然是“昨天”。
如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将您的期望/期望时区明确指定为参数。如果紧急,请与您的用户确认区域。
以Continent/Region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用2-4个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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).
如果要使用JVM的当前默认时区,请提出要求并作为参数传递。如果省略,代码将变得难以理解,因为我们不确定您是否打算使用默认值,还是像许多程序员一样不知道该问题。
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
GregorianCalendar
转换为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.
}
所得的ZonedDateTime
对象在时区带有ZoneId
对象。有了该区域,您就可以计算经过的日历天。
要使用年-月-天为单位来计算经过时间,请使用Period
类。
Period p = Period.between( zdtStart , zdtStop ) ;
如果您希望将天数作为经过的时间,请e ChronoUnit
。
long days = ChronoUnit.DAYS.between( zdtStart , zdtStop ) ;
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 8 :(得分:0)
这是我使用好的老式Calendar对象的解决方案:
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在leap年返回366,在非-年返回365。这就是为什么我们需要一个循环,您不能仅仅将年份之间的差值乘以365,因为那里可能会有a年。 (我的初稿使用的是getMaximum,但是不起作用,因为无论年份如何,它都会返回366。getMaximum是任何年份(而不是该特定年份)的最大值。)
由于此代码不假设一天中的小时数,因此不会被夏令时所迷惑。
答案 9 :(得分:0)
如果您的项目不支持新的Java 8类(作为选定的答案),则可以添加此方法来计算天数,而不受时区或其他事实的影响。
它不如其他方法快(时间复杂度更高),但是它是可靠的,无论如何,日期比较很少超过几百年或数千年。
(Kotlin)
/**
* 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))
}
答案 10 :(得分:-4)
Calendar day1 = Calendar.getInstance();
Calendar day2 = Calendar.getInstance();
int diff = day1.get(Calendar.DAY_OF_YEAR) - day2.get(Calendar.DAY_OF_YEAR);