8000 - Tweaked logic in the getMonthsBetween() method in the Date class · javaxt-project/javaxt-core@0ff9ea4 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0ff9ea4

Browse files
committed
- Tweaked logic in the getMonthsBetween() method in the Date class
git-svn-id: svn://192.168.0.80/JavaXT/javaxt-core@1604 2c7b0aa6-e0b2-3c4e-bb4a-8b65b6c465ff
1 parent 2f4ad07 commit 0ff9ea4

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

src/javaxt/utils/Date.java

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)
0