Flowable的DurationHelper时间计算工具类

2023-11-03

Flowable的DurationHelper时间计算工具类

PnYnMnDTnHnMnS时间规则

Obtain a new instance of a Duration specifying the Duration as its string representation, “PnYnMnDTnHnMnS”, as defined in XML Schema 1.0 section 3.2.6.1.

规则 示例 说明
PnY P1Y 1年以后
PnM P1M 1个月以后
PnD P1D 1天以后
PnD P1D 1天以后
PTnH PT1H 1小时以后
PTnM PT1M 1分钟以后
PTnS PT1S 1一秒钟以后

DurationHelper工具类

package org.flowable.common.engine.impl.calendar;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;

import org.flowable.common.engine.api.FlowableIllegalArgumentException;
import org.flowable.common.engine.impl.runtime.ClockReader;
import org.flowable.common.engine.impl.util.TimeZoneUtil;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;

/**
 * Helper class for parsing ISO8601 duration format (also recurring) and computing next timer date.
 */
public class DurationHelper {

    protected static DateFormat DATE_FORMAT = new SimpleDateFormat("EEE MMM dd kk:mm:ss z yyyy");

    private Calendar start;
    private Calendar end;
    private Duration period;
    private boolean isRepeat;
    private int times;
    private int maxIterations = -1;
    private boolean repeatWithNoBounds;

    private DatatypeFactory datatypeFactory;

    public Calendar getStart() {
        return start;
    }

    public Calendar getEnd() {
        return end;
    }

    public Duration getPeriod() {
        return period;
    }

    public boolean isRepeat() {
        return isRepeat;
    }

    public int getTimes() {
        return times;
    }

    protected ClockReader clockReader;

    public DurationHelper(String expressionS, int maxIterations, ClockReader clockReader) throws Exception {
        this.clockReader = clockReader;
        this.maxIterations = maxIterations;
        List<String> expression = Arrays.asList(expressionS.split("/"));
        datatypeFactory = DatatypeFactory.newInstance();

        if (expression.size() > 3 || expression.isEmpty()) {
            throw new FlowableIllegalArgumentException("Cannot parse duration");
        }
        if (expression.get(0).startsWith("R")) {
            isRepeat = true;
            times = expression.get(0).length() == 1 ? Integer.MAX_VALUE - 1 : Integer.parseInt(expression.get(0).substring(1));

            if (expression.get(0).equals("R")) { // R without params
                repeatWithNoBounds = true;
            }

            expression = expression.subList(1, expression.size());
        }

        if (isDuration(expression.get(0))) {
            period = parsePeriod(expression.get(0));
            end = expression.size() == 1 ? null : parseDate(expression.get(1));
        } else {
            start = parseDate(expression.get(0));
            if (isDuration(expression.get(1))) {
                period = parsePeriod(expression.get(1));
            } else {
                end = parseDate(expression.get(1));
                period = datatypeFactory.newDuration(end.getTimeInMillis() - start.getTimeInMillis());
            }
        }
        if (start == null) {
            start = clockReader.getCurrentCalendar();
        }

    }

    public DurationHelper(String expressionS, ClockReader clockReader) throws Exception {
        this(expressionS, -1, clockReader);
    }

    public Calendar getCalendarAfter() {
        return getCalendarAfter(clockReader.getCurrentCalendar());
    }

    public Calendar getCalendarAfter(Calendar time) {
        if (isRepeat) {
            return getDateAfterRepeat(time);
        }
        // TODO: is this correct?
        if (end != null) {
            return end;
        }
        return add(start, period);
    }

    public Boolean isValidDate(Date newTimer) {
        return end == null || end.getTime().after(newTimer) || end.getTime().equals(newTimer);
    }

    public Date getDateAfter() {
        Calendar date = getCalendarAfter();

        return date == null ? null : date.getTime();
    }

    private Calendar getDateAfterRepeat(Calendar date) {
        Calendar current = TimeZoneUtil.convertToTimeZone(start, date.getTimeZone());

        if (repeatWithNoBounds) {

            while (current.before(date) || current.equals(date)) { // As long as current date is not past the engine date, we keep looping
                Calendar newTime = add(current, period);
                if (newTime.equals(current) || newTime.before(current)) {
                    break;
                }
                current = newTime;
            }

        } else {

            int maxLoops = times;
            if (maxIterations > 0) {
                maxLoops = maxIterations - times;
            }
            for (int i = 0; i < maxLoops + 1 && !current.after(date); i++) {
                current = add(current, period);
            }

        }
        return current.before(date) ? date : TimeZoneUtil.convertToTimeZone(current, clockReader.getCurrentTimeZone());

    }

    protected Calendar add(Calendar date, Duration duration) {
        Calendar calendar = (Calendar) date.clone();

        // duration.addTo does not account for daylight saving time (xerces),
        // reversing order of addition fixes the problem
        calendar.add(Calendar.SECOND, duration.getSeconds() * duration.getSign());
        calendar.add(Calendar.MINUTE, duration.getMinutes() * duration.getSign());
        calendar.add(Calendar.HOUR, duration.getHours() * duration.getSign());
        calendar.add(Calendar.DAY_OF_MONTH, duration.getDays() * duration.getSign());
        calendar.add(Calendar.MONTH, duration.getMonths() * duration.getSign());
        calendar.add(Calendar.YEAR, duration.getYears() * duration.getSign());

        return calendar;
    }

    protected Calendar parseDate(String date) throws Exception {
        Calendar dateCalendar = null;
        try {
            dateCalendar = ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.forTimeZone(
                    clockReader.getCurrentTimeZone())).parseDateTime(date).toCalendar(null);

        } catch (IllegalArgumentException e) {
            // try to parse a java.util.date to string back to a java.util.date
            dateCalendar = new GregorianCalendar();
            dateCalendar.setTime(DATE_FORMAT.parse(date));
        }

        return dateCalendar;
    }

    protected Duration parsePeriod(String period) throws Exception {
        return datatypeFactory.newDuration(period);
    }

    protected boolean isDuration(String time) {
        return time.startsWith("P");
    }

}

DurationHelper工具类使用示例

public class ExecuteTest {


    @Test
    public void testD() throws Exception {
        System.out.println("当前时间:"+format(new Date()));
       //1年以后
        printDate("P1Y");
        //1个月以后
        printDate("P1M");
        //1天以后
        printDate("P1D");
        //1小时以后
        printDate("PT1H");
        //1分钟以后
        printDate("PT1M");
        //1秒钟以后
        printDate("PT1S");

    }

    public void printDate(String lexicalRepresentation) throws Exception {
        ClockReader clockReader = new DefaultClockImpl();
        DurationHelper dh = new DurationHelper(lexicalRepresentation, clockReader);
        System.out.println("规则:"+lexicalRepresentation+"    时间:"+format(dh.getDateAfter()));
    }

    private String format(Date date) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return dateFormat.format(date);
    }
}

示例结果:

当前时间:2023-02-15 18:14:53
规则:P1Y     时间:2024-02-15 18:14:53
规则:P1M     时间:2023-03-15 18:14:53
规则:P1D     时间:2023-02-16 18:14:53
规则:PT1H    时间:2023-02-15 19:14:53
规则:PT1M    时间:2023-02-15 18:15:53
规则:PT1S    时间:2023-02-15 18:14:54

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flowable的DurationHelper时间计算工具类 的相关文章

  • 如何以编程方式找出我的 PermGen 空间使用情况?

    我正在尝试诊断java lang OutOfMemoryError PermGen Space在 Sun 的 Hotspot JVM 上运行时出现错误 并且想知道我的程序在不同时刻使用了多少 PermGen 空间 有没有办法以编程方式找出这
  • Java Sqlite Gradle

    我对 gradle 和 java 还很陌生 我有一个使用 sqlite 的项目 它通过 intellij idea 运行良好 但我无法从终端运行它 它会抛出异常 java lang ClassNotFoundException org sq
  • 指纹奇异点检测

    我正在尝试确定指纹的核心点和增量点 我正在使用庞加莱指数方法 但我无法成功检测到这一点 而且我不明白为什么 First I divide the image in 15x15 blocks then I calculate the x an
  • 如何降低圈复杂度?

    我正在开发一个将 RequestDTO 发送到 Web 服务的类 我需要在发送请求之前验证该请求 请求可以从 3 个不同的地方发送 并且每个 请求类型 有不同的验证规则 例如请求1必须有姓名和电话号码 请求2必须有地址等 我有一个 DTO
  • 如何使用 Java 创建多个模式连接?

    我必须使用两个数据库 DB2 Oracle 我在 DB2 数据库中有一个名为NAVID 我想使用 Java 为 Oracle 中的所有表创建相同的架构 public class automateExport static String va
  • 如何防止在 CXF Web 服务客户端中生成 JAXBElement

    我正在尝试使用 CXF 创建一个 Web 服务客户端来使用 WCF Web 服务 当我使用 wsdl2java 时 它生成具有 JAXBElement 类型而不是 String 的对象 我读到有关使用 jaxb bindings xml 文
  • 在哈希图中存储字符和二进制数

    我正在尝试存储字母到二进制数的映射 这是我的映射 h 001 i 010 k 011 l 100 r 101 s 110 t 111 为此 我创建了一个哈希映射并存储了键值对 我现在想显示给定句子的相应二进制值 这是我的代码 package
  • WebLogic 10 中的临时目录

    每当 WL 停止时 它都不会删除其临时目录 即 domains mydomain servers myserver tmp WL TEMP APP DOWNLOADS domains mydomain servers myserver tm
  • 为什么一个线程会中断另一个线程[重复]

    这个问题在这里已经有答案了 在Java多线程应用程序中 我们处理InterruptedThreadException 如果另一个线程中断当前线程 则会抛出此异常 现在 当另一个线程知道它将导致异常时 它可能想要中断当前线程的原因是什么 很多
  • 通过 JNI 从 Applet 调用 DLL

    我有一个 概念验证 的作品 它跨越了一些不熟悉的领域 我的任务是将 EFTPOS 机器连接到在内联网浏览器中作为小程序运行的应用程序 我暂时忽略了 EFTPOS dll 并用我选择的语言 Delphi 创建了一个简单的 JNI 修饰的 DL
  • 如何使用 Spring MVC 和 Thymeleaf 添加静态文件

    我的问题是如何添加 CSS 和图像文件等静态文件 以便我可以使用它们 我正在使用 Spring MVC 和 Thymeleaf 我查看了有关此主题的各种帖子 但它们对我没有帮助 所以我才来问 根据这些帖子 我将 CSS 和图像文件放在res
  • 中间件 API 的最佳实践是什么? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我们正在开发一个中间件 SDK 采用 C 和 Java 语言 供游戏开发人员 动画软件开发人员 阿凡达开
  • MessageDigest MD5 算法未返回我期望的结果

    我脑后的某个东西告诉我 我在这里遗漏了一些明显的东西 我正在将现有的 java 项目与第三方 api 集成 该第三方 api 使用 api 密钥的 md5 哈希进行身份验证 它对我不起作用 在调试过程中我意识到我生成的哈希值与他们提供的示例
  • NoSuchMethodError:将 Firebase 与应用程序引擎应用程序集成时

    我试图将 firebase 实时数据库与谷歌应用程序引擎应用程序集成 我在调用时收到此错误 gt DatabaseReference ref FirebaseDatabase gt getInstance gt getReference t
  • C++ 中的 Java ArrayList [重复]

    这个问题在这里已经有答案了 在Java中我可以做 List
  • Java 8根据Map属性过滤Map对象列表以删除一些重复项

    Have a List
  • Jenkins 管道和 java.nio.file.* 方法的问题

    我正在尝试使用 java nio file 中的方法在 Jenkins 管道中执行一些基本文件操作 无论代码存在于哪个节点块中 代码都在主节点上执行 在管道中 我已经验证了各个节点块都是正确的 它们唯一地标识了特定的节点 但是 pathEx
  • java数据结构模拟数据树

    我需要帮助定义使用什么方法 我有一个 SOAP 响应 给我一个 xml 文件 我需要在屏幕上显示 3 个相关列表 当您在第一个列表中选择一个项目时 相应的选择将出现在第二个列表中 依此类推 我只对从 xml 流中提取数据后如何有效地组织数据
  • 条件查询:按计数排序

    我正在尝试执行一个标准查询 该查询返回 stackoverflow 中回答最多的问题 例如常见问题解答 一个问题包含多个答案 我正在尝试使用标准查询返回按每个问题的答案数排序的回答最多的问题 任何人都知道我应该在 hibernate cri
  • java中的回调是什么[重复]

    这个问题在这里已经有答案了 可能的重复 什么是回调函数 https stackoverflow com questions 824234 what is a callback function 我已经阅读了回调的维基百科定义 但我仍然没有明

随机推荐

  • 搭建一个Fabric网络

    生成相关证书文件 首先Fabric提供了一些工具用于生成所需的文件 cryptogen模块会根据提供的配置文件生成后续模块运行过程中需要的证书和数据文件 cryptogen常用命令 generate用于根据配置文件生成证书 showtemp
  • DS18B20使用说明

    DS18B20 温湿度监测模块 芯片介绍 基础介绍 引脚介绍 DS18B20是单总线协议的典型代表 同时也是单总线协议最广泛的应用场景 是常用的数字温度传感器 其输出的是数字信号 具有体积小 硬件开销低 抗干扰能力强 精度高的特点 DS18
  • 动态SQL,模糊查询,关联查询

    一 和 的区别 相同点 这两个都是占位符 用来指定传入sql的参数 不同点 这个是预编译的 不会发生sql注入 如果需要使用拼接的话可以使用sql的内置函数contact 这个是将其中的变量通过字符串拼接的方式插入到sql语句中的 容易发生
  • CodeSmith 使用教程(10): CodeTemplateInfo 对象

    通过CodeTemplateInfo对象可以获取代码模板文件本身的一些信息 比如文件名 源语言 编码方法 其支持的属性有 属性名 描述 CodeBehind 该模板的Code behind的文件名或者模板不使用CodeBehind时为空字符
  • Gromacs初探

    1 Gromacs是用来干什么的 分子动力学模拟是分子模拟中最接近实验条件的模拟方法 能够从原子层面给出体系的微观演化过程 直观地展示实验现象发生的机理与规律 gromacs就是一个用于分子动力学模拟的程序 2 Gromacs的步骤 以T4
  • 项目部署K8s中excel导出模板名乱码

    问题描述 线下环境测试问题 部署到k8s上时 导出报表1时 导出时用的时报表2的模板 进入镜像中查询template下的导出模板 发现模板名都是问号 乱码 而且数量少了一个 可能由于这两个模板的名字都是5个汉字 导致tomcat解析时变成了
  • 还在select 1 union select 2 union……?

    要目录干啥 用Union吧 太长 用values吧 神奇 引申Values用法 用Union吧 太长 有时候 要临时建个短列表 2047以内的纯数字还不错 有个表 也够用 select number from master spt valu
  • 人脸识别、无人驾驶背后:是谁在造人工大脑?

    NEW 关注剁手日记视频号 最新视频 OPPO下一代屏下镜头技术 这可能才是你想要的全面屏 来源 科技新知 文 樟稻 编辑 伊页 转瞬之间 ILSVRC比赛 又称ImageNet比赛 已经停办了四年 作为机器视觉领域最受追捧也是最具权威的学
  • 【马士兵】Python基础--07(列表)

    Python基础 07 文章目录 Python基础 07 列表的添加操作 列表中的删除操作 列表元素的修改操作 对列表的排序操作 列表生成式 列表的添加操作 列表的添加元素有四种方法 列表的添加操作不改变列表的id值 所以相当于没有新的列表
  • python 点云处理 使用plyfile库写.ply文件

    点云处理时 关使用python读写 ply文件的博客并不多 而且要么是从ply文件头部开始写起 要么是csdn收费的 所以这里写一个博客记录下 1 读ply文件 这个很简单 具体可以看官方文档 代码 首先安装plyfile库 pip ins
  • 关于Oracle sql查询未走索引的问题(第二次查询比第一次查询更慢)

    这段时间发现查询一个大表很慢 这个表数据量大概有3亿多 第一次查询发现返回数据很快 即正常使用索引 紧接着 再次执行这语句时 发现查询很慢 很久才返回数据 按照oracle正常sql查询来说 第二次查询应该是比第一次更快才对 所以这想象没有
  • 深入浅出谈数据挖掘

    作 者 段勇 一 数据挖掘的本质 一般来说 比较狭义的观点认为数据挖掘区别于常规数据分析的关键点在于 数据挖掘主要侧重解决四类问题 分类 聚类 关联 预测 关于这四类问题后文会详细阐述 而常规数据分析则侧重于解决除此之外的其他数据分析问题
  • 计算物品的相似度矩阵

    计算物品的相似度矩阵 例如现在有A B C D四个用户 分别对a b c d e五个物品表达了自己喜好程度 通过评分高低来表现自己的偏好程度高低 计算物品之间的相似度矩阵 算法 1 建立用户物品倒排表 A a b d B a c e C b
  • Centos8中创建LVM条带卷具体方法

    为了性能考虑 考虑将数据跨越多个磁盘上存储 即把LV上连续的数据分成大小相同的块 然后依次存储在各个磁盘PV上 类似于RAID 0的数据存放形式 实现数据读写的并发 管理员依据自己的数据需求 定义数据分块大小 分布PV磁盘个数信息 从而实现
  • 注解 @AutoConfigureBefore 和 @AutoConfigureAfter 的用途

    介绍 AutoConfigureBefore 和 AutoConfigureAfter 是 spring boot autoconfigure 包下的注解 用途 AutoConfigureBefore AAAA class 或 AutoCo
  • 利用eNSP的Cloud连接物理机防火墙(web)

    防火墙一般用USG6000V的 双击打开后一般会出现会出现以下提示 需要导入一个USG6000V的设备包 可以自行下载 下载好后 点击浏览找到对应设备包导入即可 然后就可以正常开机了 开机后输入默认的账号密码 账号 admin 密码 Adm
  • Qt/C++编写视频监控系统80-远程回放视频流

    一 前言 远程回放NVR或者服务器上的视频文件 一般有三种方式 第一种是调用厂家的SDK 这个功能最全 但是缺点明显就是每个厂家的设备都有自己的SDK 只兼容自家的设备 如果你的软件需要接入多个厂家的 那就意味着要写好多套SDK接入 而且一
  • ​​​苹果上架app需要什么条件​​​

    当我们开发完app后 需要将ipa ap 上传IPA 使用一门Ipa上传小助手把安装包上传到appstoreconnect等待审核 专用密码上传IPA IPA上传小助手可以在windows环境下把IPA上传到appuploader 1 登录
  • Ubuntu包管理工具介绍及本地源配置(三)

    不论是在学习还是在做Linux运维的过程中都需要安装各种软件包以及使用包管理工具 但由于很多内网环境几乎不允许生产环境的服务器连接互联网 这样就造成内网服务器无法使用网上的各种源 而且如果使用来回拷贝软件包安装还得解决依赖问题 所以就需要搭
  • Flowable的DurationHelper时间计算工具类

    Flowable的DurationHelper时间计算工具类 PnYnMnDTnHnMnS时间规则 Obtain a new instance of a Duration specifying the Duration as its str