@@ -708,9 +708,44 @@ private long diff(java.util.Date date1, java.util.Date date2, String interval){
708708 //**************************************************************************
709709 //** getMonthsBetween
710710 //**************************************************************************
711- /** Returns fractional month difference between two dates. Unlike the
712- * compareTo() method, this function does not round down the difference
713- * between two months.
711+ /** Returns fractional month difference between two dates. This method will
712+ * return whole numbers (1, 2, 3, etc) if the two dates fall on the same
713+ * day of the month (e.g. "2023-03-01" v "2023-04-01" or "2023-03-14" v
714+ * "2023-04-14"). Returns a decimal value less than or equal to 1 (<=1)
715+ * if the dates fall within the same month (e.g. "2024-01-01" v "2024-01-31"
716+ * yields 1.0 and "2024-01-01" v "2024-01-30" yields 0.968). Otherwise,
717+ * returns the number of full months between the two dates plus a
718+ * fractional value (e.g. "2023-01-27" v "2023-02-28" yields 1.0357). The
719+ * decimal value (numbers after the decimal point) represent fractions of a
720+ * month. Roughly speaking, a day is 0.03 of a month.
721+ *
722+ * <p/>
723+ *
724+ * There are some interesting results when comparing dates around the end
725+ * of two different months. Specifically when comparing a longer month to
726+ * shorter month. For example:
727+ * <ul>
728+ * <li>"2024-01-31" v "2024-02-29" = 1 month</li>
729+ * <li>"2023-01-31" v "2023-02-28" = 1 month</li>
730+ * <li>"2023-12-31" v "2024-02-29" = 2 months</li>
731+ * <li>"2022-12-31" v "2023-02-29" = 2 months</li>
732+ * </ul>
733+ * In these examples we are following semantic rules and are rounding down
734+ * the differences. However, when we compare dates around the end of two
735+ * different months if the start month is shorter, we don't round. Example:
736+ * <ul>
737+ * <li>"2024-04-30" v "2024-05-31" = 1 month, 1 day</li>
738+ * <li>"2023-02-28" v "2024-02-29" = 12 months, 1 day</li>
739+ * </ul>
740+ *
741+ * In these examples you can see that we are following semantic rules
742+ * rather than straight math.
743+ *
744+ * <p/>
745+ *
746+ * Note that you can use the compareTo() method to compare months using the
747+ * Java standard which rounds down the difference between two months and
748+ * does not return fractions.
714749 */
715750 public static double getMonthsBetween (javaxt .utils .Date start , javaxt .utils .Date end ) {
716751 return getMonthsBetween (start .getLocalDate (), end .getLocalDate ());
@@ -762,7 +797,7 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
762797 if (m ==0 && start .getMonthValue ()==end .getMonthValue ()){
763798
764799 //Simply compare the days of the month
765- fraction = (end .getDayOfMonth ()-start .getDayOfMonth ())/(double )end .lengthOfMonth ();
800+ fraction = (end .getDayOfMonth ()-( start .getDayOfMonth ()- 1 ))/(double )end .lengthOfMonth ();
766801
767802 }
768803 else {
@@ -778,7 +813,7 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
778813 //Create new date a few days after the end of the month
779814 LocalDate d = e2 .plusDays (start .getDayOfMonth ()-maxDays );
780815
781- //Calulate months between the start date and the new date
816+ //Calculate months between the start date and the new date
782817 m = ChronoUnit .MONTHS .between (start , d );
783818
784819 //Calculate fraction
@@ -795,7 +830,7 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
795830 }
796831 else {
797832
798- //Calulate months between the start date and the new end date
833+ //Calculate months between the start date and the new end date
799834 m = ChronoUnit .MONTHS .between (start , e2 );
800835
801836 //Calculate fraction
@@ -816,7 +851,9 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
816851 else if (e2 .isBefore (end )){
817852
818853 //add from e2
819- fraction = (end .getDayOfMonth ()-start .getDayOfMonth ())/(double )end .lengthOfMonth ();
854+ int x = start .getDayOfMonth ()==1 ? 1 : 0 ;
855+
856+ fraction = (end .getDayOfMonth ()-(start .getDayOfMonth ()-x ))/(double )end .lengthOfMonth ();
820857
821858 }
822859 }
@@ -828,7 +865,7 @@ else if (e2.isBefore(end)){
828865
829866
830867 //When the 2 dates fall on the the last day of the month, round up
831- if (startIsLastDayInMonth && endIsLastDayInMonth ){
868+ if (( startIsLastDayInMonth && endIsLastDayInMonth ) && ( start . getMonthValue ()> end . getMonthValue ()) ){
832869 diff = Math .round (diff );
833870 }
834871
0 commit comments