Search code examples
javadatetimestampjodatimedate-conversion

Joda DateTime Issue with Year


When I run the following code snippet:

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;

public class TimestampTest {

    public static void main(String... args) throws Exception {
        Date aDate1880 = new Date(-20, 0, 1);
        Timestamp timestamp = new Timestamp(aDate1880.getTime());
        DateTime dateTime = new DateTime(timestamp).withZoneRetainFields(DateTimeZone.getDefault());

        System.out.println(dateTime.year().get());

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(timestamp);

        System.out.println(calendar.get(Calendar.YEAR));
    }
}

I get the following output:

1879
1880

As aDate1880 does actually represents year 1880 I don't know why Joda DateTime gives year as 1879. Any help would be appreciated.


Solution

  • This code:

    Date aDate1880 = new Date(-20, 0, 1);
    

    Creates a Date equivalent to January 1st 1880. As the time fields were not provided, they are set to midnight at the JVM default timezone. In my case, it's "America/Sao_Paulo", so the results below might be different in your case - but it'd explain what's happening anyway. In my case, the date created is:

    Thu Jan 01 00:00:00 BRT 1880

    (January 1st 1880 at midnight in America/Sao_Paulo timezone - BRT means "Brazilian Time")

    Calling aDate1880.getTime() returns the value -2840130000000, which corresponds in UTC to 1880-01-01T03:00:00Z.

    When converting to DateTime, it uses joda-time internal timezone data, an in my case the DateTime is:

    1879-12-31T23:53:32.000-03:06:28

    That's because before 1900, many countries didn't use current timezone rules, and most cities had their own local time. And most offsets were calculated based on the longitude, and that's why it has such strange results like "-03:06:28".

    Probably your timezone has a similar issue.

    Note: new DateTime(timestamp) already uses the default timezone, so the call to withZoneRetainFiels is redundant:

    DateTime dateTime = new DateTime(timestamp);
    // this prints "true"
    System.out.println(dateTime.equals(dateTime.withZoneRetainFields(DateTimeZone.getDefault())));
    

    To create the date you want, you can use only Joda-Time classes:

    // January 1st 1880, at midnight in JVM default timezone
    DateTime d = new LocalDate(1880, 1, 1).toDateTimeAtStartOfDay();