Как создать одно выражение, отображающее разницу во времени между двумя датами в виде лет, месяцев, дней, часов, минут, секунд


Как я могу создать одиночный отчет Джаспера JRExpression , который визуализирует разницу между двумя java.util.Date в формате 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

JRExpression-это одна строка, в которой объявление переменной не допускается, однако вы можете использовать условные операторы с использованием синтаксиса boolean ? yes:no, для вас, кто не знаком, представьте себе одну строку System.out.println();

Пример желаемого вывода (Если у вас есть хорошее решение удалить описание единицы, когда ее нет, и рассмотрим единственное / множественное число, но это не обязательно, если это серия утверждений if):

2 года, 8 месяцев, 12 дней, 2 часа, 53 минуты, 10 с

1 час, 1 минута

И 2 февраля - 4 марта, и 4 марта-6 апреля-это "1 месяц, 2 дня", переход на летнее время, однако, можно игнорировать-спасибо @Affe

Дополнительные требования:

  • можно использовать только отчет Джаспера зависимости (joda не является включенный).
  • предпочтительный jdk 1.7 или меньше (1.8 принимается, если это только решение)

Нет необходимости форматировать ответ как выражение отчета Джаспера это может быть простой код System.out.println (я с удовольствием отредактирую ваш ответ позже, чтобы также добавить код выражения отчета Джаспера). Пример

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

Что я пробовал:

я отвечаю на несколько вопросов в разделе отчета jasper SO, и этот вопрос часто используется при создании отчетов. Я бы предпочел хороший ответ из раздела java, который я могу связать, а не передавать свой код по этому вопросу (который я знал бы только частично решить в качестве примера)

Это пример по вопросу в jasper-report: вычисление разницы во времени и дате

Некоторый справочный код:

Вычислить разницу дат / времени в java

Как найти длительность разницы между двумя датами на Яве?

для вас это так я не хочу использовать объявление переменной, так как это приведет к недействительности решения, если пользователю потребуется использовать его для параметров.

1 2

1 ответ:

API календаря не может быть непосредственно использован для этой проблемы: каждая операция потребует нескольких строк, так как интересные методы возвращают void и не могут быть связаны.

Это очень большая натяжка, но, как указано в зависимостях JasperReports , существует org.codehaus.castor:castor-xml:1.3.3 которая сама зависит от commons-lang:commons-lang:2.6. Поэтому мы можем использовать DurationFormatUtils.formatPeriod(startMillis, endMillis, format) метод, который присутствует в commons-lang. Строка формата для использования здесь будет быть

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

Который напечатает нужную строку. Все еще необходимо соблюдать осторожность: это будет включать 0s (например, "0 months") и также будет иметь неправильную множественность (например, "1 months").

  • мы можем использовать регулярное выражение "(?<!\\d)0 (\\w+) ?", чтобы удалить все 0 для строки. Это регулярное выражение соответствует любому 0, , которому не предшествует цифра (мы не хотим, например, соответствовать 10), за которым следует один или несколько символов слова и, возможно, следует пробел.
  • тогда мы можем использовать регулярные выражение "(?<!\\d)1 (\\w+)s", чтобы соответствовать каждому появлению "1 ...s" и заменить его на "1 ...", чтобы иметь надлежащую множественность. Это регулярное выражение соответствует любому 1, не предваренному цифрой, за которым следует один или несколько символов слова (захваченных в группе), заканчивающихся на s; оно будет заменено на "1 $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 $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 $1")]]></textFieldExpression>
      </textField>
    </band>
  </title>
</jasperReport>

С выходом:

Введите описание изображения здесь


Если вышесказанное выглядит слишком хрупким (из-за явной зависимости к commons-lang, которая не может быть там для всех версий JasperReports), есть другое возможное решение с использованием 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 $1")
);