Joda DateTime to Timestamp conversion

It is a common misconception that time (a measurable 4th dimension) is different over the world. Timestamp as a moment in time is unique. Date however is influenced how we “see” time but actually it is “time of day”.

An example: two people look at the clock at the same moment. The timestamp is the same, right? But one of them is in London and sees 12:00 noon (GMT, timezone offset is 0), and the other is in Belgrade and sees 14:00 (CET, Central Europe, daylight saving now, offset is +2).

Their perception is different but the moment is the same.

You can find more details in this answer.

UPDATE

OK, it’s not a duplicate of this question but it is pointless since you are confusing the terms “Timestamp = moment in time (objective)” and “Date[Time] = time of day (subjective)”.

Let’s look at your original question code broken down like this:

// Get the "original" value from database.
Timestamp momentFromDB = rs.getTimestamp("anytimestampcolumn");

// Turn it into a Joda DateTime with time zone.
DateTime dt = new DateTime(momentFromDB, DateTimeZone.forID("anytimezone"));

// And then turn it back into a timestamp but "with time zone".
Timestamp ts = new Timestamp(dt.getMillis());

I haven’t run this code but I am certain it will print true and the same number of milliseconds each time:

System.out.println("momentFromDB == dt : " + (momentFromDB.getTime() == dt.getTimeInMillis());
System.out.println("momentFromDB == ts : " + (momentFromDB.getTime() == ts.getTime()));
System.out.println("dt == ts : " + (dt.getTimeInMillis() == ts.getTime()));

System.out.println("momentFromDB [ms] : " + momentFromDB.getTime());
System.out.println("ts [ms] : " + ts.getTime());
System.out.println("dt [ms] : " + dt.getTimeInMillis());

But as you said yourself printing them out as strings will result in “different” time because DateTime applies the time zone. That’s why “time” is stored and transferred as Timestamp objects (which basically wraps a long) and displayed or entered as Date[Time].

In your own answer you are artificially adding an offset and creating a “wrong” time. If you use that timestamp to create another DateTime and print it out it will be offset twice.

// Turn it back into a Joda DateTime with time zone.
DateTime dt = new DateTime(ts, DateTimeZone.forID("anytimezone"));

P.S. If you have the time go through the very complex Joda Time source code to see how it holds the time (millis) and how it prints it.

JUnit Test as proof

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

import org.junit.Before;
import org.junit.Test;


public class WorldTimeTest {
    private static final int MILLIS_IN_HOUR = 1000 * 60 * 60;
    private static final String ISO_FORMAT_NO_TZ = "yyyy-MM-dd'T'HH:mm:ss.SSS";
    private static final String ISO_FORMAT_WITH_TZ = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";

    private TimeZone londonTimeZone;
    private TimeZone newYorkTimeZone;
    private TimeZone sydneyTimeZone;
    private long nowInMillis;
    private Date now;

    public static SimpleDateFormat createDateFormat(String pattern, TimeZone timeZone) throws Exception {
        SimpleDateFormat result = new SimpleDateFormat(pattern);
        // Must explicitly set the time zone with "setCalendar()".
        result.setCalendar(Calendar.getInstance(timeZone));
        return result;
    }

    public static SimpleDateFormat createDateFormat(String pattern) throws Exception {
        return createDateFormat(pattern, TimeZone.getDefault());
    }

Leave a Comment