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
Duration.of(3, CalendarUnit.DAYS)
- duration consisting of a single itemDuration.ofCalendarUnits(2, 5, 11)
- tuple of 2 years, 5 months and 11 daysDuration.ofClockUnits(30, 4, 104)
- tuple of 30 hours, 4 minutes and 104 secondsDuration.ofPositive().days(2).hours(5).build()
- tuple of 2 days and 5 hours (builder pattern)Duration.ofNegative().days(2).hours(5).build()
- tuple of -2 days and -5 hours (builder pattern)Duration.ofZero()
- empty duration
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
.