Jim Moody
Jim Moody

Reputation: 808

Incorrect date when converting unix epoch to human readable using Java

EDIT: Removed the '*1000' and still getting incorrect date but updated the log below to show what I am now getting.

Below is my code snippet and my log and I thought I implemented it correctly so I don't know why it isn't giving me the correct conversion:

NewFoodItem foodItem = data.get(position);
String date = new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new java.util.Date (foodItem.date));
String a =  Integer.toString(foodItem.date);
Log.d("returnedDate:", a);
Log.d("formattedDate:", date);

It won't let me post an image but the log looks like this:

D/returnedDate:  1409012824
D/formattedDate: 01/17/1970 02:23:32
D/returnedDate:  1409013004
D/formattedDate: 01/17/1970 02:23:33

Upvotes: 1

Views: 2136

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 339561

The Answer by Andrew T. is correct: integer overflow. But the example code is now outmoded.

java.time

The modern approach uses the java.time classes.

The Instant class represents a moment. Like java.util.Date, Instant counts from the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00Z. But Instant uses a finer resolution of nanoseconds rather than milliseconds.

Append an L to the end of your numeric literal to indicate long type. Use underscores wherever you like to group your digits, with no meaning added (ignored by compiler).

long input = 1_409_012_824L ;
Instant instant = Instant.ofEpochSecond( input ) ;

Generate a textual representation of the value in standard ISO 8601 format.

String output = instant.toString() ;

2014-08-26T00:27:04Z

For more flexibility in generating text, convert to a OffsetDateTime.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

Automatically localize the output using a DateTimeFormatter.

Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).withLocale( locale ) ;
String output2 = odt.format( f ) ;

Aug 26, 2014, 12:27:04 AM

See this code run live at IdeOne.com.


Table of date-time types in Java, both modern and legacy.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

Table of which java.time library to use with which version of Java or Android

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Upvotes: 3

Andrew T.
Andrew T.

Reputation: 4707

I just tested with some assumption, and it seems that the problem is related to integer overflow.

I assume you defined NewFoodItem.date as int, instead of long. Hence, when you multiply the date * 1000 (both are int), it returns int.

int d = 1409012824; // foodItem.date
int d1000 = d * 1000; // returns 263550912 because of overflow, instead of 1409012824000

String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
    .format(new Date(d1000)); // returns 01/04/1970 08:42:30

When I try changing one of them to long, it behaves as expected

// case 1
long d = 1409012824;
long d1000 = d * 1000; // now returns 1409012824000 correctly

String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
    .format(new Date(d1000)); // returns 08/26/2014 08:27:04

// case 2
int d = 1409012824;
long d1000 = d * 1000L; // note the "L" suffix to indicate the number as long 
long d1000f = d * 1000; // FAIL, still returns 263550912 because of integer overflow

String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
    .format(new Date(d1000)); // returns 08/26/2014 08:27:04
String date = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
    .format(new Date(d1000f)); // returns 01/04/1970 08:42:30

Generally when working with Date in Java, we define them as long since normally they are in millisecond. For easier maintenance, changing the type of NewFoodItem.date as long is the preferred one; much better if it's in millisecond also.

Upvotes: 2

Related Questions