SkillAgentSearch skills...

Itu

An extremely fast parser and formatter of standardized date and date-times supporting RFC-3339 (ISO-8601 profile) and more.

Install / Use

/learn @ethlo/Itu

README

Internet Time Utility

Maven Central javadoc Hex.pm Codacy Badge codecov

An extremely fast parser and formatter of ISO-8601 date-times. Handle RFC-3339 Timestamps and W3C Date and Time Formats with ease! Now also supports a subset of duration strings!

Features

Low ceremony, high productivity with a very easy to use API.

  • Well-documented.
  • Aim for 100% specification compliance.
  • Handling leap-seconds.
  • Zero dependencies.
  • Java 8 compatible.
  • Apache 2 licensed.

Performance

Typically, 10x to 30x faster than parsing and formatting with Java JDK classes.

The details and tests are available in a separate repository, date-time-wars.

Usage

Add dependency


<dependency>
    <groupId>com.ethlo.time</groupId>
    <artifactId>itu</artifactId>
    <version>1.14.0</version>
</dependency>

Below you find some samples of usage of this library. Please check out the javadoc for more details.

Parsing

This is a collection of usage examples for parsing.

parseRfc3339

<smaller style="float:right;">source »</smaller>

The simplest and fastest way to parse an RFC-3339 timestamp by far!

final String text = "2012-12-27T19:07:22.123456789-03:00";
final OffsetDateTime dateTime = ITU.parseDateTime(text);
assertThat(dateTime.toString()).isEqualTo(text);

parseLenient

<smaller style="float:right;">source »</smaller>

Parses a date-time with flexible granularity. Works for anything from a year to a timestamp with nanoseconds, with or without timezone offset.

final String text = "2012-12-27T19:07:23.123";
final DateTime dateTime = ITU.parseLenient(text);
final String formatted = dateTime.toString();
assertThat(formatted).isEqualTo(text);

parseLenientWithCustomSeparators

<smaller style="float:right;">source »</smaller>

In case you encounter the need for a somewhat different time-separator or fraction separator you can use the ParseConfig to set up you preferred delimiters.

final ParseConfig config = ParseConfig.DEFAULT
                .withDateTimeSeparators('T', '|')
                .withFractionSeparators('.', ',');
final DateTime result = ITU.parseLenient("1999-11-22|11:22:17,191", config);
assertThat(result.toString()).isEqualTo("1999-11-22T11:22:17.191");

parsePosition

<smaller style="float:right;">source »</smaller>

This allows you to track where to start reading. Note that the check for trailing junk is disabled when using ParsePosition.

final ParsePosition pos = new ParsePosition(10);
final OffsetDateTime result = ITU.parseDateTime("some-data,1999-11-22T11:22:19+05:30,some-other-data", pos);
assertThat(result.toString()).isEqualTo("1999-11-22T11:22:19+05:30");
assertThat(pos.getIndex()).isEqualTo(35);

explicitGranularity

<smaller style="float:right;">source »</smaller>

This is useful if you need to handle different granularity with different logic or interpolation.

final TemporalHandler<OffsetDateTime> handler = new TemporalHandler<OffsetDateTime>()
        {
            @Override
            public OffsetDateTime handle(final LocalDate localDate)
            {
                return localDate.atTime(OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC));
            }

            @Override
            public OffsetDateTime handle(final OffsetDateTime offsetDateTime)
            {
                return offsetDateTime;
            }
        };
final OffsetDateTime result = ITU.parse("2017-12-06", handler);
assertThat(result.toString()).isEqualTo("2017-12-06T00:00Z");

lenientTimestamp

<smaller style="float:right;">source »</smaller>

In some real world scenarios, it is useful to parse a best-effort timestamp. To ease usage, we can easily convert a raw DateTime instance into Instant.

Note the limitations and the assumption of UTC time-zone, as mentioned in the javadoc.

final Instant instant = ITU.parseLenient("2017-12-06").toInstant();
assertThat(instant.toString()).isEqualTo("2017-12-06T00:00:00Z");

parseCustomFormat

<smaller style="float:right;">source »</smaller>

In case the format is not supported directly, you can build your own parser.

final DateTimeParser parser = DateTimeParsers.of(
                digits(DAY, 2),
                separators('-'),
                digits(MONTH, 2),
                separators('-'),
                digits(YEAR, 4),
                separators(' '),
                digits(HOUR, 2),
                digits(MINUTE, 2),
                digits(SECOND, 2),
                separators(','),
                fractions()
        );
final String text = "31-12-2000 235937,123456";
final DateTime result = parser.parse(text);
assertThat(result.toString()).isEqualTo("2000-12-31T23:59:37.123456");

parseUsingInterfaceRfc33939

<smaller style="float:right;">source »</smaller>

DateTimerParser interface for RFC-3339.

final DateTimeParser parser = DateTimeParsers.rfc3339();
final String text = "2000-12-31 23:59:37.123456";
final DateTime result = parser.parse(text);
assertThat(result.toString()).isEqualTo("2000-12-31T23:59:37.123456");

parseUsingInterfaceLocalTime

<smaller style="float:right;">source »</smaller>

DateTimerParser interface for local time.

final DateTimeParser parser = DateTimeParsers.localTime();
final String text = "23:59:37.123456";
final LocalTime result = parser.parse(text).toLocalTime();
assertThat(result.toString()).isEqualTo(text);

parseUsingInterfaceLocalDate

<smaller style="float:right;">source »</smaller>

DateTimerParser interface for local date.

final DateTimeParser parser = DateTimeParsers.localDate();
final String text = "2013-12-24";
final LocalDate result = parser.parse(text).toLocalDate();
assertThat(result.toString()).isEqualTo(text);

Formatting

This is a collection of usage examples for formatting.

formatRfc3339WithUTC

<smaller style="float:right;">source »</smaller>

The simplest and fastest way to format an RFC-3339 timestamp by far!

final OffsetDateTime input = OffsetDateTime.of(2012, 12, 27, 19, 7, 22, 123456789, ZoneOffset.ofHoursMinutes(-3, 0));
assertThat(ITU.formatUtcNano(input)).isEqualTo("2012-12-27T22:07:22.123456789Z");
assertThat(ITU.formatUtcMicro(input)).isEqualTo("2012-12-27T22:07:22.123456Z");
assertThat(ITU.formatUtcMilli(input)).isEqualTo("2012-12-27T22:07:22.123Z");
assertThat(ITU.formatUtc(input)).isEqualTo("2012-12-27T22:07:22Z");

formatWithDateTime

<smaller style="float:right;">source »</smaller>

Format with DateTime.

final DateTime input = DateTime.of(2020, 11, 27, 12, 39, 19, null);
assertThat(input.toString(Field.MINUTE)).isEqualTo("2020-11-27T12:39");
assertThat(input.toString(Field.SECOND)).isEqualTo("2020-11-27T12:39:19");

Leap-second handling

parseLeapSecond

<smaller style="float:right;">source »</smaller>

Parse a valid leap-second (i.e. it is on a date that would allow for it, and it is also in the list of known actual leap-seconds).

try
        {
            ITU.parseDateTime("1990-12-31T15:59:60-08:00");
        }
        catch (LeapSecondException exc)
        {
            // The following helper methods are available let you decide how to progress
            assertThat(exc.getSecondsInMinute()).isEqualTo(60);
            assertThat(exc.getNearestDateTime()).isEqualTo(OffsetDateTime.of(1990, 12, 31, 16, 0, 0, 0, ZoneOffset.ofHours(-8)));
            assertThat(exc.isVerifiedValidLeapYearMonth()).isTrue();
        }

Duration Parser

Parses a duration string, a strict subset of ISO 8601 durations.

Supported Units

This method supports time-based durations with the following units:

  • Weeks (W)
  • Days (D)
  • Hours (H)
  • Minutes (M)
  • Seconds (S), including fractional seconds up to nanosecond precision

Not Allowed Units

The following units are explicitly not allowed to avoid ambiguity:

  • Years (Y)
  • Months (M in the date section)

Negative Durations

Negative durations are supported and must be prefixe

Related Skills

View on GitHub
GitHub Stars35
CategoryDevelopment
Updated7mo ago
Forks10

Languages

Java

Security Score

87/100

Audited on Aug 13, 2025

No findings