Skip to content

Commit

Permalink
Update dependencies and benchmarking code
Browse files Browse the repository at this point in the history
  • Loading branch information
ethlo committed Feb 26, 2022
1 parent f15b9d7 commit b872c7b
Show file tree
Hide file tree
Showing 29 changed files with 1,788 additions and 357 deletions.
1,183 changes: 1,183 additions & 0 deletions .editorconfig

Large diffs are not rendered by default.

71 changes: 46 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
# Internet Time Utility

[![Maven Central](https://img.shields.io/maven-central/v/com.ethlo.time/itu.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.ethlo.time%22%20a%3A%22itu%22)
[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](LICENSE)
[![Coverage Status](https://coveralls.io/repos/github/ethlo/itu/badge.svg?branch=master&kill_cache=1)](https://coveralls.io/github/ethlo/itu?branch=master)[![Build Status](https://travis-ci.org/ethlo/itu.svg?branch=master)](https://travis-ci.org/ethlo/itu)
[![Coverage Status](https://coveralls.io/repos/github/ethlo/itu/badge.svg?branch=master&kill_cache=1)](https://coveralls.io/github/ethlo/itu?branch=master)[![Build
Status](https://travis-ci.org/ethlo/itu.svg?branch=master)](https://travis-ci.org/ethlo/itu)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/598913bc1fe9405c82be73d9a4f105c8)](https://www.codacy.com/app/ethlo/itu?utm_source=github.com&utm_medium=referral&utm_content=ethlo/itu&utm_campaign=Badge_Grade)

An extremely fast parser and formatter of standardized date-times.

> Date and time formats cause a lot of confusion and interoperability problems on the Internet.
This document addresses many of the problems encountered and makes recommendations to improve consistency and interoperability when representing and using date and time in Internet protocols.
> Date and time formats cause a lot of confusion and interoperability problems on the Internet. This document addresses many of the problems encountered and makes recommendations to improve consistency and interoperability when representing and using date and time in Internet protocols.
This project's goal it to do one thing and to do it right; make it easy to handle [Date and Time on the Internet: Timestamps](https://www.ietf.org/rfc/rfc3339.txt) and W3C [Date and Time Formats](https://www.w3.org/TR/NOTE-datetime) in Java.
This project's goal it to do one thing and to do it right; make it easy to
handle [Date and Time on the Internet: Timestamps](https://www.ietf.org/rfc/rfc3339.txt) and
W3C [Date and Time Formats](https://www.w3.org/TR/NOTE-datetime) in Java.

## Features

* No external dependencies, minimalistic JAR
* Apache license
* Configurable validator, formatter and parser within the boundaries of the specification
Expand All @@ -20,18 +24,22 @@ This project's goal it to do one thing and to do it right; make it easy to handl
* Very high performance

## Performance
Implementation | Parse | Format
---------------|---------:|-----------:
java.util (Java 7) * | 742 850 parse/sec | 1 837 811 format/sec
java.time (Java 8) | 545 333 parse/sec | 2 101 431 format/sec
Apache FastDateUtils * | 1 076 995 parse/sec | 1 989 163 format/sec
Internet Time Utility | 15 569 458 parse/sec | 12 726 932 format/sec

* Single hard-coded format. Lenient parsing would require multiple patterns to be attempted (4-6).
<img src="doc/performance.jpg" alt="Performance plot">

| Implementation | Parse | Format | Round-trip |
-------------------|--------:|----------:|-----:|
| Google DateTime | 1,020 ns | Not supported | N/A
| JDK Java Time | 1,558 ns | 426 ns | 1,984 ns |
| Ethlo ITU | 88 ns |166 ns |254 ns|


Your milage may vary. The tests are included in this repository.
Values in nano-seconds. Lower is better.

Your mileage may vary. The tests are easy to run and are included in the repository.

## Example use

```java
// Parse a string
final OffsetDateTime dateTime = ITU.parseDateTime("2012-12-27T19:07:22.123456789-03:00");
Expand All @@ -42,15 +50,18 @@ final String formatted = ITU.formatUtc(dateTime); // 2012-12-27T22:07:22Z
// Format with microsecond precision
final String formattedMicro = ITU.formatUtcMicro(dateTime); // 2012-12-27T22:07:22.123457Z
```

## Q & A

*Why this little project?*

There are an endless amount of APIs with non-standard date/time exchange, and the goal of this project is to make it a no-brainer to do-the-right-thing(c).
There are an endless amount of APIs with non-standard date/time exchange, and the goal of this project is to make it a
no-brainer to do-the-right-thing(c).

*Why the performance optimized version?*

Some projects use epoch time-stamps for date-time exchange, and from a performance perspective this *may* make sense in *some* cases. With this project one can do-the-right-thing and maintain performance in date-time handling.
Some projects use epoch time-stamps for date-time exchange, and from a performance perspective this *may* make sense
in *some* cases. With this project one can do-the-right-thing and maintain performance in date-time handling.

*What is wrong with epoch timestamps?*

Expand All @@ -59,9 +70,13 @@ Some projects use epoch time-stamps for date-time exchange, and from a performan
* Unclear resolution and/or time-range

## What is RFC-3339?
[RFC-3339](https://www.ietf.org/rfc/rfc3339.txt) is a subset/profile defined by [W3C](https://www.w3.org/) of the formats defined in [ISO-8601](http://www.iso.org/iso/home/standards/iso8601.htm), to simplify date and time exhange in modern Internet protocols.

Typical formats include:
[RFC-3339](https://www.ietf.org/rfc/rfc3339.txt) is a subset/profile defined by [W3C](https://www.w3.org/) of the
formats defined in [ISO-8601](http://www.iso.org/iso/home/standards/iso8601.htm), to simplify date and time exhange in
modern Internet protocols.

Typical formats include:

* `2017-12-27T23:45:32Z` - No fractional seconds, UTC/Zulu time
* `2017-12-27T23:45:32.999Z` - Millisecond fractions, UTC/Zulu time
* `2017-12-27T23:45:32.999999Z` - Microsecond fractions, UTC/Zulu time
Expand All @@ -72,24 +87,30 @@ Typical formats include:
* `2017-12-27T18:45:32.999999999-05:00` - Nanosecond fractions, EST time

## What is W3C - Date and Time Formats
[Date and Time Formats](https://www.w3.org/TR/NOTE-datetime) is a _note_, meaning it is not endorsed, but it still serves as a sane subset of ISO-8601, just like RFC-3339.

Typical formats include:
[Date and Time Formats](https://www.w3.org/TR/NOTE-datetime) is a _note_, meaning it is not endorsed, but it still
serves as a sane subset of ISO-8601, just like RFC-3339.

Typical formats include:

* `2017-12-27T23:45Z` - Minute resolution, UTC/Zulu time
* `2017-12-27` - Date only, no timezone (like someones birthday)
* `2017-12` - Year and month only. Like an expiry date.

## Limitations

### Local offset
For the sake of avoiding data integrity issues, this library will not allow offset of `-00:00`.
Such offset is described in RFC3339 section 4.3., named "Unknown Local Offset Convention". Such offset is explicitly prohibited in ISO-8601 as well.

> If the time in UTC is known, but the offset to local time is unknown,
this can be represented with an offset of "-00:00". This differs
semantically from an offset of "Z" or "+00:00", which imply that UTC
is the preferred reference point for the specified time.
For the sake of avoiding data integrity issues, this library will not allow offset of `-00:00`. Such offset is described
in RFC3339 section 4.3., named "Unknown Local Offset Convention". Such offset is explicitly prohibited in ISO-8601 as
well.

> If the time in UTC is known, but the offset to local time is unknown, this can be represented with an offset of "-00:00". This differs semantically from an offset of "Z" or "+00:00", which imply that UTC is the preferred reference point for the specified time.
### Leap second parsing
Since Java's `java.time` classes do not support storing leap seconds, ITU will throw a `LeapSecondException` if one is encountered to signal that this is a leap second. The exception can then be queried for the second-value. Storing such values is not possible in a `java.time.OffsetDateTime`, the `60` is therefore abandoned and the date-time will use `59` instead of `60`.

Since Java's `java.time` classes do not support storing leap seconds, ITU will throw a `LeapSecondException` if one is
encountered to signal that this is a leap second. The exception can then be queried for the second-value. Storing such
values is not possible in a `java.time.OffsetDateTime`, the `60` is therefore abandoned and the date-time will use `59`
instead of `60`.

Binary file added doc/performance.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 36 additions & 24 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,46 @@
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<url>https://github.com/ethlo/itu</url>
<developers>
<developer>
<name>Morten Haraldsen</name>
<url>http://ethlo.com</url>
<url>https://ethlo.com</url>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert-core</artifactId>
<version>2.0M10</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.21.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.ethlo.time</groupId>
<artifactId>chronograph</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client</artifactId>
<version>1.41.4</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -49,7 +61,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<version>3.0.0-M5</version>
<configuration>
<excludes>
<exclude>**/*CorrectnessTest.java</exclude>
Expand All @@ -64,7 +76,7 @@
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
Expand All @@ -74,7 +86,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.4</version>
<version>0.8.7</version>
<executions>
<execution>
<id>prepare-agent</id>
Expand All @@ -92,7 +104,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<version>3.0.0-M5</version>
<configuration>
<excludes>
<exclude>**/*BenchmarkTest.java</exclude>
Expand All @@ -102,7 +114,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
Expand All @@ -115,7 +127,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
Expand All @@ -131,12 +143,12 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.3</version>
<version>2.8.1</version>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.5</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>sonatype-nexus-staging</serverId>
Expand All @@ -147,7 +159,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<version>3.0.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
Expand All @@ -164,7 +176,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>1.12</version>
<version>2.0.0</version>
<configuration>
<verbose>false</verbose>
<addSvnKeyWords>true</addSvnKeyWords>
Expand Down Expand Up @@ -204,19 +216,19 @@
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.12</version>
<version>3.4.3</version>
</extension>
</extensions>
</build>
<distributionManagement>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<scm>
<url>http://github.com:ethlo/itu</url>
<url>https://github.com:ethlo/itu</url>
<connection>scm:git:[email protected]:ethlo/itu.git</connection>
<developerConnection>scm:git:[email protected]:ethlo/itu.git</developerConnection>
</scm>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import java.util.Arrays;
import java.util.Date;

public class FastInternetDateTimeUtil extends AbstractRfc3339 implements W3cDateTimeUtil
public class EthloITU extends AbstractRfc3339 implements W3cDateTimeUtil
{
public static final int LEAP_SECOND_SECONDS = 60;
private static final char PLUS = '+';
Expand All @@ -46,7 +46,7 @@ public class FastInternetDateTimeUtil extends AbstractRfc3339 implements W3cDate
private static final char ZULU_UPPER = 'Z';
private static final char ZULU_LOWER = 'z';
private static final int[] widths = new int[]{100_000_000, 10_000_000, 1_000_000, 100_000, 10_000, 1_000, 100, 10, 1};
private final StdJdkInternetDateTimeUtil delegate = new StdJdkInternetDateTimeUtil();
private final Java8Rfc3339 delegate = new Java8Rfc3339();

@Override
public OffsetDateTime parseDateTime(String s)
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/ethlo/time/ITU.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

public class ITU
{
private static final FastInternetDateTimeUtil delegate = new FastInternetDateTimeUtil();
private static final EthloITU delegate = new EthloITU();
private static final ZoneId GMT_ZONE = ZoneId.of("GMT");

private ITU()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
*
* @author ethlo - Morten Haraldsen
*/
public class StdJdkInternetDateTimeUtil extends AbstractRfc3339
public class Java8Rfc3339 extends AbstractRfc3339
{
private SimpleDateFormat[] formats = new SimpleDateFormat[MAX_FRACTION_DIGITS];

Expand Down Expand Up @@ -86,7 +86,7 @@ public class StdJdkInternetDateTimeUtil extends AbstractRfc3339

.toFormatter();

public StdJdkInternetDateTimeUtil()
public Java8Rfc3339()
{
for (int i = 1; i < MAX_FRACTION_DIGITS; i++)
{
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/ethlo/time/LeapSecondException.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down
Loading

0 comments on commit b872c7b

Please sign in to comment.