我有开始日期和结束日期。
我需要在Java中这两个日期之间的月数。
例如
它有一个日期和一个二月日期。
它应该返回2.
答案 0 :(得分:38)
正如其他人所说,如果有一个图书馆会在几个月内给你时差,你可以使用它,那么你也可以。
否则,如果y1
和m1
是第一个日期的年份和月份,而y2
和m2
是第二个日期的年份和月份,那么你想要的价值是:
(y2 - y1) * 12 + (m2 - m1) + 1;
请注意,即使第二个日期在第一个日期之后,中间项(m2 - m1)也可能是负数,但这没关系。
无论是月份是在1月= 0还是1月= 1,无论是年份是AD,1900年以来的年份,还是其他什么都没关系,只要这两个日期使用相同的基础。因此,例如,不要混合AD和BC日期,因为没有第0年,因此BC从AD偏移1。
如果以适当的形式提供给您,或者使用日历,您可以直接从日期获得y1
等。
答案 1 :(得分:35)
除了使用Joda时间,这似乎是我最喜欢的建议,我会提供以下代码:
public static final int getMonthsDifference(Date date1, Date date2) {
int m1 = date1.getYear() * 12 + date1.getMonth();
int m2 = date2.getYear() * 12 + date2.getMonth();
return m2 - m1 + 1;
}
编辑:从Java 8开始,有一种更标准的计算相同差异的方法。请参阅我的替代答案using JSR-310 api。
答案 2 :(得分:30)
我会强烈为此推荐Joda-Time。
请注意尼克霍尔特的评论如下。夏令时的变化。
答案 3 :(得分:18)
现在{8}已包含在Java 8及更高版本的SDK中,这是获得两个日期值差异的更标准方法:
public static final long getMonthsDifference(Date date1, Date date2) {
YearMonth m1 = YearMonth.from(date1.toInstant());
YearMonth m2 = YearMonth.from(date2.toInstant());
return m1.until(m2, ChronoUnit.MONTHS) + 1;
}
这有利于清楚地说明计算的精确度,并且很容易理解计算的目的是什么。
答案 4 :(得分:15)
Java 8解决方案:
@Test
public void monthBetween() {
LocalDate d1 = LocalDate.of(2013, Month.APRIL, 1);
LocalDate d2 = LocalDate.of(2014, Month.APRIL, 1);
long monthBetween = ChronoUnit.MONTHS.between(d1, d2);
assertEquals(12, monthBetween);
}
答案 5 :(得分:8)
使用joda time将是这样的(我比较了今天和2012年12月20日之间的几个月)
import org.joda.time.DateTime ;
import org.joda.time.Months;
DateTime x = new DateTime().withDate(2009,12,20); // doomsday lol
Months d = Months.monthsBetween( new DateTime(), x);
int monthsDiff = d.getMonths();
结果:41个月(2009年7月6日起)
应该很容易吗? :)
ps:您还可以使用SimpleDateFormat转换日期 像:
Date x = new SimpleDateFormat("dd/mm/yyyy").parse("20/12/2009");
DateTime z = new DateTime(x);
如果您不想使用Joda(无论出于何种原因),您可以将日期转换为TimeStamp,然后在两个日期之间进行毫秒的差异,然后计算回数月。但我仍然倾向于使用Joda时间来简化:)
答案 6 :(得分:8)
基于上面提到的答案,我自己编写了一些,我将其添加到现有的DateUtils类中:
public static Integer differenceInMonths(Date beginningDate, Date endingDate) {
if (beginningDate == null || endingDate == null) {
return 0;
}
Calendar cal1 = new GregorianCalendar();
cal1.setTime(beginningDate);
Calendar cal2 = new GregorianCalendar();
cal2.setTime(endingDate);
return differenceInMonths(cal1, cal2);
}
private static Integer differenceInMonths(Calendar beginningDate, Calendar endingDate) {
if (beginningDate == null || endingDate == null) {
return 0;
}
int m1 = beginningDate.get(Calendar.YEAR) * 12 + beginningDate.get(Calendar.MONTH);
int m2 = endingDate.get(Calendar.YEAR) * 12 + endingDate.get(Calendar.MONTH);
return m2 - m1;
}
关联单位测试:
public void testDifferenceInMonths() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
assertEquals(12, DateUtils.differenceInMonths(sdf.parse("2014/03/22"), sdf.parse("2015/03/22")).intValue());
assertEquals(11, DateUtils.differenceInMonths(sdf.parse("2014/01/01"), sdf.parse("2014/12/25")).intValue());
assertEquals(88, DateUtils.differenceInMonths(sdf.parse("2014/03/22"), sdf.parse("2021/07/05")).intValue());
assertEquals(6, DateUtils.differenceInMonths(sdf.parse("2014/01/22"), sdf.parse("2014/07/22")).intValue());
}
答案 7 :(得分:2)
答案 8 :(得分:2)
这取决于您对一个月的定义,但这是我们使用的:
int iMonths = 0;
Calendar cal1 = GregorianCalendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = GregorianCalendar.getInstance();
cal2.setTime(date2);
while (cal1.after(cal2)){
cal2.add(Calendar.MONTH, 1);
iMonths++;
}
if (cal2.get(Calendar.DAY_OF_MONTH) > cal1.get(Calendar.DAY_OF_MONTH)){
iMonths--;
}
return iMonths;
答案 9 :(得分:2)
ChronoUnit.MONTHS.between(
YearMonth.from( LocalDate.of( 2009 , 1 , 29 ) ) ,
YearMonth.from( LocalDate.of( 2009 , 2 , 2 ) )
)
Answer by Roland Tepp已接近但忽略了时区的关键问题。确定月份和日期需要一个时区,就像任何特定时刻日期在全球各地一样。
ZonedDateTime
因此,他将java.util.Date
个对象转换为java.time.Instant
个对象的示例隐式使用UTC。根据定义,这两个类中的值始终为UTC。因此,您需要将这些对象调整到所需/预期的时区,以便能够提取有意义的日期。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtStart = myJavaUtilDate1.toInstant().atZone( z );
ZonedDateTime zdtStop = myJavaUtilDate2.toInstant().atZone( z );
YearMonth
由于您想知道日期范围触及了多少个日历月,而不是30天的块数,请转换为YearMonth
个对象。
YearMonth start = YearMonth.from( zdtStart );
YearMonth stop = YearMonth.from( zdtStop );
ChronoUnit
通过调用ChronoUnit
枚举来计算月数。
long monthsBetween = ChronoUnit.MONTHS.between( start , stop );
1
你想要2的结果,但我们在这里得到1。原因是在日期时间工作中,最佳实践是通过半开放方法定义时间跨度。在半开放中,开头是包含,而结尾是独占。我建议你在整个日期工作中坚持这个定义,因为这样做最终有意义,消除了令人困惑的含糊之处,并使你的工作更容易在心理上解析,更不容易出错。但是如果你坚持你的定义,只需在结果中添加1
,假设你有正数的结果(意味着你的时间跨度是时间而不是向后)。
LocalDate
原始问题不明确,但可能需要仅限日期值而不是日期时间值。如果是这样,请使用LocalDate
类。 LocalDate
类表示没有时间且没有时区的仅限日期的值。
LocalDate start = LocalDate.of( 2009 , 1 , 29 ) ;
LocalDate stop = LocalDate.of( 2009 , 2 , 2 ) ;
long monthsBetween = ChronoUnit.MONTHS.between( start , stop );
1
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 10 :(得分:1)
这是使用java.util.Calendar
对象的解决方案:
private static Integer getMonthsBetweenDates(Date d1, Date d2) {
Calendar todayDate = getCalendar(d1);
Calendar pastDate = getCalendar(d2);
int yearDiff = todayDate.get(Calendar.YEAR) - pastDate.get(Calendar.YEAR);
if (pastDate.get(Calendar.MONTH) < 11 && pastDate.get(Calendar.DAY_OF_MONTH) < 31){ //if pastDate is smaller than 31/12
yearDiff++;
}
int monthCount = 0;
for (int year = 0 ; year < yearDiff ; year++){
if (year == 0) {
monthCount += 12 - pastDate.get(Calendar.MONTH);
} else if (year == yearDiff - 1){ //last year
if (todayDate.get(Calendar.MONTH) < pastDate.get(Calendar.MONTH)){
monthCount += todayDate.get(Calendar.MONTH) + 1;
} else if (todayDate.get(Calendar.MONTH) >= pastDate.get(Calendar.MONTH) && todayDate.get(Calendar.DAY_OF_MONTH) < pastDate.get(Calendar.DAY_OF_MONTH)){
monthCount += todayDate.get(Calendar.MONTH);
} else if (todayDate.get(Calendar.MONTH) >= pastDate.get(Calendar.MONTH) && todayDate.get(Calendar.DAY_OF_MONTH) >= pastDate.get(Calendar.DAY_OF_MONTH)){
monthCount += todayDate.get(Calendar.MONTH) + 1;
}
}
for (int months = 0 ; months < 12 ; months++){
if (year > 0 && year < yearDiff -1){
monthCount++;
}
}
}
return monthCount;
}
答案 11 :(得分:1)
您可以使用日历或Joda time库。
在Joda时间,您可以使用Days.daysBetween()方法。然后,您可以计算月份差异。您还可以使用DateTime.getMonthOfYear()并进行减法(对于同一年的日期)。
答案 12 :(得分:1)
答案 13 :(得分:1)
它不是最好的答案,但你可以使用unixtimestamp 首先,您会找到日期的unixtime 然后互相推出
最后你应该将unixtime(sum)转换为String
答案 14 :(得分:1)
我必须写这个实现,becoz我有自定义的时间段,我必须在两个日期内寻找。 在这里,您可以定义自定义时间段并输入逻辑,以进行计算。
此处TimePeriod是一个POJO,它有开始,结束,期间开始,期末
公共课每月延长期{
public int getPeriodCount(String startDate, String endDate, int scalar) {
int cnt = getPeriods(startDate, endDate, scalar).size();
return cnt;
}
public List getPeriods(String startDate, String endDate, int scalar) {
ArrayList list = new ArrayList();
Calendar startCal = CalendarUtil.getCalendar(startDate);
Calendar endCal = CalendarUtil.getCalendar(endDate);
while (startCal.compareTo(endCal) <= 0) {
TimePeriod period = new TimePeriod();
period.setStartDate(startCal.getTime());
period.setPeriodStartDate(getPeriodStartDate((Calendar) startCal.clone()).getTime());
Calendar periodEndCal = getPeriodEndDate((Calendar) startCal.clone(), scalar);
period.setEndDate(endCal.before(periodEndCal) ? endCal.getTime() : periodEndCal.getTime());
period.setPeriodEndDate(periodEndCal.getTime());
periodEndCal.add(Calendar.DATE, 1);
startCal = periodEndCal;
list.add(period);
}
return list;
}
private Calendar getPeriodStartDate(Calendar cal) {
cal.set(Calendar.DATE, cal.getActualMinimum(Calendar.DATE));
return cal;
}
private Calendar getPeriodEndDate(Calendar cal, int scalar) {
while (scalar-- > 0) {
cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
if (scalar > 0)
cal.add(Calendar.DATE, 1);
}
return cal;
}
}
答案 15 :(得分:0)
这里是java中monthDiff的完整实现,没有迭代。它返回两个日期之间的完整月的数量。如果要在结果中包括不完整的月份数(如第一个问题),则必须在调用该方法之前将两个日期的天,小时,分钟,秒和毫秒清零,否则可以更改不比较天,小时,分钟等的方法。
import java.util.Date;
import java.util.Calendar;
...
public static int monthDiff(Date d1, Date d2) {
int monthDiff;
Calendar c1, c2;
int M1, M2, y1, y2, t1, t2, h1, h2, m1, m2, s1, s2, ms1, ms2;
c1 = Calendar.getInstance();
c1.setTime(d1);
c2 = Calendar.getInstance();
c2.setTime(d2);
M1 = c1.get(Calendar.MONTH);
M2 = c2.get(Calendar.MONTH);
y1 = c1.get(Calendar.YEAR);
y2 = c2.get(Calendar.YEAR);
t1 = c1.get(Calendar.DAY_OF_MONTH);
t2 = c2.get(Calendar.DAY_OF_MONTH);
if(M2 < M1) {
M2 += 12;
y2--;
}
monthDiff = 12*(y2 - y1) + M2 - M1;
if(t2 < t1)
monthDiff --; // not a full month
else if(t2 == t1) { // perhaps a full month, we have to look into the details
h1 = c1.get(Calendar.HOUR_OF_DAY);
h2 = c2.get(Calendar.HOUR_OF_DAY);
if(h2 < h1)
monthDiff--; // not a full month
else if(h2 == h1) { // go deeper
m1 = c1.get(Calendar.MINUTE);
m2 = c2.get(Calendar.MINUTE);
if(m2 < m1) // not a full month
monthDiff--;
else if(m2 == m1) { // look deeper
s1 = c1.get(Calendar.SECOND);
s2 = c2.get(Calendar.SECOND);
if(s2 < s1)
monthDiff--; // on enleve l'age de mon hamster
else if(s2 == s1) {
ms1 = c1.get(Calendar.MILLISECOND);
ms2 = c2.get(Calendar.MILLISECOND);
if(ms2 < ms1)
monthDiff--;
// else // it's a full month yeah
}
}
}
}
return monthDiff;
}
答案 16 :(得分:0)
仅用1行和一些数学就可以完成很多长代码答案:
events.js:174
throw er; // Unhandled 'error' event
^
Error: write EPIPE
at WriteWrap.afterWrite [as oncomplete] (net.js:779:14)
Emitted 'error' event at:
at Socket.onerror (_stream_readable.js:713:12)
at Socket.emit (events.js:189:13)
at Socket.EventEmitter.emit (domain.js:441:20)
at onwriteError (_stream_writable.js:431:12)
at onwrite (_stream_writable.js:456:5)
at _destroy (internal/streams/destroy.js:40:7)
at Socket._destroy (net.js:604:3)
at Socket.destroy (internal/streams/destroy.js:32:8)
at WriteWrap.afterWrite [as oncomplete] (net.js:781:10)
答案 17 :(得分:0)
long monthsBetween = ChronoUnit.MONTHS.between(LocalDate.parse("2016-01-29").minusMonths(1),
LocalDate.parse("2016-02-02").plusMonths(1));
答案 18 :(得分:0)
低于逻辑将在几个月内获取差异
(endCal.get(Calendar.YEAR)*12+endCal.get(Calendar.MONTH))-(startCal.get(Calendar.YEAR)*12+startCal.get(Calendar.MONTH))
答案 19 :(得分:0)
用于查找两个日期之间的月份差异的完整代码段如下:
public String getContractMonth(String contractStart, String contractEnd) {
SimpleDateFormat dfDate = new SimpleDateFormat("yyyy-MM-dd");
String months = "0";
try {
Date startDate = dfDate.parse(contractStart);
Date endDate = dfDate.parse(contractEnd);
Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(startDate);
Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(endDate);
int diffYear = endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR);
int diffMonth = diffYear * 12 + endCalendar.get(Calendar.MONTH) - startCalendar.get(Calendar.MONTH);
months = diffMonth + "";
} catch (ParseException e) {
e.printStackTrace();
} catch (java.text.ParseException e) {
e.printStackTrace();
}
return months;
}
答案 20 :(得分:0)
为什么不用完整的时间计算
public static Integer calculateMonthDiff(Date begining, Date end) throws Exception {
if (begining.compareTo(end) > 0) {
throw new Exception("Beginning date is greater than the ending date");
}
if (begining.compareTo(end) == 0) {
return 0;
}
Calendar cEndCheckDate = Calendar.getInstance();
cEndCheckDate.setTime(begining);
int add = 0;
while (true) {
cEndCheckDate.add(Calendar.MONTH, 1);
add++;
if (cEndCheckDate.getTime().compareTo(end) > 0) {
return add - 1;
}
}
}