Как создать одно выражение, отображающее разницу во времени между двумя датами в виде лет, месяцев, дней, часов, минут, секунд
Как я могу создать одиночный отчет Джаспера 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 ответ:
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") );