`
wangyanlong0107
  • 浏览: 495114 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

【转】Java按自然月计算两个日期相差的年月日

    博客分类:
  • java
 
阅读更多

曾经我以为计算两个日期之差很简单,在给我的团队成员分配任务时,也觉得就是调用一个方法的问题,可是当我发现结果老是不对时,才发现原来JDK 提供的API中根本没有这样的方法,我也很恼火,也怪不得不少牛人在博客里怒斥Java标准库中对日期的处理晦涩不堪的现状,想这样的功能提供也是理所应当的,也就说明Date,Calendar中提供的日期处理的功能不够强大,因为已经有开源(Joda,某个知名的Java开源类库,在时间日期的处理上相比Java标准库更加强大且易用,IBM的日期类库中提供了强大的功能),各大论坛中对这个问题争论很多,可是很多都是考虑的比较简单,每个月按30天计算,可能你会说,计算的这么精确吗?答案是在一定的场合下是非常有必要的,在银行,图书馆过期图书计费,网络流量计费等,都是按照自然月来计算的,需要考虑的因素很多,而不是简单的30天,我现在需要的场合是Baby Care这款软件中,要计算Baby的年龄,就是xx years,xx months,xx days,因为很多人需要用这个看看小孩是否满月,是否周岁等,开始为了简单,我们按30天每月,后来有人反馈,计算方法不对,只好让用户选择,是每月按30天计算,还是按自然月计算。

按每月30天计算,论坛中常讨论的方法,,并且似乎也是没有问题的,但是往往计算的结果有时会相差一天:

  1. public long diffValue(Date date1, Date date2)    
  2. {    
  3.  //return date1.getTime() / (24*60*60*1000) - date2.getTime() / (24*60*60*1000);    
  4.  return (date2.getTime()  - date1.getTime() )/ 86400000;  //用立即数,减少乘法计算的开销   
  5. }   

下面是正确的解法:

问题的关键是过滤掉时分秒,保留日期部分。干的活象低通滤波器,滤掉高频杂波,保留低频信号,/86400000,就是把时分秒全忽略掉了。

解法1:

这篇博客对这个问题分析的比较透彻:http://blog.csdn.net/solomonxu/archive/2007/04/27/1587237.aspx

  1. public long differ(Date date1, Date date2)    
  2. {    
  3.  //return date1.getTime() / (24*60*60*1000) - date2.getTime() / (24*60*60*1000);    
  4.  return date2.getTime() / 86400000 - date1.getTime() / 86400000;  //用立即数,减少乘法计算的开销   
  5. }  
  6.  

解法2:

http://blog.csdn.net/rmartin/archive/2006/12/22/1452867.aspxhttp://butunclebob.com/ArticleS.UncleBob.JavaDates

把date1,date2都设置为同样的时间,我曾经设置date1为00:00:00,date2为23:59:59秒,在非常情况下,1S之差也会导致计算的天数少1.

  1. private int daysBetween(Date now, Date returnDate) {   
  2.     Calendar cNow = Calendar.getInstance();   
  3.     Calendar cReturnDate = Calendar.getInstance();   
  4.     cNow.setTime(now);   
  5.     cReturnDate.setTime(returnDate);   
  6.     setTimeToMidnight(cNow);   
  7.     setTimeToMidnight(cReturnDate);   
  8.  long todayMs = cNow.getTimeInMillis();   
  9.  long returnMs = cReturnDate.getTimeInMillis();   
  10.  long intervalMs = todayMs - returnMs;   
  11.  return millisecondsToDays(intervalMs);   
  12.   }   
  13.    
  14.  private int millisecondsToDays(long intervalMs) {   
  15.  return (int) (intervalMs / (1000 * 86400));   
  16.   }   
  17.    
  18.  private void setTimeToMidnight(Calendar calendar) {   
  19.     calendar.set(Calendar.HOUR_OF_DAY, 0);   
  20.     calendar.set(Calendar.MINUTE, 0);   
  21.     calendar.set(Calendar.SECOND, 0);  
  22.  
  23. }  
  24.  

解法3:

  1. SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");   
  2. java.util.Date date= myFormatter.parse("2003-05-1");    
  3. java.util.Date mydate= myFormatter.parse("1899-12-30");   
  4. long  day=(date.getTime()-mydate.getTime())/(24*60*60*1000);   
  5. out.println(day);  
  6.  

上面的解法思想都一样,都是忽略的时分秒,相比之下,第一种方法最为简单,可是这些都是每月按30天计算的,自然月计算的方法系统API中没有,总不至于为了使用这个方法,去引用开源的库吧,但是这个问题的处理逻辑也是很复杂的,要考虑的因素很多,往往测试的时候,发现某种特例计算的结果不正确,煞为恼火,Java真不给力~~

基本上花了一下午的时间,去分析,然后画了流程图,写成代码,可能水平有限,方法虽然笨拙,但是还是能用的,如有不正确的地方,欢迎大家指正,也期待有更加简单巧妙的方法。

 

breezy

相应代码:

  1. public static int[] getNeturalAge(Calendar calendarBirth,Calendar calendarNow) { 
  2. int diffYears = 0, diffMonths, diffDays; 
  3. int dayOfBirth = calendarBirth.get(Calendar.DAY_OF_MONTH); 
  4. int dayOfNow = calendarNow.get(Calendar.DAY_OF_MONTH); 
  5. if (dayOfBirth <= dayOfNow) { 
  6. diffMonths = getMonthsOfAge(calendarBirth, calendarNow); 
  7. diffDays = dayOfNow - dayOfBirth; 
  8. if (diffMonths == 0
  9. diffDays++; 
  10. else { 
  11. if (isEndOfMonth(calendarBirth)) { 
  12. if (isEndOfMonth(calendarNow)) { 
  13. diffMonths = getMonthsOfAge(calendarBirth, calendarNow); 
  14. diffDays = 0
  15. else { 
  16.                     calendarNow.add(Calendar.MONTH, -1); 
  17. diffMonths = getMonthsOfAge(calendarBirth, calendarNow); 
  18. diffDays = dayOfNow + 1
  19. else { 
  20. if (isEndOfMonth(calendarNow)) { 
  21. diffMonths = getMonthsOfAge(calendarBirth, calendarNow); 
  22. diffDays = 0
  23. else { 
  24.                     calendarNow.add(Calendar.MONTH, -1);// 上个月 
  25. diffMonths = getMonthsOfAge(calendarBirth, calendarNow); 
  26. // 获取上个月最大的一天 
  27. int maxDayOfLastMonth = calendarNow         .getActualMaximum(Calendar.DAY_OF_MONTH); 
  28. if (maxDayOfLastMonth > dayOfBirth) { 
  29. diffDays = maxDayOfLastMonth - dayOfBirth + dayOfNow; 
  30. else { 
  31. diffDays = dayOfNow; 
  32. // 计算月份时,没有考虑年 
  33. diffYears = diffMonths / 12
  34. diffMonths = diffMonths % 12
  35. return new int[] { diffYears, diffMonths, diffDays }; 
  1. /**  
  2. * 获取两个日历的月份之差  
  3.  
  4. * @param calendarBirth  
  5. * @param calendarNow  
  6. * @return  
  7. */ 
  8. public static int getMonthsOfAge(Calendar calendarBirth,  
  9. Calendar calendarNow) {  
  10. return (calendarNow.get(Calendar.YEAR) - calendarBirth  
  11. .get(Calendar.YEAR))* 12+ calendarNow.get(Calendar.MONTH)  
  12. - calendarBirth.get(Calendar.MONTH);  
  13.     } 
  1. /**  
  2. * 判断这一天是否是月底  
  3.  
  4. * @param calendar  
  5. * @return  
  6. */ 
  7. public static boolean isEndOfMonth(Calendar calendar) {  
  8. int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);  
  9. if (dayOfMonth == calendar.getActualMaximum(Calendar.DAY_OF_MONTH))  
  10. return true;  
  11. return false;  
  12.     } 

如果你有更好的方法,欢迎探讨:-)

本文出自 “超越梦想” 博客,请务必保留此出处http://breezy.blog.51cto.com/2400264/451353

分享到:
评论

相关推荐

    java实现两个时间相差的年月日 (相差几年几天几日的结果)

    网上很多资源都没有输出结果是(相差几年几个月几天的代码)希望对大家有帮助 有不足地方 望大家多多指点

    java计算两个时间相差月数

    java计算两个时间(yyyy-MM-dd HH:mm:ss)相差月数两个时间格式可为年月日时分秒

    Java编程输入两个年月日,(1)判断两个日期是否相同,并且将相差的天数显示出来;(2)将日期后推或前推N天,并将该日期输出。

    综上所述,这个Java程序主要实现了两个功能:一是判断两个给定日期是否相同及计算它们之间的天数差;二是将给定日期向前或向后调整一定数量的天数。程序的核心是`DateType`类的设计与实现,它包含了日期的创建、打印...

    java日期,时间工具类

    各种日期格式,时间戳,时间计算的相互转换。直接引入工程中,可使用

    计算两日期的时间差

    计算两日期之间的时间差,输入两个年月日 计算相差天数

    java 两个日期的所有天

    可以列出两个日期中间的所有天 20090501, 20090502, 20090503, 20090504, 20090505, 20090506, 20090507, 20090508, 20090509,

    计算两个时间相差几年几月

    用于计算两个时间的差值,非常实用!

    Java日期工具类

    16、计算传入的两个日期之间相差的天数 17、根据传入的年月返回该月的第一天 18、根据传入的年月返回该月最后的一天 19、获得当前月份的第一天 20、获得当前月份的最后一天 21、获取上月的第一天 22、获取上月的最后...

    JAVA日期计算程序

    日期计算程序。 1、由用户输入一个月份,屏幕上输出这个月的月历,每星期一行,从星期日开始,到星期六结束。 2、由用户输入一个日期,屏幕上回答是星期几。...3、由用户输入二个日期,计算这两个日期之间相差多少天。

    计算天数 java练习

    `LocalDate`类用于表示没有时区信息的日期,`Period`类则用于表示两个日期之间的差值(包括年、月、日): ```java LocalDate startDate = LocalDate.of(2020, 1, 1); LocalDate endDate = LocalDate.of(2020, 12, ...

    最全Java常用日期处理工具类

    7.两个时间相差距离多少天多少小时多少分多少秒 8.按默认格式的字符串距离今天的天数 9.比较两个时间的大小 HH:mm:ss 10.按用户格式字符串距离今天的天数 11.cron "0 06 10 15 1 ? 2014" 专门用于处理...

    常用的java日期比较和日期计算方法小结

    计算两个日期之间相差的天数,可以通过`java.util.Calendar`类来实现。首先将字符串转换为日期,然后获取每个日期对应的毫秒值,相减得到的差值除以一天的毫秒数(1000 * 60 * 60 * 24)即可。示例如下: ```java ...

    Java中使用period和duration计算时间差

    在 Java 中,计算时间差可以使用 Period 和 Duration 两个类,它们都是不可变的、线程安全的。下面是对这两个类的详细介绍和使用示例。 Period 类 Period 类用于计算两个日期之间的时间差,最高精度为天。它可以...

    判断两个时间段的时间差

    java时间差代码,可以轻松判断两个时间段之间相差多少天

    java处理日期、时间的类

    根据生日计算年龄,只精确到日期 接受Calendar类型的日期数据,计算天数差 获取当前日期,格式化成yyyy-MM-dd 获取当前日期,格式化成yyyy-MM-dd HH:mm:ss ...接受Date类型的日期参数,返回两个日期相差的天数

    Java获取时间差(天数差,小时差,分钟差)代码示例

    Java获取时间差是指计算两个时间点之间的时间间隔, Java中可以使用SimpleDateFormat类来实现时间差的计算。在Java中,时间差可以分为天数差、小时差、分钟差等。下面将对Java获取时间差的代码示例进行详细讲解。 ...

    时间处理常用java

    最后,可以使用`Calendar`类来计算两个日期之间相差的天数: ```java public int getIntervalDays(Calendar startDay, Calendar endDay) { if (startDay.after(endDay)) { Calendar temp = startDay; startDay = ...

    日期求差代码

    本文详细介绍了“日期求差代码”中的核心知识点,包括闰年的判断、日期的比较、日期的加法以及计算两个日期之间相差的天数。这些方法共同构成了一个完整的日期处理工具包,可以方便地应用于需要进行日期计算的各种...

    Java常用工具类(免费)

    接收两个日期字符串作为参数,计算这两个日期之间的天数差。 ##### 10. 获得当前时间(年月日 时分秒):`getCurrentDateTime` 返回当前时间的具体格式,包括年月日及时分秒等信息。 ##### 11. 根据日期获取星座: ...

    J2EE系统中日期时间的处理方法.pdf

    1. **日期时间类**:`java.util.Date` 和 `java.sql.Timestamp` 是用来表示日期时间的两个主要类。`java.util.Date` 应用于大多数场合,而`java.sql.Timestamp` 主要在数据库交互中使用。 2. **时区类**:`java....

Global site tag (gtag.js) - Google Analytics