当前位置: 首页 > news >正文

Java 实现 Oracle 的 MONTHS_BETWEEN 函数

介绍

因为系统迁移, 有一些函数要转成 Java 版本, Oracle 的

官方介绍 - MONTHS_BETWEEN

MONTHS_BETWEEN returns number of months between dates date1 and date2. The month and the last day of the month are defined by the parameter NLS_CALENDAR. 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.

翻译
MONTHS_BETWEEN返回日期date1和日期date2之间的月数。月份和月份的最后一天由参数NLS_CALENDAR定义。如果date1晚于date2,则结果为正。如果date1早于date2,则结果为负。如果date1和date2是同一个月的同一天,或者都是同一个月的最后一天,那么结果总是一个整数。否则,Oracle数据库根据31天的月份计算结果的小数部分,并考虑时间组件date1和date2的差异。

Java 代码

    /*** 计算两个日期之间的月份差值,精确到小数点.* 逻辑参考 Oracle 的 MONTHS_BETWEEN 函数.由于函数的特殊性,两个日期的格式尽可能规整为 YYYY-MM-DD 格式,会忽略时分秒** <pre>* select MONTHS_BETWEEN('2019-01-31', '2019-02-28') from dual;* </pre>** @param startDate 开始日期* @param endDate   结束日期* @return 月份差值*/public static double monthsBetween(Date startDate, Date endDate) {// 将旧版Date转换为Instant,然后调整到系统默认时区并转换为LocalDateTimeLocalDateTime dateTime1 = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();LocalDateTime dateTime2 = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();// 确保dateTime1 >= dateTime2,若否则交换并取负数if (dateTime1.isBefore(dateTime2)) {return -monthsBetween(endDate, startDate);}LocalDate date1 = dateTime1.toLocalDate();LocalDate date2 = dateTime2.toLocalDate();// 判断是否为月末boolean isDate1EndOfMonth = date1.equals(date1.withDayOfMonth(date1.lengthOfMonth()));boolean isDate2EndOfMonth = date2.equals(date2.withDayOfMonth(date2.lengthOfMonth()));// 计算年月日差值int yearDiff = date1.getYear() - date2.getYear();int monthDiff = date1.getMonthValue() - date2.getMonthValue();int dayDiff = date1.getDayOfMonth() - date2.getDayOfMonth();// 核心计算逻辑 - 月份部分double totalMonths = yearDiff * 12 + monthDiff;// 处理天数部分if (isDate1EndOfMonth && isDate2EndOfMonth) {// 若均为月末,天数差清零dayDiff = 0;}// 核心计算逻辑 - 天数部分 Oracle按31天计算日占比totalMonths += dayDiff / 31.0;// 处理时间部分Duration duration = Duration.between(dateTime2.toLocalTime(), dateTime1.toLocalTime());long hours = duration.toHours();long minutes = duration.toMinutes() % 60;long seconds = duration.getSeconds() % 60;// 核心计算逻辑 - 时分秒部分 将时分钟秒转换为月的比例 Oracle按31天744小时计算double timeAsMonth = hours / 744.0 + minutes / (744.0 * 60) + seconds / (744.0 * 60 * 60);// 处理位数为小数点后14位. Oracle 默认小数点后14位return Math.round((totalMonths + timeAsMonth) * 100000000000000.0) / 100000000000000.0;}

单元测试

@Test
void monthsBetween() {/*selectmonths_between(to_date('2025-01-07 01:12:41', 'yyyy-mm-dd hh24:mi:ss'), to_date('2025-03-09 11:22:48', 'yyyy-mm-dd hh24:mi:ss')) as "-2.07818361708483",months_between(to_date('2025-02-27 01:12:41', 'yyyy-mm-dd hh24:mi:ss'), to_date('2025-06-01 21:22:48', 'yyyy-mm-dd hh24:mi:ss')) as "-3.18839867084827",months_between(to_date('2025-03-17 01:12:41', 'yyyy-mm-dd hh24:mi:ss'), to_date('2025-05-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')) as "-1.48224275686977"from dual*/log.info("计算月份差: {}", DateUtils.monthsBetween(DateUtils.parse("2025-01-07 01:12:41", "yyyy-MM-dd HH:mm:ss"), DateUtils.parse("2025-03-09 11:22:48", "yyyy-MM-dd HH:mm:ss")));log.info("计算月份差: {}", DateUtils.monthsBetween(DateUtils.parse("2025-02-27 01:12:41", "yyyy-MM-dd HH:mm:ss"), DateUtils.parse("2025-06-01 21:22:48", "yyyy-MM-dd HH:mm:ss")));log.info("计算月份差: {}", DateUtils.monthsBetween(DateUtils.parse("2025-03-17 01:12:41", "yyyy-MM-dd HH:mm:ss"), DateUtils.parse("2025-05-01 00:00:00", "yyyy-MM-dd HH:mm:ss")));
}

相关文章:

Java 实现 Oracle 的 MONTHS_BETWEEN 函数

介绍 因为系统迁移, 有一些函数要转成 Java 版本, Oracle 的 官方介绍 - MONTHS_BETWEEN MONTHS_BETWEEN returns number of months between dates date1 and date2. The month and the last day of the month are defined by the parameter NLS_CALENDAR. If date1 is late…...

windows下使用msys2编译ffmpeg

三种方法&#xff1a; 1、在msys2中使用gcc编译 2、在msys2中使用visual studio编译&#xff08;有环境变量&#xff09; 3、在msys2中使用visual studio编译&#xff08;无环境变量&#xff09; 我的环境&#xff1a; 1、msys2-x86_64-20250221 2、vs2015 3、ffmpeg-7.1…...

Vivado常用的时序约束方法

1,create_clock :创建时钟约束 create_clock -period 20.000 -name sys_clk [get_ports sys_clk 该约束含义是创建一个时钟周期20ns的时钟,时钟名字为sys_clk。注意:如果是差分时钟,只需要约束差分时钟的P端,N端不用约束。 2,set_clock_uncertainty:设置时钟不确定性 s…...

力扣HOT100之哈希:1. 两数之和

这道题之前刷代码随想录的时候已经刷过好几遍了&#xff0c;看到就直接秒了。这道题主要是通过unordered_map<int, int>来建立哈希表&#xff0c;其中键用来保存向量中的元素&#xff0c;而对应的值则为元素的下标。遍历整个向量&#xff0c;当遍历到nums[i]时&#xff0…...

如何在rust中解析 windows 的 lnk文件(快捷方式)

一、从标题二开始看&#x1f601; 这些天在使用rust写一个pc端应用程序&#xff0c;需要解析lnk文件获取lnk的图标以及原程序地址&#xff0c;之前并没有过pc端应用程序开发的经验&#xff0c; 所以在广大的互联网上游荡了两天。额&#x1f97a; 今天找到了这个库 lnk_parse很…...

豆包大模型 MarsCode AI 刷题专栏 001

001.找单独的数 难度&#xff1a;易 问题描述 在一个班级中&#xff0c;每位同学都拿到了一张卡片&#xff0c;上面有一个整数。有趣的是&#xff0c;除了一个数字之外&#xff0c;所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上…...

python语言总结(持续更新)

本文主要是总结各函数&#xff0c;简单的函数不会给予示例&#xff0c;如果在平日遇到一些新类型将会添加 基础知识 输入与输出 print([要输出的内容])输出函数 input([提示内容]如果输入提示内容会在交互界面显示&#xff0c;用以提示用户)输入函数 注释 # 单行注释符&…...

leetcode15 三数之和

1.哈希法 为了避免重复 class Solution { public:vector<vector<int>> threeSum(vector<int>& nums) {set<vector<int>> temple;//使用 set 来存储符合条件的三元组&#xff0c;避免重复vector<vector<int>> out;//存放最终输…...

深入探讨AI-Ops架构 第一讲 - 运维的进化历程以及未来发展趋势

首先&#xff0c;让我们一起回顾运维的进化之路&#xff0c;然后再深入探讨AI-Ops架构的细节。 运维的进化历程 1. AI 大范围普及前的运维状态 (传统运维) 在AI技术尚未广泛渗透到运维领域之前&#xff0c;我们称之为传统运维&#xff0c;其主要特点是&#xff1a; 人工驱动…...

Android Native 之 文件系统挂载

一、文件系统挂载流程概述 二、文件系统挂载流程细节 1、Init启动阶段 众所周知&#xff0c;init进程为android系统的第一个进程&#xff0c;也是native世界的开端&#xff0c;要想让整个android世界能够稳定的运行&#xff0c;文件系统的创建和初始化是必不可少的&#xff…...

常用word python matlab快捷键

这里写自定义目录标题 WordMatlabpythonlinuxWord Matlab 1 结构体 字符串成员做索引,必须()类似python* 解包作用,转化字符串到属性类型 如果属性名存入列表 a = [“para1”] 比如stru1.para1 = [‘c’,‘d’]; 那么若要用a中para1来索引,必须要加圆括号; ==》 X Strut…...

MySQL------存储引擎和用户和授权

9.存储引擎 1.两种引擎 MyISAM和InnoDB 2.两种区别 1.事务&#xff1a; MyISAM不支持事务 2.存储文件: innodb : frm、ibd MyISAM: frm、MYD、MYI 3.数据行锁定: MyISAM不支持 4.全文索引: INNODB不支持&#xff0c;所以MYISAM做select操作速度很快 5.外键约束: MyISAM…...

react拖曳组件react-dnd的简单封装使用

分享原因 由于项目中需要使用拖曳组件(需求:全局&#xff0c;跨组件&#xff0c;跨数据)&#xff0c;我选择了react-dnd 概念 React DnD 是一组 React 高阶组件&#xff0c;我们在使用的时候只需要将目标元素进行包裹&#xff0c;就可以实现目标元素具有拖动或接受拖动的功能。…...

Excel中COUNTIF用法解析

COUNTIF 是 Excel 中一个非常实用的函数&#xff0c;用于统计满足某个条件的单元格数量。它的基本语法如下&#xff1a; 基本语法 COUNTIF(范围, 条件) 范围&#xff1a;需要统计的单元格区域&#xff0c;例如 A1:A10 或整列 A:A。 条件&#xff1a;用于判断哪些单元格需要被…...

Uniapp 页面返回不刷新?两种方法防止 onShow 触发多次请求!

目录 前言1. 变量&#xff08;不生效&#xff09;2. 延迟&#xff08;生效&#xff09; 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 在 Uniapp 中&#xff0c;使用 onShow() 钩子来监听页面显示&#xff0…...

《论数据湖技术及其应用》审题技巧 - 系统架构设计师

论题写作框架 一、考点概述 “数据湖技术及其应用”这一论题主要考察的是软件测试工程师对于前沿数据存储与处理技术的理解及其在软件开发项目中的实际应用能力。具体而言&#xff0c;该论题涵盖了以下几个核心考点&#xff1a; 软件项目管理与开发经验 &#xff1a;要求考生…...

C++蓝桥杯基础篇(八)

片头 嗨~小伙伴们&#xff0c;大家好&#xff01;今天我们一起来学习C蓝桥杯基础篇&#xff08;八&#xff09;&#xff0c;练习相关字符串的习题&#xff0c;准备好了吗&#xff1f;Are you ready? Lets go! 第1题 字符串中的数字个数 这道题&#xff0c;我们用字符数组或者…...

AI 实战 - pytorch框架基于retinaface实现face检测

pytorch框架基于retinaface实现face检测 简介模型结构MobileNet-0.25SSH结构Head结构 Anchor编解码 环境开发环境 数据简介 训练测试参考 简介 RetinaFace是在RetinaNet基础上引申出来的人脸检测框架&#xff0c;所以大致结构和RetinaNet非常像。 主要改进&#xff1a;1.Mobi…...

如何在PHP中实现API版本管理:保持向后兼容性

如何在PHP中实现API版本管理&#xff1a;保持向后兼容性 在现代Web开发中&#xff0c;API&#xff08;应用程序编程接口&#xff09;是连接前端和后端的关键桥梁。随着业务需求的不断变化&#xff0c;API的版本管理变得尤为重要。良好的版本管理策略不仅能够确保新功能的顺利引…...

Docker Compose企业示例

利用容器编排完成haproxy和nginx负载均衡架构实施 1.mkdir docker.test 2.touch haproxy.yml 3.mkdir /var/lib/docker/volumes/conf 4.dnf install haproxy -y --downloadonly --downloaddir/xixi&#xff1a;下载内容到/xixi目录下 5. rpm2cpio haproxy-2.4.22-4.el9.x8…...

在openKylin下安装配置GitLab遇到的问题及解决方案(v0.1.0)

作者&#xff1a;沈传越 明德融创工作室&#xff08;Minter Fusion Studio, MFS&#xff09; 出品 本文安装的GitLab-ce 15.10.0版。操作系统openKylin 2.0 SP2。 一、安装GitLab-ce依赖软件时报错 1. 错误描述 在执行sudo apt-get install curl openssh-server ca-certifi…...

微信小程序集成通义千问:打造悬浮窗智能对话助手

1. 为什么要在微信小程序里集成通义千问&#xff1f; 最近两年AI对话助手火得一塌糊涂&#xff0c;但大部分应用都是独立APP或者网页版。其实对于很多轻量级场景来说&#xff0c;直接在微信小程序里集成AI助手反而更实用。想象一下&#xff0c;当你在小程序里购物遇到问题时&am…...

SegFormer源码解读:从注意力机制到特征融合的实现细节

SegFormer源码解读&#xff1a;从注意力机制到特征融合的实现细节 【免费下载链接】SegFormer Official PyTorch implementation of SegFormer 项目地址: https://gitcode.com/gh_mirrors/se/SegFormer SegFormer是一个基于Transformer的语义分割模型&#xff0c;它通过…...

三步解锁wxappUnpacker:从小白到高手的蜕变指南

三步解锁wxappUnpacker&#xff1a;从小白到高手的蜕变指南 【免费下载链接】wxappUnpacker 项目地址: https://gitcode.com/gh_mirrors/wxappu/wxappUnpacker 工具定位&#xff1a;小程序逆向工程的瑞士军刀 wxappUnpacker是一款专注于微信小程序解包的开源工具集&am…...

从‘飞到红色建筑左边’说起:拆解无人机视觉语言导航(VLN)背后的三大工程难题

从"飞到红色建筑左边"说起&#xff1a;拆解无人机视觉语言导航的工程化困局 当你在测试场地对无人机说出"飞到红色建筑左边"时&#xff0c;这个看似简单的指令背后&#xff0c;是一场跨越模态鸿沟的复杂解码过程。不同于实验室里的完美演示&#xff0c;真实…...

Modbus转EtherCAT网关开发秘笈:用AX58100实现120个命令自动映射(Web配置全图解)

Modbus转EtherCAT网关开发实战&#xff1a;AX58100零代码配置与工业部署全指南 工业自动化领域正经历着从传统串行通信向实时以太网协议的转型浪潮。作为这场变革的核心枢纽&#xff0c;协议转换网关的性能直接决定了整个系统的响应速度和稳定性。本文将深入探讨如何利用AX5810…...

Qwen3-ASR-1.7B服务管理技巧:使用Supervisor监控与重启服务

Qwen3-ASR-1.7B服务管理技巧&#xff1a;使用Supervisor监控与重启服务 当你把Qwen3-ASR-1.7B语音识别模型部署到服务器上&#xff0c;准备让它7x24小时稳定工作时&#xff0c;有没有遇到过这样的问题&#xff1a; 半夜服务突然挂了&#xff0c;第二天早上才发现&#xff0c;…...

零基础玩转OpenClaw:nanobot镜像入门10个实用命令

零基础玩转OpenClaw&#xff1a;nanobot镜像入门10个实用命令 1. 认识nanobot镜像 第一次接触OpenClaw时&#xff0c;我被它"让AI直接操作电脑"的理念吸引&#xff0c;但本地部署的复杂环境配置让我望而却步。直到发现nanobot这个超轻量级镜像&#xff0c;内置了Qw…...

MoE大模型入门指南:小白也能掌握的AI核心技术(收藏学习)

混合专家模型&#xff08;Mixture-of-Experts&#xff0c; MoE&#xff09;是机器学习和深度学习中的一种流行架构&#xff0c;目前被广泛应用于大模型领域。MoE的基本原理是通过门控&#xff08;Gating&#xff09;机制&#xff0c;加权集成各专家&#xff08;Experts&#xf…...

如何在浏览器中免安装使用微信?这个开源插件给你答案!

如何在浏览器中免安装使用微信&#xff1f;这个开源插件给你答案&#xff01; 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 你是否曾经遇到过这样的…...