如何创建一个单个表达式,显示两个日期之间的时间差,以年,月,日,小时,分钟,秒为单位 [英] How to create a single expression displaying time difference between two Date's as years, months, days, hours, minutes, seconds

查看:327
本文介绍了如何创建一个单个表达式,显示两个日期之间的时间差,以年,月,日,小时,分钟,秒为单位的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何创建一个单个 jasper报告






如果上面看起来太脆弱(因为显式依赖于 commons-lang ,所有JasperReports版本都无法使用),还有另一种可能解决方案,使用Java 8中引入的 Java Time API



这是可怕的(我不认为有一个更简单的方法),但输出与上面完全一样,其中开始 end 都是 LocalDateTime 对象:

  System.out.println( (
ChronoUnit.YEARS.between(start,end)+years+
ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start,end)),end)+个月+
ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start,end )),end)+days+
ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(ChronoUnit.MONTHS.between(start。加上几年(ChronoUnit.YEARS.between(start,end)),end))。plusDays(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(ChronoUnit.MONTHS.between start.plusYears(开始,结束)),end)),end)),end)+hours+
ChronoUnit.MINUTES.between(start.plusYears(ChronoUnit.YEARS.between (开始,结束))。plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start,end)),end))。plusDays(ChronoUnit.DAYS.between(start (),(),(),(),(),(),。 .HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start,end)),end))。 (ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(start,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。之间(start.plusYears(ChronoUnit.YEARS.between(start,end)),end)),end))。plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoU (开始,结束))。加上Months(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)),结束))。plusHours(ChronoUnit.HOURS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(ChronoUnit.MONTHS.between(start.plusYears(ChronoUnit.YEARS.between(开始,结束)),加上日期(ChronoUnit.DAYS.between(start.plusYears(ChronoUnit.YEARS.between(start,end))。plusMonths(Chro noUnit.MONTHS.between(start.plusYears(开始,结束)),结束)),end)),end)),end)),end)+seconds

.replaceAll((?<!\\d)0(\\\w +)?,)
.replaceAll((?<!\\d )1(\\w +)s,1 $ 1)
);


How can I create a single jasper report JRExpression that visualize the difference between two java.util.Date in format yy year(s) month(s) dd day(s), hh hour(s), mm minute(s), ss second(s)

java.util.Date startDate
java.util.Date endDate

A JRExpression is a single line where variable declaration is not allowed, however you may use conditional statements using syntax boolean ? yes:no, for you who are not familiar imagine one line of System.out.println();

Example of desired output (if you have a nice solution remove description of unit when not present and consider singular/plural but this is not necessary if it's a serie of if statements):

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

Additional requirements:

  • Only jasper report dependencies may be used (joda is not included).
  • Preferable jdk 1.7 or less (1.8 is accepted if this is only solution)

There is no need to format the answer as jasper report expression it can be a simple System.out.println code (I'm happy to edit your answer later to also add the jasper report expression code). Example

((endDate.getTime()-startDate.getTime()) / (60 * 60 * 1000)) % 24 + " hour(s), " +  
((endDate.getTime()-startDate.getTime()) / (60 * 1000)) % 60 + " minute(s)"

What have I tried:

I answer multiple question in the jasper report section of SO, and this question is common in report generation. I would prefer a good answer from the java section that I can link rather then passing my code on this issue (that I would only know to solve partially as example)

This is an example on question in : Calculating Time and Date difference

Some reference code:

Calculate date/time difference in java

How to find the duration of difference between two dates in java?

For you that are familiar to jasper report I don't want to use the variable declaration since this would invalidate the solution if user need to use it on parameters.

解决方案

The Calendar API cannot be directly be used for this problem: every operation would require multiple lines since the interesting methods are void returning and can't be chained.

This is a very big stretch, but, as listed in 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) method, which is present in commons-lang. The format String to use here would be

"y' years 'M' months 'd' days 'H' hours 'm' minutes 's' seconds'"

which would print the wanted String. Care must still be taken: this will include 0s (like "0 months") and will also have incorrect pluralization (like "1 months").

  • We can use the regular expression "(?<!\\d)0 (\\w+) ?" to remove all the 0s for the String. This regex matches any 0, not preceded by a digit (we don't want to match 10 for example), followed by one or more word characters and optionally followed by a space.
  • Then, we can use the regular expression "(?<!\\d)1 (\\w+)s" to match every occurence of "1 ...s" and replace it with "1 ..." to have proper pluralization. This regular expression matches any 1, not preceded by a digit, followed by one or more word characters (captured in a group) ending with an s; it would be replaced with "1 $1", i.e. 1 followed by the value captured.

Example:

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 $1")
);

All this can be done with Java 7 or lower.

In a JasperReports, this would be an example:

<?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 $1")]]></textFieldExpression>
      </textField>
    </band>
  </title>
</jasperReport>

With the output being:


If the above looks too fragile (because of the explicit dependency towards commons-lang that could not be there for all JasperReports version), there is another possible solution using the Java Time API introduced in Java 8.

This is horrible (I don't think there is a simpler way), but the output is exactly the same as above, where start and end are both LocalDateTime objects:

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 $1")
);

这篇关于如何创建一个单个表达式,显示两个日期之间的时间差,以年,月,日,小时,分钟,秒为单位的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆