Skip to content

Best Practices

Java offers two sets of date and time APIs. Unless dealing with legacy code, it's best to stick with the new API. However, if you need to convert between them, here's how:

Old API to New API

To convert old Date or Calendar objects to the new API, you can use the toInstant() method to get an Instant, which can then be converted to ZonedDateTime:

java
// Date -> Instant:
Instant ins1 = new Date().toInstant();

// Calendar -> Instant -> ZonedDateTime:
Calendar calendar = Calendar.getInstance();
Instant ins2 = calendar.toInstant();
ZonedDateTime zdt = ins2.atZone(calendar.getTimeZone().toZoneId());

You can see that the old TimeZone provides a toZoneId() method to convert to the new ZoneId.

New API to Old API

To convert ZonedDateTime back to the old API, you can use a long timestamp as an intermediary:

java
// ZonedDateTime -> long:
ZonedDateTime zdt = ZonedDateTime.now();
long ts = zdt.toEpochSecond() * 1000; // Convert to milliseconds

// long -> Date:
Date date = new Date(ts);

// long -> Calendar:
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTimeZone(TimeZone.getTimeZone(zdt.getZone().getId()));
calendar.setTimeInMillis(ts);

Storing Dates and Times in Databases

Apart from java.util.Date, there's java.sql.Date, which ignores time-related information. In databases, there are several types for storing date and time:

  • DATETIME: Represents date and time.
  • DATE: Represents only the date.
  • TIME: Represents only the time.
  • TIMESTAMP: Similar to DATETIME but updates automatically on record creation or update.

Here's how these database types map to Java classes:

Database TypeCorresponding Java Class (Old)Corresponding Java Class (New)
DATETIMEjava.util.DateLocalDateTime
DATEjava.sql.DateLocalDate
TIMEjava.sql.TimeLocalTime
TIMESTAMPjava.sql.TimestampLocalDateTime

The most common type to store in a database is Instant, as it allows you to display the correct local time based on the user's timezone. It's best to store this as a long integer (e.g., BIGINT).

You can create a timestampToString() method to display different local times based on preferences:

java
import java.time.*;
import java.time.format.*;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        long ts = 1574208900000L;
        System.out.println(timestampToString(ts, Locale.CHINA, "Asia/Shanghai"));
        System.out.println(timestampToString(ts, Locale.US, "America/New_York"));
    }

    static String timestampToString(long epochMilli, Locale lo, String zoneId) {
        Instant ins = Instant.ofEpochMilli(epochMilli);
        DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT);
        return f.withLocale(lo).format(ZonedDateTime.ofInstant(ins, ZoneId.of(zoneId)));
    }
}

Summary

  • Always prefer the new java.time package for date and time handling.
  • When storing timestamps in a database, using a long integer provides space efficiency and high performance without relying on the database's date/time types.
Best Practices has loaded