Analog of ORACLE function MONTHS_BETWEEN in Java

后端 未结 8 543
时光说笑
时光说笑 2021-01-12 09:56

Does Java have some analog of Oracle\'s function MONTHS_BETWEEN?

8条回答
  •  难免孤独
    2021-01-12 10:19

    I had to migrate some Oracle code to java and haven't found the analog for months_between oracle function. While testing listed examples found some cases when they produce wrong results.

    So, created my own function. Created 1600+ tests comparing results of db vs my function, including dates with time component - all work fine.

    Hope, this can help someone.

    public static double oracle_months_between(Timestamp endDate,Timestamp startDate) {
    
        //MONTHS_BETWEEN returns number of months between dates date1 and date2.
        // If date1 is later than date2, then the result is positive.
        // If date1 is earlier than date2, then the result is negative.
        // If date1 and date2 are either the same days of the month or both last days of months, then the result is always an integer.
        // Otherwise Oracle Database calculates the fractional portion of the result based on a 31-day month and considers the difference in time components date1 and date2.
    
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String endDateString = sdf.format(endDate), startDateString = sdf.format(startDate);
    
        int startDateYear = Integer.parseInt(startDateString.substring(0,4)), startDateMonth = Integer.parseInt(startDateString.substring(5,7)), startDateDay = Integer.parseInt(startDateString.substring(8,10));
        int endDateYear = Integer.parseInt(endDateString.substring(0,4)), endDateMonth = Integer.parseInt(endDateString.substring(5,7)), endDateDay = Integer.parseInt(endDateString.substring(8,10));
    
        boolean endDateLDM = is_last_day(endDate), startDateLDM = is_last_day(startDate);
    
        int diffMonths = -startDateYear*12 - startDateMonth + endDateYear * 12 + endDateMonth;
    
        if (endDateLDM && startDateLDM || extract_day(startDate) == extract_day(endDate)){
            // If date1 and date2 are either the same days of the month or both last days of months, then the result is always an integer.
            return (double)(diffMonths);
        }
    
        double diffDays = (endDateDay - startDateDay)/31.;
    
        Timestamp dStart = Timestamp.valueOf("1970-01-01 " + startDateString.substring(11)), dEnd = Timestamp.valueOf("1970-01-01 " + endDateString.substring(11));
    
        return diffMonths + diffDays + (dEnd.getTime()-dStart.getTime())/1000./3600./24./31.;
    }
    
    public static boolean is_last_day(Timestamp ts){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(ts);
        int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        return max == Integer.parseInt((new SimpleDateFormat("dd").format(ts)));
    }
    

提交回复
热议问题