经过的月数计算未给出当前月和日但不同年份的日期的正确结果

我试图计算自特定日期以来经过的月份,该function正常工作,虽然它给了我一个月的差异(不到一个月),如果我把今天的日期与过去的不同年份。

对所有日期说,该function运作良好,除了:

如果今天是“2014-03-06”(YYYY,MM,DD)并且我将日期作为“2006-03-06”处理到该function,则结果会缩短一个月,但是如果我明天使用相同的日期,结果很好。 在哪里我错了。 以下是代码:

public static int months(String d) { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd"); Date d1 = null; try { d1 = f.parse(d); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Date d2 = (getCurrentDate()); Date d2 = getCurrentDate(); Calendar c1 = Calendar.getInstance(); c1.setTime(d1); Calendar c2 = Calendar.getInstance(); c2.setTime(d2); int diff = 0; if (c2.after(c1)) { while (c2.after(c1)) { c1.add(Calendar.MONTH, 1); if (c2.after(c1)) { diff++; } } } else if (c2.before(c1)) { while (c2.before(c1)) { c1.add(Calendar.MONTH, -1); if (c1.before(c2)) { diff--; } } } System.out.println(diff); return diff; } 

结果:95个月。

理想情况下应该是96个月。

请不要考虑函数的静态性质,我已将此代码隔离在另一个项目中以用于测试目的。

这是c1和c2的值:

 java.util.GregorianCalendar[time=1141583400000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2006,MONTH=2,WEEK_OF_YEAR=10,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=65,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=19800000,DST_OFFSET=0] and c2 is: java.util.GregorianCalendar[time=1394044200000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2014,MONTH=2,WEEK_OF_YEAR=10,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=65,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=1,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=19800000,DST_OFFSET=0] 95 

我的坏处是getCurrentDate():

 public static Date getCurrentDate() { String DateStr = new SimpleDateFormat("yyyy-MM-dd"/*, current*/).format(Calendar.getInstance().getTime()); // String DateStr = formattedDate; Date date = null; try { date = new SimpleDateFormat("yyyy-MM-dd"/*, current*/).parse(DateStr); } catch (ParseException e) { e.printStackTrace(); } java.sql.Date dx = new java.sql.Date(date.getTime()); return dx; } 

检查你的getCurrentDate()方法。 我已用new Date()替换,输出为96如你所说。

Calendar beforebefore的比较还包括时间信息,这可能会导致计算结束,导致比较失败…

尝试将值调整到日期边界…例如……

 import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class TestMonths { public static final String TEST1 = "2006-03-06"; public static final String TEST2 = "2014-03-06"; public static void main(String[] args) { System.out.println(months(TEST2)); } public static Date getCurrentDate() throws ParseException { return new SimpleDateFormat("yyyy-MM-dd").parse(TEST1); } public static int months(String d) { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd"); Date d1 = null; Date d2 = null; try { d1 = f.parse(d); d2 = (getCurrentDate()); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } Calendar c1 = Calendar.getInstance(); c1.setTime(d1); Calendar c2 = Calendar.getInstance(); c2.setTime(d2); int diff = 0; if (c2.after(c1)) { System.out.println("After"); setStartOfDay(c1); setEndOfDay(c2); while (c2.after(c1)) { c1.add(Calendar.MONTH, 1); if (c2.after(c1)) { diff++; } } } else if (c2.before(c1)) { System.out.println("Before"); setStartOfDay(c2); setEndOfDay(c1); while (c2.before(c1)) { c1.add(Calendar.MONTH, -1); if (c2.before(c1)) { diff--; } } } System.out.println(diff); return diff; } public static void setStartOfDay(Calendar cal) { cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); } public static void setEndOfDay(Calendar cal) { cal.set(Calendar.HOUR_OF_DAY, 23); cal.set(Calendar.MINUTE, 59); cal.set(Calendar.SECOND, 59); cal.set(Calendar.MILLISECOND, 99); } } 

ps-我还纠正了“之前”分支(其中c2是“之前” c1 )因为存在逻辑错误……

我知道为项目添加新的依赖项并不总是可行和可取的,但您是否考虑过使用JodaTime库进行日期/时间计算? 它有更清洁的api,它严格遵循所有日历/时区限制。

以下是您的日期示例(省略了从字符串解析的日期)。

  DateTime from = new DateTime(2006, 3, 6, 0, 0); //2006-03-06 DateTime to = new DateTime(2014, 3, 6, 0, 0); //2014-03-06 System.out.println(new Interval(from, to).toPeriod(PeriodType.months())); 

它打印“P96M”,即96个月。

请注意,此示例使用默认(系统)时区。

改变这个:

 Date d2 = getCurrentDate(); 

对此:

 Calendar now = Calendar.getInstance(); Date d2 = now.getTime(); 

它返回96给我。

编辑—

如果您正在使用函数getCurrentDate(),我建议您将其替换为:

 public static Date getCurrentDate() { Calendar now = Calendar.getInstance(); Date d2 = now.getTime(); return d2 } 

正如Deinlandel指出的正确答案所指出的那样,使用Joda-Time库可以更轻松地完成日期工作。

这是我对一些示例代码的看法。

 DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); DateTime dateTimeStart = new DateTime( "2006-03-06", timeZone ); DateTime dateTimeStop = new DateTime( "2014-03-06", timeZone ); int months = Months.monthsBetween( dateTimeStart, dateTimeStop ).getMonths(); 

转储到控制台……

 System.out.println( "dateTimeStart: " + dateTimeStart ); System.out.println( "dateTimeStop: " + dateTimeStop ); System.out.println( "months: " + months ); 

跑的时候……

 dateTimeStart: 2006-03-06T00:00:00.000+01:00 dateTimeStop: 2014-03-06T00:00:00.000+01:00 months: 96