Nomix Prenomax
Nomix Prenomax

Reputation: 103

Removing '-' from negative Joda time Periods

I have a question regarding subtracting Joda DateTimes, and I use Period to get number of dates, hours, minutes and seconds between the two.

Output example : 2 days 11h 23min 05sec

DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
DateTime firstDate = formatter.parseDateTime(firstStringDateValue);
DateTime secondDate = formatter.parseDateTime(secondStringDateValue);

DurationFieldType[] types = {DurationFieldType.days(), 
                             DurationFieldType.hours(), 
                             DurationFieldType.minutes(), 
                             DurationFieldType.seconds()};

Period period = new Period(firstDate, secondDate, PeriodType.forFields(types));

PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
            .minimumPrintedDigits(2)
            .appendDays().appendSuffix(" Day", " Days").appendSeparator(" ")
            .appendHours().appendSuffix("h").appendSeparator(" ")
            .appendMinutes().appendSuffix("min").appendSeparator(" ")
            .appendSeconds().appendSuffix("sec")
            .toFormatter();

String result = periodFormatter.print(period);

The problem is when the start the date is greater than the end date.

The result is something like this : -2 days -11h -23min -05sec

So I was wondering is there a way to make it look like this : - 2 days 11h 23min 05sec, with only one '-' in front of the whole thing. But using Joda related functions.

Or at least a method to tell me if the Period is negative.

I can do this using string manipulation but it seems a bit too manual.

Thank you.

Upvotes: 2

Views: 436

Answers (2)

Maksim Yakunin
Maksim Yakunin

Reputation: 458

Unfortunately, Period has no method abs() in comparison with Duration.

However, we can write our own helper-method to achieve this with help of Period::negated() method:

public static Period periodAbs(Period period) {
    return period.toStandardSeconds().getSeconds() < 0
        ? period.negated()
        : period;
}

Furthermore, you can extract this logic to separate class (that's definitely better choice in my opinion) if you don't like static methods :

public static class AbsPeriod {
    private final Period period;

    public AbsPeriod(Period period) {
        this.period = period;
    }

    public Period value() {
        return period.toStandardSeconds().getSeconds() < 0
            ? period.negated()
            : period;
    }
}

Complete runnable example:

import org.joda.time.DateTime;
import org.joda.time.DurationFieldType;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;

class Scratch {
    public static void main(String[] args) {
        DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss");
        DateTime firstDate = formatter.parseDateTime("12/11/2001 12:12:12");
        DateTime secondDate = formatter.parseDateTime("12/11/2000 12:12:12");

        DurationFieldType[] types = {DurationFieldType.days(),
            DurationFieldType.hours(),
            DurationFieldType.minutes(),
            DurationFieldType.seconds()};

        Period period = new Period(firstDate, secondDate, PeriodType.forFields(types));

        PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
            .minimumPrintedDigits(2)
            .appendDays().appendSuffix(" Day", " Days").appendSeparator(" ")
            .appendHours().appendSuffix("h").appendSeparator(" ")
            .appendMinutes().appendSuffix("min").appendSeparator(" ")
            .appendSeconds().appendSuffix("sec")
            .toFormatter();

        System.out.println("original period = " + periodFormatter.print(period));
        System.out.println("absolute period = " + periodFormatter.print(new AbsPeriod(period).value()));
    }

    public static class AbsPeriod {
        private final Period period;

        public AbsPeriod(Period period) {
            this.period = period;
        }

        public Period value() {
            return period.toStandardSeconds().getSeconds() < 0
                ? period.negated()
                : period;
        }
    }
}

And corresponding STDOUT produced by this test-snippet:

original period = -365 Days
absolute period = 365 Days

Upvotes: 2

Vinetos
Vinetos

Reputation: 150

What you need is comparing two date.

There are isAfter and isBefore methods that compare dates by millis (ignoring time zone).

firstDate.isBefore(secondDate)
firstDate.isAfter(secondDate)

Now, you can set parameters in the correct order.
Then, add the leading minus if needed.

Upvotes: 2

Related Questions