在原有《java语言时间表达式引擎》https://www.iteye.com/blog/kanpiaoxue-2217121 的基础上进行了精简。
时间表达式也进行了微调,改为: {dt:格式化字符串,offset}
import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.collect.Maps; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 时间表达式引擎 * * @ClassName: DateExpressionEngine * @author kanpiaoxue * @version 1.0 * @CreateTime: 2020/06/29 20:28:06 * @Description: */ public class DateExpressionEngine { private static final Pattern PATTERN = Pattern.compile("(\\{dt:(.*?)\\})"); private static final Pattern OFFSET_PATTERN = Pattern.compile("^(-?\\d+?)?([y,Y,M,w,W,d,D,H,h,m])$"); private static final Pattern OFFSET_SPECIAL_PATTERN = Pattern.compile("^([F,f,E,e])([M,w,W,q,Q])$"); private static final String FIRST_STRING = "F"; private static final String END_STRING = "E"; private static final String YEAR_STRING = "y"; private static final String QUARTR_STRING = "Q"; private static final String MONTH_STRING = "M"; private static final String WEEK_STRING = "w"; private static final String DAY_STRING = "d"; private static final String HOUR_STRING = "H"; private static final String MINUTE_STRING = "m"; private static final int PAIR_LENGTH = 2; private static final int ZERO = 0; /** * * @param text * 需要处理的字符串 * * <pre> * 里面可以含有任意多个时间表达式 * 格式:dateFormat[,offset]} * dateFormat: 符合java的java.text.DateFormat规范的表达式 * DateUnit 时间格式单位:[注意大小写] * y : year * M : Month * d : day * w : week * H : Hour * m : minute * * [重点]这里的格式有两种,一种是一般日期表达式,一种是特殊表达式 * * 一、一般日期表达式: * offset的表达式:(-)?number+DateUnit * offset的正则表达式: ^((?:-)?\\d+?)([y,M,w,d,H,m])$ * * example: * {dt:MM} {dt:MMdd} {dt:MM/dd} {dt:HH} {dt:HHmm} * {dt:yyyyMMdd} {dt:yyyy-MM-dd} {dt:yyyy/MM/dd} * {dt:yyyyMMddHH} {dt:yyyy-MM-dd HH} {dt:yyyy/MM/dd HH} * {dt:yyyyMMddHHmm} {dt:yyyy-MM-dd HH:mm} {dt:yyyy/MM/dd HH:mm} * {dt:yyyyMMdd,-1y} {dt:yyyy-MM-dd,-1y} {dt:yyyy/MM/dd,-1y} * {dt:yyyyMMdd,-1M} {dt:yyyy-MM-dd,-1M} {dt:yyyy/MM/dd,-1M} * {dt:yyyyMMdd,1d} {dt:yyyy-MM-dd,1d} {dt:yyyy/MM/dd,1d} * {dt:yyyyMMddHH,1H} {dt:yyyy-MM-dd HH,1H} {dt:yyyy/MM/dd HH,1H} * {dt:yyyyMMdd,1w} {dt:yyyy-MM-dd,1w} {dt:yyyy/MM/dd,1w} * {dt:yyyyMMddHHmm,10m} {dt:yyyy-MM-dd HH:mm,10m} {dt:yyyy/MM/dd HH:mm,10m} * * 二、特殊表达式 * 用来计算:季度初/末,月初/末,周初/末(也就是周一和周日) * offset的表达式:position+DateUnit * offset的正则表达式:^([F,f,E,e])([M,w,W,q,Q])$ * ------------------ * F,f means: first * E,e means: end * ------------------ * M : Month * w,W : Week * q,Q : Quarter * * </pre> * * @param dateTime * 时间 * @return 经过计算之后的字符串 */ public static String formatDateExpression(String text, DateTime dateTime) { Preconditions.checkArgument(StringUtils.isNotBlank(text), "text is null or empty!"); Preconditions.checkNotNull(dateTime, "dateTime is null"); Matcher m = PATTERN.matcher(text); Map<String, String> map = Maps.newHashMap(); /** * 如果找到时间表达式则进行替换,如果找不到,则不进行处理 */ while (m.find()) { /** * <pre> * * {dt:expression} is group(1) , as: {dt:yyyyMMdd,-1y} , {dt:yyyyMMdd,FQ} * expression is group(2) , as: yyyyMMdd,-1y , yyyyMMdd,FQ * </pre> */ String expression = m.group(2); // expressionWrapper : {dt:yyyyMMdd,-1y} , {dt:yyyyMMdd,FQ} String expressionWrapper = text.substring(m.start(1), m.end(1)); // 格式化时间 String replaceString = formatDateTime(expression, dateTime); map.put(expressionWrapper, replaceString); } // 替换表达式为正确的时间字符串 for (Entry<String, String> kv : map.entrySet()) { text = StringUtils.replace(text, kv.getKey(), kv.getValue()); } return text; } private static String formatDateTime(String express, DateTime dateTime) { // 将表达式切分开 List<String> lst = Splitter.on(',').trimResults().omitEmptyStrings().splitToList(express); int size = lst.size(); Preconditions.checkArgument(size <= PAIR_LENGTH, unexpected(express)); // 如果存在复杂的计算表达式 if (lst.size() == PAIR_LENGTH) { String offsetExpression = lst.get(1); // 处理季度、月、周的第一天和最后一天 Matcher m = OFFSET_SPECIAL_PATTERN.matcher(offsetExpression); if (m.matches()) { dateTime = processFirstOrLast(express, dateTime, m); } else { // 处理一般的时间表达式 dateTime = processNormal(express, dateTime, offsetExpression); } } // 得到时间表达式的格式化部分 String format = lst.get(0); return dateTime.toString(format); } private static DateTime processFirstOrLast(String express, DateTime dateTime, Matcher sm) { String str = sm.group(1); Preconditions.checkArgument(StringUtils.isNotBlank(str), unexpected(express)); String unit = sm.group(2); if (QUARTR_STRING.equalsIgnoreCase(unit)) { dateTime = processQuarter(express, dateTime, str); } else if (MONTH_STRING.equals(unit)) { dateTime = processMonth(express, dateTime, str); } else if (WEEK_STRING.equalsIgnoreCase(unit)) { dateTime = processWeek(express, dateTime, str); } return dateTime; } private static DateTime processMonth(String express, DateTime dateTime, String str1) { if (FIRST_STRING.equalsIgnoreCase(str1)) { dateTime = dateTime.dayOfMonth().withMinimumValue(); } else if (END_STRING.equalsIgnoreCase(str1)) { dateTime = dateTime.dayOfMonth().withMaximumValue(); } else { throw new IllegalArgumentException(unexpected(express)); } return dateTime; } private static DateTime processNormal(String express, DateTime dateTime, String offsetExpression) { Matcher m = OFFSET_PATTERN.matcher(offsetExpression); Preconditions.checkArgument(m.matches(), unexpected(express)); String numString = m.group(1); int num = StringUtils.isBlank(numString) ? ZERO : Integer.valueOf(numString).intValue(); if (ZERO == num) { // 如果是 offset == 0, 不需要进行下面的单位转换,直接返回当前时间 return dateTime; } String unit = m.group(2); if (YEAR_STRING.equalsIgnoreCase(unit)) { // IgnoreCase dateTime = dateTime.plusYears(num); } else if (MONTH_STRING.equals(unit)) { dateTime = dateTime.plusMonths(num); } else if (WEEK_STRING.equalsIgnoreCase(unit)) { // IgnoreCase dateTime = dateTime.plusWeeks(num); } else if (DAY_STRING.equalsIgnoreCase(unit)) { // IgnoreCase dateTime = dateTime.plusDays(num); } else if (HOUR_STRING.equalsIgnoreCase(unit)) { // IgnoreCase dateTime = dateTime.plusHours(num); } else if (MINUTE_STRING.equals(unit)) { dateTime = dateTime.plusMinutes(num); } else { throw new IllegalArgumentException(unexpected(express)); } return dateTime; } private static DateTime processQuarter(String express, DateTime dateTime, String str) { DateTime startQuarter = dateTime.plusMonths(0 - (dateTime.monthOfYear().get() - 1) % 3).dayOfMonth() .withMinimumValue(); if (FIRST_STRING.equalsIgnoreCase(str)) { // 季度初 dateTime = startQuarter; } else if (END_STRING.equalsIgnoreCase(str)) { // 季度末 dateTime = startQuarter.plusMonths(3).plusDays(-1); } else { throw new IllegalArgumentException(unexpected(express)); } return dateTime; } private static DateTime processWeek(String express, DateTime dateTime, String str1) { if (FIRST_STRING.equalsIgnoreCase(str1)) { dateTime = dateTime.dayOfWeek().withMinimumValue(); } else if (END_STRING.equalsIgnoreCase(str1)) { dateTime = dateTime.dayOfWeek().withMaximumValue(); } else { throw new IllegalArgumentException(unexpected(express)); } return dateTime; } private static String unexpected(String express) { return String.format("unexpected expression format:%s", express); } }
相关推荐
Fel Java表达式引擎是一款轻量级且高效的开源表达式计算引擎。它的全称是FastExpressionLanguage,专门设计用于满足不断变化的功能需求和性能需求。Fel的执行方式主要依赖于函数,运算符如加减乘除等被视为Fel函数,...
### 高速 Fel表达式引擎知识点详解 #### 一、Fel表达式引擎概述 Fel(Fast Expression Language)是一种高性能的表达式引擎,旨在满足企业级应用对于表达式处理的需求。它具备快速执行的能力,与ognl等其他流行...
6. **API集成**:Fel-all-0.9.tar.gz文件包含了一个完整的Fel引擎包,很可能提供了方便的Java API,使得开发者能够轻松地将Fel引擎集成到Java项目中,进行表达式的创建、编译和执行。 7. **扩展性**:Fel引擎可能...
Java表达式引擎是指能够解析和计算表达式的软件组件,它能够从字符串形式的表达式中获取值、执行方法调用等操作。在Java领域中,表达式引擎常常用于处理动态计算需求,如模板引擎、规则引擎等场景。 从提供的文件...
在Java中,我们可以使用RE2J库,它是Google开发的一个高效、安全的正则表达式引擎,支持构造有限状态自动机。虽然RE2J主要设计用于正则表达式的匹配,但通过它的内部机制,我们可以间接地实现字符串生成。 下面是一...
Fel表达式引擎在Java应用中尤其常见,它能够嵌入到各种系统中,提升程序的可扩展性和灵活性。 **一、Fel语法基础** 1. **变量和常量**:Fel支持变量和常量的使用。变量以$开头,例如`$name`,常量则直接书写,如`...
尤其是在Java语言环境中,`java.util.regex`包提供了丰富的API来支持正则表达式的创建与使用。然而,在实际应用中,随着正则表达式的复杂度增加,其执行效率往往会成为性能瓶颈之一。本文将深入探讨Java中正则表达式...
JEXL(Java Expression Language)是Apache Commons项目提供的一种轻量级的表达式语言,它允许我们在Java应用程序中方便地执行JavaScript风格的表达式。本文将深入探讨如何使用JEXL在Java中解析和执行表达式。 首先...
在这个场景中,我们关注的是一个用Java编写的专门用于解析算术表达式的解释器。Java是一种广泛使用的面向对象的编程语言,以其跨平台性和强大的库支持而著名。下面我们将深入探讨Java解释算术表达式这一主题。 首先...
在Java编程语言中,计算数学表达式是一项常见的需求,它涉及到字符串解析、语法分析和运算符优先级处理等多个环节。`jeval-0.9.4`是一个Java库,专门用于解析和评估数学表达式。这个库使得开发人员能够轻松地在程序...
2. Java 正则表达式的历史:Java 一直以来没有自带对正则表达式的支持,直到 Java 1.40 版本引入了 java.util.regex 包。之前,许多第三方类库提供了对正则表达式的支持,但这些类库都不一致、兼容性差。 3. ...
IK Expression 是一个开源的(OpenSource),可扩展的(Extensible), 基于java 语言开发的一个超轻量级(Super lightweight)的公式化语言解析执行 工具包。它是一个采用逆波兰式算法结合指针栈优化的公式解析引擎...
Java正则表达式是Java编程语言中用于处理字符串的强大工具,它允许程序员通过模式匹配来查找、替换或分割文本。正则表达式(Regular Expression,简称regex)是一种由字符、元字符和操作符组成的模式,可以用来匹配...
Java表达式解析是编程中的一个重要概念,特别是在设计编译器、解释器或脚本引擎时。这个程序可能是为了理解并执行简单的数学或逻辑表达式,比如`2 + 3 * (4 - 5)`。在Java中实现这样的解析器,我们需要理解表达式...
在Java编程语言中实现一个多功能计算器,涉及到许多关键知识点,包括但不限于基础的算术运算、字符串解析、表达式求值、异常处理以及用户界面设计。下面将详细阐述这些知识点。 1. **基础算术运算**:计算器的核心...
Java的BeanShell是一个轻量级、动态的脚本语言,它是专门为Java平台设计的,允许在运行时执行Java代码或者类似JavaScript的语法。BeanShell在Java应用中常被用来进行快速原型开发、测试以及扩展,它提供了一种简单的...
7. **使用NetBeans**:NetBeans是一个流行的开源IDE,支持多种编程语言,包括Java。在NetBeans中开发这个项目,开发者可以利用其内置的项目管理、代码编辑、调试和构建工具,使得开发流程更加高效和便捷。 在压缩包...
IKExpression是一款针对Java平台的轻量级表达式引擎,主要用于解析和执行用户自定义的表达式,从而实现程序的动态配置和灵活性。IKExpression V2.1.0是该引擎的升级版本,提供了更高效、稳定和易用的特性。 在...