How to handle a duration?

Table Of Contents

The class net.time4j.Duration
How to create a duration?
Manual creation as tuple of amounts and units
Evaluation as distance between two points in time
Parsing an ISO-compatible canonical representation
Normalization
Manipulations, composition and splitting
Format support
Using Duration.Formatter
Using PrettyTime

The class net.time4j.Duration

Duration handling in Time4J mainly uses the class net.time4j.Duration. Its internal state is a sorted list of duration items and the sign of the duration. Every duration item is just a composition of an amount (as long-primitive) and the associated unit (as generic type U extends IsoUnit). The sign is always related to the whole duration, never to its single distinct duration items, so mixed signs are never possible. The generic type parameter U controls if the duration is just a) calendrical or b) clock-related or c) a general date-time duration.

How to create a duration?

There are at least following three principle ways to create an object of type net.time4j.Duration.

Manual creation as tuple of amounts and units

Evaluation as distance between two points in time

Any duration can also be the result of the evaluation of the temporal distance between two points in time as far as the associated time axis is related to the unit type IsoUnit. This is valid for PlainDate, PlainTime and PlainTimestamp. However, a TimeMetric is necessary to tell Time4J how to evaluate the distance. Example which specifies the units to be used for the calculation:

	PlainTimestamp start = PlainDate.of(2014, 3, 28).atTime(0, 30);
	PlainTimestamp end = PlainDate.of(2014, 4, 5).atTime(14, 15);

	Duration<IsoUnit> durationJava6 = start.until(end, Duration.in(DAYS, HOURS, MINUTES)); // works in Java 6
	Duration<IsoUnit> durationJava8 = Duration.in(DAYS, HOURS, MINUTES).between(start, end); // equivalent alternative for Java 8
	System.out.println(durationJava6); // output: P8DT13H45M
	System.out.println(durationJava6.equals(durationJava8)); // output: true

Time4J will iterate about all given units in order to determine the partial duration amounts dependent on the associated unit. For positive durations the iteration order is from greatest to smallest units, for negative duration it is the reverse order. More details and some mathematical reasons for the choosen algorithm can be found in the description of AbstractDuration.

It is also possible to specify the timezone in order to take into account possible daylight savings if the duration needs to be evaluated. Following code deploys another kind of TimeMetric:

	PlainTimestamp start = PlainTimestamp.of(2014, 3, 30, 0, 0);
	PlainTimestamp end = PlainTimestamp.of(2014, 3, 30, 5, 0);

	System.out.println(t1.until(t2, Duration.in(Timezone.of("Europe/Berlin"), ClockUnit.HOURS))); 
	// output: PT4H (one hour less because of change to summer time)

Parsing an ISO-compatible canonical representation

While the last code examples show the ISO-8601-output of the Object-method toString() the reverse construction of a duration from a canonical representation is possible, too. Even alternative ISO-formats are understood:

	Duration<IsoUnit> duration1 = Duration.parsePeriod("-P18DT2H"); // -18 days and -2 hours (negative)
	Duration<CalendarUnit> duration2 = Duration.parseCalendarPeriod("P0000-11-04"); // 11 months and 4 days

Important: Such an ISO-8601-compatible representation is the standard way how to store a duration for example in a database.

Normalization

The term "normalization" describes a transformation of a duration into another more or less similar (but often not exactly equivalent) form. Time4J offers several built-in normalizers which implement the interface Normalizer. Such a normalizer can then be used as argument to the duration-method with(Normalizer) in order to normalize the given duration.

	Duration<ClockUnit> d = Duration.parseClockPeriod("PT3H60M").with(Duration.STD_CLOCK_PERIOD);
	// PT4H - normalized using one of several normalizer constants in class net.time4j.Duration

	Duration<CalendarUnit> d = Duration.of(35, DAYS).with(PlainDate.of(2015, 4, 29));
	// P1M5D - purpose of given reference date as normalizer is to determine the length of involved month

Manipulations, composition and splitting

A given duration can be manipulated by various methods like plus(), with(), inverse(), abs() or multipliedBy(). Two or more duration can be merged together using plus() provided that there will not be any mixed signs present.

Following example demonstrates a combination of splitting, normalization and composition:

	Duration<IsoUnit> duration = Duration.parsePeriod("P2DT27H55M90S"); // 2 days, 27 hours, 55 minutes and 90 seconds

	Duration<CalendarUnit> calendricalPart = duration.toCalendarPeriod(); // splitting - 2 days
	Duration<ClockUnit> clockPart = duration.toClockPeriod(); // splitting - 27 hours, 55 minutes and 90 seconds

	clockPart = clockPart.with(ClockUnit.MINUTES.rounded()); // normalized to 27 hours and 57 minutes

	System.out.println(Duration.compose(calendricalPart, clockPart).with(Duration.STD_PERIOD)); // P3DT3H57M (3 days, 3 hours and 57 minutes)

Format support

Using Duration.Formatter

This style enables formatting and parsing based on pattern symbols. Even features like adjacent digit parsing are supported. Example:

	Duration<?> duration = Duration.ofPositive().days(15).hours(17).minutes(45).build();
	System.out.println(Duration.formatter("[##D]hhmm").format(duration)); // formatted output: 151745
	System.out.println(Duration.formatter("[##D]hhmm").parse("151745")); // P15DT17H45M

Using PrettyTime

The pattern-based style is convenient if you have a fixed structure in mind. However, it is not sufficient for internationalized applications. To achieve the option to print localized durations in social-media-style, you can do this:

	Duration<?> duration = Duration.ofPositive().days(15).hours(17).minutes(45).build();
	String s = PrettyTime.of(Locale.GERMAN).print(duration, TextWidth.WIDE);
	System.out.println(s); // output: 15 Tage, 17 Stunden und 45 Minuten	

Note that parsing is NOT supported in contrast to the pattern-based way, only printing. Therefore the class PrettyTime is only designed for formatted output while the underlying duration object must be kept in the background, for example in a http session.

Relative times measuring the nominal duration of a given moment relative to current time in a timezone are supported, too. To make this work, you simply call printRelative() on a localized instance of PrettyTime.