javatimestampepochzone

Some dates cannot be converted correctly in Java to an epoch timestamps at the midnight of a specific timezone


This Java code, given a date as a string, is supposed to print the epoch timestamp for the same date at the midnight for the CET zone (supposing I'm not in the same zone).

public static void main(String[] args) throws ParseException {

    String dateStr = "1995-06-06";

    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
    formatter.setTimeZone(TimeZone.getTimeZone("CET"));
    Date date = formatter.parse(dateStr);
    Calendar c = new GregorianCalendar();
    c.setTimeZone(TimeZone.getTimeZone("CET"));
    c.setTime(date);

    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);

    System.out.println("Epoch timestamp = " + c.getTime().getTime());
}

If I run the above program I should get printed:

 Epoch timestamp = 802389600000

And I can verify it's correct here:

https://www.epochconverter.com/timezones?q=802389600&tz=Europe%2FMalta

Now, that works for most of the dates. However, there are some bizarre dates like "1975-09-19", where it doesn't work. In fact, It generates 180313200000 as a timestamp, which gives 1am and not midnight:

https://www.epochconverter.com/timezones?q=180313200&tz=Europe%2FMalta

Can you explain why? What am I missing?


Solution

  • Time zone discrepancy

    Your Java code uses CET, which is not really a time zone (for example because most of the areas where it’s used use CEST instead for most of the year). Java translates CET to Europe/Paris. France and Paris did not use summer time (DST) in 1975. It was reintroduced in March 1976.

    Your link to the epoch converter specifies Malta time zone (Europe/Malta). Malta did use summer time in 1975: it was on CEST from 20 April to 21 September that year.

    This explains the difference in your results.

    In Java code

    If you wanted Malta time:

        String dateStr = "1975-09-19";
    
        long epochTimestamp = 
                LocalDate 
                .parse(dateStr)                            
                .atStartOfDay(ZoneId.of("Europe/Malta"))
                .toInstant()
                .toEpochMilli();
    
        System.out.println("Epoch timestamp = " + epochTimestamp);
    

    This prints:

    Epoch timestamp = 180309600000

    And the epoch converter that you linked to is happy to agree:

    Conversion results (180309600)

    180309600 converts to Friday September 19, 1975 00:00:00 (am) in time zone Europe/Malta (CEST) The offset (difference to Greenwich Time/GMT) is +02:00 or in seconds 7200. This date is in daylight saving time.

    In Java do use java.time, the modern Java date and time API, for your date and time work. It is so much nicer to work with compared to the old date and time classes like SimpleDateFormat, TimeZone, Date and Calendar. Also setting the hours, etc., to 0 is not the correct way to get the first moment of the day. There are cases where summer time begins at the start of the day, so the first moment of the day is 01:00:00. Java knows that, so the atStartOfDay method will give you the correct forst moment of the day in question.

    And no matter if using outdated or modern classes always specify time zone in the region/city format, for example Europe/Paris or Europe/Malta. The three, four and five letter time zone abbreviations are often ambiguous and often not true time zones, so not to be relied on.

    Links