JGlobalDateTime project

Easily compare instants with time zones in Java

By Manuel Domínguez-Dorado

Application development has evolved significantly over the last decade. Nowadays, no one develops applications (mobile, web, or desktop) without considering that potential users may be spread across the globe. And if that’s the case… synchronization must be considered. Like it or not, time zones exist and must be dealt with. Questions like “Does 14:35 in Beijing coincide with 21:12 in Afghanistan? Is it before or after?” may have more or less implications depending on what we’re developing. Do we have options in Java? Yes, we do.


At a Glance

Before Java 8, the options for managing different time zones in our developments weren’t particularly abundant or good. Libraries like Joda-Time came to fill that gap, offering a more than satisfactory solution. So satisfactory that the library kept growing and now offers a huge number of options. If you only need limited use of time zone comparison, it might be a bit too much.

Java 8 introduced a new API for managing dates, times, calendars… with time zone information. This API greatly simplifies the work compared to previous versions. But, as is usual in Java, it offers basic primitives that, if not encapsulated, make the source code very cumbersome.


What Is an Instant?

Before continuing, I’d like to explain something that confuses many people. Regardless of how a date/time is represented in different time zones, the instant it refers to is unique. An example makes it clearer:

  • Someone in Madrid sends an SMS at 16:00.
  • At the same time, someone in London sends another. But there it’s 15:00.

Obviously, the instant, the moment, is the same. If we represent this instant according to Madrid’s time zone, both occurred at 16:00. But if we do it with London’s time zone, both occurred at 15:00. If each one represents it according to their time zone, it seems like it’s not the same instant. But it only seems that way.

The key, therefore, is to have mechanisms to compare two date/time values regardless of the time zone they are referenced to. If something happened before, at the same time, or after another event in time, this should be knowable regardless of how that instant is represented.


The JGlobalDateTime Library

Some time ago, I decided to write a small Java library to help me manage and compare dates and times with time zone information. I called it JGlobalDateTime and published it on GitHub so anyone could use and modify it freely.

JGlobalDateTime logo


Why Another Library for the Same Thing?

For several reasons. The context in which I needed something like this was:

  • A Java backend, behind a series of firewalls, load balancers, and an Enterprise Service Bus (ESB).
  • An Android client application.
  • Approximately 1,000,000 users spread across more than 80 countries, using the mobile app against the backend.

Each client, user of the Android app, sends data to the backend. The data from all clients is related, and the order in which the data was generated by the different clients (not the order of arrival at the backend) was especially relevant. Therefore, I needed date and time comparison with time zone.

The mobile client sent this data in JSON format via a TLS connection, and the backend received and processed it considering the instant the data was generated. So it was very convenient to be able to compare based on a date in text format.

After processing, the backend stored in the database the information related to the origin instant of the data, so it was also useful to transform that information into the format of the DBMS being used: MySQL/MariaDB.

Also—and this was probably the main reason I decided to develop JGlobalDateTime—the library’s dependencies had to be minimal and the JAR size had to be small. Joda-Time was over half a MB and the raw Java 8 API cluttered the source code.


What Is JGlobalDateTime Useful For?

As mentioned above, if you have an application with a backend and a client used anywhere in the world and need to send textual information between both parts… JGlobalDateTime is useful. If the client is mobile (you have space constraints in the app) and you’re going to store date/time data in a database, it’s even more useful.


What License Does It Have?

I uploaded it to GitHub under the terms of the Apache 2.0 license. You can use it, fork it, extend it (if you send me a pull request with your changes, even better) under the terms of that license. The project site is JGlobalDateTime, and you can download the JAR from the releases section.


How Does It Work?

The main idea is that JGlobalDateTime establishes a common reference point from which comparisons are made. It doesn’t really matter what it is, as long as it’s the same. From there, something is done internally and the operation is simple.

Import the Package

import com.manolodominguez.jglobaldatetime.JGlobalDateTime;

Create Variables

JGlobalDateTime gdt1;
JGlobalDateTime gdt2;
JGlobalDateTime gdt3;
JGlobalDateTime gdt4;

Instantiate Variables

gdt1 = new JGlobalDateTime(); // current date/time with system default time zone
gdt2 = new JGlobalDateTime("2017-08-20T14:20:18.811-05:00[America/Chicago]");
gdt3 = new JGlobalDateTime(1428348018845L); // from milliseconds since EPOCH
gdt4 = new JGlobalDateTime(new Timestamp(1428348018845L)); // from JDBC Timestamp

Access Values

System.out.println("gdt1: " + gdt1.toNormalizedDateTimeString());
System.out.println("gdt2: " + gdt2.toNormalizedDateTimeString());
System.out.println("gdt3: " + gdt3.toNormalizedDateTimeString());
System.out.println("gdt4: " + gdt4.toNormalizedDateTimeString());

Change Time Zone

gdt1.changeZoneID("Pacific/Tahiti");
gdt3.changeZoneID("Australia/Sydney");
g.changeZoneID("Antarctica/South_Pole");

Make Comparisons

if (gdt1.isBefore(gdt2)) {
    System.out.println(gdt1.toNormalizedDateTimeString() + " happened before " + gdt2.toNormalizedDateTimeString());
} else if (gdt1.isAfter(gdt2)) {
    System.out.println(gdt1.toNormalizedDateTimeString() + " happened after " + gdt2.toNormalizedDateTimeString());
} else {
    System.out.println(gdt1.toNormalizedDateTimeString() + " happened at the same time as " + gdt2.toNormalizedDateTimeString());
}

Fuzzy Time Checks

if (gdt3.happenedSinceMoreThan(3, ChronoUnit.YEARS)) {
    System.out.println("gdt3 " + gdt3.toNormalizedDateTimeString() + " happened more than 3 years ago");
} else {
    System.out.println("gdt3 " + gdt3.toNormalizedDateTimeString() + " happened 3 years ago or less");
}

if (gdt1.isGoingToHappenInLessThan(7, ChronoUnit.DAYS)) {
    System.out.println("gdt1 " + gdt1.toNormalizedDateTimeString() + " will happen in less than 7 days");
} else {
    System.out.println("gdt1 " + gdt1.toNormalizedDateTimeString() + " will happen in 7 days or more");
}

Add or Subtract Units

gdt2.increase(4, ChronoUnit.MINUTES);
gdt3.decrease(1, ChronoUnit.YEARS);

Conclusion

JGlobalDateTime has many other options. In this article, I’ve tried to highlight only the most important ones. It’s released under a fairly permissive open-source license, so it may be useful to you and is unlikely to cause licensing conflicts in your software.

If you need very advanced operations with time zones, calendars… then use another library like Joda-Time, but if your needs are more modest, you’ll probably find JGlobalDateTime a very useful tool that adds very little extra space to your project.

In any case, the important thing is to have options to choose from.

Tags: projects