如何创建一个表达式,将两个日期之间的时差显示为年、月、日、小时、分钟、秒
How to create a single expression displaying time difference between two Date's as years, months, days, hours, minutes, seconds
我如何创建一个 single jasper 报告 JRExpression 以 yy year(s) month(s) 格式可视化两个 java.util.Date
之间的差异dd 天,hh 小时,mm 分钟,ss 秒
java.util.Date startDate
java.util.Date endDate
JREExpression 是单行,不允许声明变量,但是你可以使用语法 boolean ? yes:no
的条件语句,对于不熟悉的你想象一行 System.out.println();
所需输出的示例(如果您有一个很好的解决方案,请在不存在时删除单元描述并考虑 singular/plural,但如果它是一系列 if 语句,则没有必要):
2 years, 8 months, 12 days, 2 hours, 53 minutes, 10 s
1 hour, 1 minute
both Feb 2- Mar 4 and Mar 4 - April 6 are "1 month, 2 days",
daylight savings however can be ignored - thanks @Affe
附加要求:
- 只能使用 jasper 报告 dependencies(joda 不是
包括)。
- 最好jdk 1.7 或更低(如果这只是解决方案,1.8 也可以接受)
无需将答案格式化为 jasper 报告表达式,它可以是一个简单的 System.out.println
代码(我很乐意稍后编辑您的答案以添加 jasper 报告表达式代码)。范例
((endDate.getTime()-startDate.getTime()) / (60 * 60 * 1000)) % 24 + " hour(s), " +
((endDate.getTime()-startDate.getTime()) / (60 * 1000)) % 60 + " minute(s)"
我尝试了什么:
我在SO的jasper报告部分回答了多个问题,这个问题在报告生成中很常见。我更喜欢 java 部分的一个很好的答案,我可以 link 而不是在这个问题上传递我的代码(我只知道部分解决作为示例)
中有问题的例子
部分参考代码:
Calculate date/time difference in java
How to find the duration of difference between two dates in java?
对于熟悉 jasper 报告的你,我不想使用变量声明,因为如果用户需要在参数上使用它,这会使解决方案无效。
日历 API 不能直接用于此问题:每个操作都需要多行,因为有趣的方法是 void
返回并且不能链接。
这是一个非常大的延伸,但是,正如在the dependencies of JasperReports, there is org.codehaus.castor:castor-xml:1.3.3
which depends itself on commons-lang:commons-lang:2.6
. We therefore can make use of the DurationFormatUtils.formatPeriod(startMillis, endMillis, format)
中列出的方法,它存在于commons-lang
中。此处使用的格式字符串为
"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'"
这将打印想要的字符串。仍然必须小心:这将包括 0(如 "0 months"
)并且还会有不正确的复数形式(如 "1 months"
)。
- 我们可以使用正则表达式
"(?<!\d)0 (\w+) ?"
来删除字符串的所有 0。此正则表达式匹配任何 0、not preceded by a digit(例如,我们不想匹配 10),后跟一个或多个单词字符,并且可选地后跟 space.
- 然后,我们可以使用正则表达式
"(?<!\d)1 (\w+)s"
来匹配每个出现的 "1 ...s"
并将其替换为 "1 ..."
以获得适当的复数形式。此正则表达式匹配任何 1,前面没有数字,后跟一个或多个以 s
结尾的单词字符(捕获在一组中);它将替换为 "1 "
,即 1 后跟捕获的值。
示例:
System.out.println(
org.apache.commons.lang.time.DurationFormatUtils.formatPeriod(
startDate.getTime(),
endDate.getTime(),
"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'"
)
.replaceAll("(?<!\d)0 (\w+) ?", "")
.replaceAll("(?<!\d)1 (\w+)s", "1 ")
);
所有这些都可以用 Java 7 或更低的版本来完成。
在 JasperReports 中,这将是一个示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.2.1.final using JasperReports Library version 6.2.1 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports jasperreports.sourceforge.net/…" name="Blank_A4" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="f067f2c4-395f-4669-9fda-4fe81cc59227">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
<parameter name="dateStart" class="java.util.Date" isForPrompting="false">
<defaultValueExpression><![CDATA[new java.util.Date(1)]]></defaultValueExpression>
</parameter>
<parameter name="dateEnd" class="java.util.Date" isForPrompting="false">
<defaultValueExpression><![CDATA[new java.util.Date()]]></defaultValueExpression>
</parameter>
<queryString><![CDATA[]]></queryString>
<title>
<band height="43" splitType="Stretch">
<textField>
<reportElement x="0" y="0" width="560" height="30" uuid="cc03531c-2983-4f9a-9619-2826ed92760e"/>
<textFieldExpression><![CDATA[org.apache.commons.lang.time.DurationFormatUtils.formatPeriod($P{dateStart}.getTime(),$P{dateEnd}.getTime(),"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'").replaceAll("(?<!\d)0 (\w+) ?", "").replaceAll("(?<!\d)1 (\w+)s", "1 ")]]></textFieldExpression>
</textField>
</band>
</title>
</jasperReport>
输出为:
如果以上内容看起来太脆弱(因为对 commons-lang
的显式依赖并非所有 JasperReports 版本都存在),there is another possible solution using the Java Time API 在 Java 8.
这是可怕的(我不认为有更简单的方法),但输出与上面完全相同,其中start
和end
都是 LocalDateTime
个对象:
System.out.println((
ChronoUnit.YEARS.between(start, end) + " years " +
ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end) + " months " +
ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end) + " days " +
ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end) + " hours " +
ChronoUnit.MINUTES.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)).plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end)), end) + " minutes " +
ChronoUnit.SECONDS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)).plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end)).plusMinutes(ChronoUnit.MINUTES.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)).plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end)), end)), end) + " seconds"
)
.replaceAll("(?<!\d)0 (\w+) ?", "")
.replaceAll("(?<!\d)1 (\w+)s", "1 ")
);
我如何创建一个 single jasper 报告 JRExpression 以 yy year(s) month(s) 格式可视化两个 java.util.Date
之间的差异dd 天,hh 小时,mm 分钟,ss 秒
java.util.Date startDate
java.util.Date endDate
JREExpression 是单行,不允许声明变量,但是你可以使用语法 boolean ? yes:no
的条件语句,对于不熟悉的你想象一行 System.out.println();
所需输出的示例(如果您有一个很好的解决方案,请在不存在时删除单元描述并考虑 singular/plural,但如果它是一系列 if 语句,则没有必要):
2 years, 8 months, 12 days, 2 hours, 53 minutes, 10 s
1 hour, 1 minute
both Feb 2- Mar 4 and Mar 4 - April 6 are "1 month, 2 days", daylight savings however can be ignored - thanks @Affe
附加要求:
- 只能使用 jasper 报告 dependencies(joda 不是 包括)。
- 最好jdk 1.7 或更低(如果这只是解决方案,1.8 也可以接受)
无需将答案格式化为 jasper 报告表达式,它可以是一个简单的 System.out.println
代码(我很乐意稍后编辑您的答案以添加 jasper 报告表达式代码)。范例
((endDate.getTime()-startDate.getTime()) / (60 * 60 * 1000)) % 24 + " hour(s), " +
((endDate.getTime()-startDate.getTime()) / (60 * 1000)) % 60 + " minute(s)"
我尝试了什么:
我在SO的jasper报告部分回答了多个问题,这个问题在报告生成中很常见。我更喜欢 java 部分的一个很好的答案,我可以 link 而不是在这个问题上传递我的代码(我只知道部分解决作为示例)
中有问题的例子部分参考代码:
Calculate date/time difference in java
How to find the duration of difference between two dates in java?
对于熟悉 jasper 报告的你,我不想使用变量声明,因为如果用户需要在参数上使用它,这会使解决方案无效。
日历 API 不能直接用于此问题:每个操作都需要多行,因为有趣的方法是 void
返回并且不能链接。
这是一个非常大的延伸,但是,正如在the dependencies of JasperReports, there is org.codehaus.castor:castor-xml:1.3.3
which depends itself on commons-lang:commons-lang:2.6
. We therefore can make use of the DurationFormatUtils.formatPeriod(startMillis, endMillis, format)
中列出的方法,它存在于commons-lang
中。此处使用的格式字符串为
"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'"
这将打印想要的字符串。仍然必须小心:这将包括 0(如 "0 months"
)并且还会有不正确的复数形式(如 "1 months"
)。
- 我们可以使用正则表达式
"(?<!\d)0 (\w+) ?"
来删除字符串的所有 0。此正则表达式匹配任何 0、not preceded by a digit(例如,我们不想匹配 10),后跟一个或多个单词字符,并且可选地后跟 space. - 然后,我们可以使用正则表达式
"(?<!\d)1 (\w+)s"
来匹配每个出现的"1 ...s"
并将其替换为"1 ..."
以获得适当的复数形式。此正则表达式匹配任何 1,前面没有数字,后跟一个或多个以s
结尾的单词字符(捕获在一组中);它将替换为"1 "
,即 1 后跟捕获的值。
示例:
System.out.println(
org.apache.commons.lang.time.DurationFormatUtils.formatPeriod(
startDate.getTime(),
endDate.getTime(),
"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'"
)
.replaceAll("(?<!\d)0 (\w+) ?", "")
.replaceAll("(?<!\d)1 (\w+)s", "1 ")
);
所有这些都可以用 Java 7 或更低的版本来完成。
在 JasperReports 中,这将是一个示例:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.2.1.final using JasperReports Library version 6.2.1 -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports jasperreports.sourceforge.net/…" name="Blank_A4" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="f067f2c4-395f-4669-9fda-4fe81cc59227">
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
<parameter name="dateStart" class="java.util.Date" isForPrompting="false">
<defaultValueExpression><![CDATA[new java.util.Date(1)]]></defaultValueExpression>
</parameter>
<parameter name="dateEnd" class="java.util.Date" isForPrompting="false">
<defaultValueExpression><![CDATA[new java.util.Date()]]></defaultValueExpression>
</parameter>
<queryString><![CDATA[]]></queryString>
<title>
<band height="43" splitType="Stretch">
<textField>
<reportElement x="0" y="0" width="560" height="30" uuid="cc03531c-2983-4f9a-9619-2826ed92760e"/>
<textFieldExpression><![CDATA[org.apache.commons.lang.time.DurationFormatUtils.formatPeriod($P{dateStart}.getTime(),$P{dateEnd}.getTime(),"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'").replaceAll("(?<!\d)0 (\w+) ?", "").replaceAll("(?<!\d)1 (\w+)s", "1 ")]]></textFieldExpression>
</textField>
</band>
</title>
</jasperReport>
输出为:
如果以上内容看起来太脆弱(因为对 commons-lang
的显式依赖并非所有 JasperReports 版本都存在),there is another possible solution using the Java Time API 在 Java 8.
这是可怕的(我不认为有更简单的方法),但输出与上面完全相同,其中start
和end
都是 LocalDateTime
个对象:
System.out.println((
ChronoUnit.YEARS.between(start, end) + " years " +
ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end) + " months " +
ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end) + " days " +
ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end) + " hours " +
ChronoUnit.MINUTES.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)).plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end)), end) + " minutes " +
ChronoUnit.SECONDS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)).plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end)).plusMinutes(ChronoUnit.MINUTES.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)).plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)).plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)).plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start, end)), end)), end)), end)), end)), end) + " seconds"
)
.replaceAll("(?<!\d)0 (\w+) ?", "")
.replaceAll("(?<!\d)1 (\w+)s", "1 ")
);