@@ -708,9 +708,44 @@ private long diff(java.util.Date date1, java.util.Date date2, String interval){
708
708
//**************************************************************************
709
709
//** getMonthsBetween
710
710
//**************************************************************************
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.
714
749
*/
715
750
public static double getMonthsBetween (javaxt .utils .Date start , javaxt .utils .Date end ) {
716
751
return getMonthsBetween (start .getLocalDate (), end .getLocalDate ());
@@ -762,7 +797,7 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
762
797
if (m ==0 && start .getMonthValue ()==end .getMonthValue ()){
763
798
764
799
//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 ();
766
801
767
802
}
768
803
else {
@@ -778,7 +813,7 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
778
813
//Create new date a few days after the end of the month
779
814
LocalDate d = e2 .plusDays (start .getDayOfMonth ()-maxDays );
780
815
781
- //Calulate months between the start date and the new date
816
+ //Calculate months between the start date and the new date
782
817
m = ChronoUnit .MONTHS .between (start , d );
783
818
784
819
//Calculate fraction
@@ -795,7 +830,7 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
795
830
}
796
831
else {
797
832
798
- //Calulate months between the start date and the new end date
833
+ //Calculate months between the start date and the new end date
799
834
m = ChronoUnit .MONTHS .between (start , e2 );
800
835
801
836
//Calculate fraction
@@ -816,7 +851,9 @@ private static double getMonthsBetween(LocalDate start, LocalDate end) {
816
851
else if (e2 .isBefore (end )){
817
852
818
853
//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 ();
820
857
821
858
}
822
859
}
@@ -828,7 +865,7 @@ else if (e2.isBefore(end)){
828
865
829
866
830
867
//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 ()) ){
832
869
diff = Math .round (diff );
833
870
}
834
871
0 commit comments