0

Using java.time's Instant and java.sql's Timestamp, why do these:

System.out.println("epoch: " + Instant.EPOCH);
System.out.println("timestamp: " + Timestamp.from(Instant.EPOCH));

produce different results:

epoch: 1970-01-01T00:00:00Z
timestamp: 1970-01-01 01:00:00.0
Toni
  • 73
  • 1
  • 2
  • 11
  • 3
    they don't, it's just the formatting that is different. – Stultuske Jun 18 '21 at 12:48
  • Related: [Java - Convert java.time.Instant to java.sql.Timestamp without Zone offset](https://stackoverflow.com/questions/42766674/java-convert-java-time-instant-to-java-sql-timestamp-without-zone-offset) – Ole V.V. Jun 19 '21 at 10:05

2 Answers2

1

The Timestamp class injects the JVM‘s current default time zone. One of many reasons why you should never use these legacy date-time classes. Use only their replacement, the java.time classes. Sun, Oracle, and the JCP community gave up on these wretched date-time classes such as Date, Calendar, and Timestamp with their unanimous adoption of JSR 310.

Your JVM’s current default time zone on the first moment of 1970 as seen in UTC was using an offset-from-UTC of one hour ahead. Hence the 1 AM display, adding one hour to the same simultaneous moment with a time of 00:00 seen in places such as Iceland whose offset from UTC on that date at that time was zero hours-minutes-seconds.

Another problem with that output from Timestamp#toString is that it neglects to indicate its time zone or offset-from-UTC. In contrast, the java.time.Instant#toString method puts a Z on the end to indicate, per ISO 8601 standard, an offset of zero hours-minutes-seconds.

The Instant class represents a moment in UTC, always UTC, an offset of zero. So no such confusion and ambiguity as with Timestamp.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Why does Instant.EPOCH and Timestamp.from(Instant.EPOCH) return different results?

Echoing Stultuske's comment:

they don't, it's just the formatting that is different.

Let's see how

Given below is the hierarchy of java.sql.Timestamp:

java.lang.Object
    java.util.Date
        java.sql.Timestamp

On the same page of the documentation, you will find the following information:

The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.

The implementation inheritance is a way of reusing the code of the superclass in a subclass and type inheritance is a way of specializing (subclassing) a supertype for a specific implementation**.

The purpose of creating java.sql.Timestamp has been summarized in the following line on the same page of the documentation:

A thin wrapper around java.util.Date that allows the JDBC API to identify this as an SQL TIMESTAMP value.

So, do not expect java.sql.Timestamp to be much different from java.util.Date.

About java.util.Date:

A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.

Date date = new Date();

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);

sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = sdf.format(date);

sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = sdf.format(date);

On the other hand, An Instant represents an instantaneous point on the timeline in UTC.

Putting all in a demo:

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        System.out.println("Instant:   " + Instant.EPOCH);
        System.out.println("Timestamp: " + epochMilliFormatted());
    }

    public static String epochMilliFormatted() {
        Date date = new Date(Timestamp.from(Instant.EPOCH).getTime());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH);
        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        return sdf.format(date);
    }
}

Output:

Instant:   1970-01-01T00:00:00Z
Timestamp: 1970-01-01T00:00:00Z

The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).

ONLINE DEMO

Note: The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*. Learn more about the modern Date-Time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

** To learn more about the implementation inheritance and the type inheritance, check the following links:
  1. Multiple Inheritance of State, Implementation, and Type
  2. implementation inheritance vs type inheritance
  3. difference between interface inheritance and implementation inheritance
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110