mmmiki
mmmiki

Reputation: 1409

Converting Long to Date in Java returns 1970

I have list with long values (for example: 1220227200, 1220832000, 1221436800...) which I downloaded from web service. I must convert it to Dates. Unfortunately this way, for example:

Date d = new Date(1220227200);

returns 1 Jan 1970. Anyone know another way to convert it correctly?

Upvotes: 140

Views: 446132

Answers (12)

BalusC
BalusC

Reputation: 1109112

The constructor of java.util.Date taking the date as a long argument interprets the argument in milliseconds, not seconds.

Parameters: date - the milliseconds since January 1, 1970, 00:00:00 GMT.

Your value is in seconds, so you need to convert it to milliseconds. You can either multiply it by 1000 or use the TimeUnit helper.

Date date = new Date(TimeUnit.SECONDS.toMillis(1220227200));

This prints here:

Sun Aug 31 20:00:00 GMT-04:00 2008

Which equals to 1 september 2008 at 00:00 UTC.

In case you're already on Java 8 or newer, it's better to use Instant#ofEpochSecond() instead. This way you don't need to convert seconds to milliseconds even though there's also a Instant#ofEpochMilli() method.

Instant instant = Instant.ofEpochSecond(1220227200);

This prints here:

2008-09-01T00:00:00Z

Upvotes: 191

Andrew Samsonov
Andrew Samsonov

Reputation: 42

Because 1220227200 ms = 338,952 hours. java.util.Date has constructor new Date(Long milliseconds) - Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT. So, in your case just remember 1 sec = 1000 millisec

Upvotes: 0

Basil Bourque
Basil Bourque

Reputation: 339303

tl;dr

java.time.Instant                    // Represent a moment as seen in UTC. Internally, a count of nanoseconds since 1970-01-01T00:00Z.
.ofEpochSecond( 1_220_227_200L )     // Pass a count of whole seconds since the same epoch reference of 1970-01-01T00:00Z.

Know Your Data

People use various precisions in tracking time as a number since an epoch. So when you obtain some numbers to be interpreted as a count since an epoch, you must determine:

  • What epoch?
    Many epochs dates have been used in various systems. Commonly used is POSIX/Unix time, where the epoch is the first moment of 1970 in UTC. But you should not assume this epoch.
  • What precision?
    Are we talking seconds, milliseconds, microseconds, or nanoseconds since the epoch?
  • What time zone?
    Usually a count since epoch is in UTC/GMT time zone, that is, has no time zone offset at all. But sometimes, when involving inexperienced or date-time ignorant programmers, there may be an implied time zone.

In your case, as others noted, you seem to have been given seconds since the Unix epoch. But you are passing those seconds to a constructor that expects milliseconds. So the solution is to multiply by 1,000.

Lessons learned:

  • Determine, don't assume, the meaning of received data.
  • Read the doc.

Graph showing various granularities of resolution in date-time systems including whole seconds, milliseconds, microseconds, and nanoseconds.

Your Data

Your data seems to be in whole seconds. If we assume an epoch of the beginning of 1970, and if we assume UTC time zone, then 1,220,227,200 is the first moment of the first day of September 2008.

Joda-Time

The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use instead either the Joda-Time library or the new java.time package bundled in Java 8 (and inspired by Joda-Time).

Note that unlike j.u.Date, a DateTime in Joda-Time truly knows its own assigned time zone. So in the example Joda-Time 2.4 code seen below, note that we first parse the milliseconds using the default assumption of UTC. Then, secondly, we assign a time zone of Paris to adjust. Same moment in the timeline of the Universe, but different wall-clock time. For demonstration, we adjust again, to UTC. Almost always better to explicitly specify your desired/expected time zone rather than rely on an implicit default (often the cause of trouble in date-time work).

We need milliseconds to construct a DateTime. So take your input of seconds, and multiply by a thousand. Note that the result must be a 64-bit long as we would overflow a 32-bit int.

long input = 1_220_227_200L;  // Note the "L" appended to long integer literals.
long milliseconds = ( input * 1_000L ); // Use a "long", not the usual "int". Note the appended "L".

Feed that count of milliseconds to constructor. That particular constructor assumes the count is from the Unix epoch of 1970. So adjust time zone as desired, after construction.

Use proper time zone names, a combination of continent and city/region. Never use 3 or 4 letter codes such as EST as they are neither standardized not unique.

DateTime dateTimeParis = new DateTime( milliseconds ).withZone( DateTimeZone.forID( "Europe/Paris" ) );

For demonstration, adjust the time zone again.

DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );

Dump to console. Note how the date is different in Montréal, as the new day has begun in Europe but not yet in America.

System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUTC: " + dateTimeUtc );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );

When run.

dateTimeParis: 2008-09-01T02:00:00.000+02:00
dateTimeUTC: 2008-09-01T00:00:00.000Z
dateTimeMontréal: 2008-08-31T20:00:00.000-04:00

java.time

The makers of Joda-Time have asked us to migrate to its replacement, the java.time framework as soon as is convenient. While Joda-Time continues to be actively supported, all future development will be done on the java.time classes and their extensions in the ThreeTen-Extra project.

The java-time framework is defined by JSR 310 and built into Java 8 and later. The java.time classes have been back-ported to Java 6 & 7 on the ThreeTen-Backport project and to Android in the ThreeTenABP project.

An Instant is a moment on the timeline in UTC with a resolution of nanoseconds. Its epoch is the first moment of 1970 in UTC.

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

Apply an offset-from-UTC ZoneOffset to get an OffsetDateTime.

Better yet, if known, apply a time zone ZoneId to get a ZonedDateTime.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

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

Upvotes: 83

abhimanyu
abhimanyu

Reputation: 894

Try this with adjusting the date format.

long longtime = 1212580300;
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyHHmm");
Date date = (Date) dateFormat.parseObject(longtime + "");
System.out.println(date);

Note: Check for 24 hours or 12 hours cycle.

Upvotes: 3

Marlon
Marlon

Reputation: 149

Only set the time in mills on Calendar object

Calendar c = Calendar.getInstance();
c.setTimeInMillis(1385355600000l);
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// get Date
System.out.println(c.getTime());

Upvotes: 14

Jack G.
Jack G.

Reputation: 3941

The long values, most likely, correspond to Epoch timestamps, and the values are:

1220227200 = Mon, 01 Sep 2008 00:00:00 GMT

1220832000 = Mon, 08 Sep 2008 00:00:00 GMT

1221436800 = Mon, 15 Sep 2008 00:00:00 GMT

One can convert these long values to java.util.Date, taking into account the fact java.util.Date uses millisecs – as previously hinted, but with some flaw - like this:

// note: enforcing long literals (L), without it the values would just be wrong.
Date date = new Date(1220227200L * 1000L); 

Now, to display the date correctly, one can use java.text.DateFormat as illustrated hereafter:

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Wrong date time value: " + date);
System.out.println("Correct date time value: " + df.format(date));

Below are the results of displaying the converted long value to java.util.Date without using and using the DateFormat:

Date wrong (off by 2 hours): Mon Sep 01 02:00:00 CEST 2008
Correct date : Monday, 1 September 2008 00:00:00 o'clock UTC

Upvotes: 6

Mohammad Namvar
Mohammad Namvar

Reputation: 49

Try this:

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1220227200 * 1000);
System.out.println(cal.getTime());

Upvotes: 4

Shivan Dragon
Shivan Dragon

Reputation: 15229

1220227200 corresponds to Jan 15 1980 (and indeed new Date(1220227200).toString() returns "Thu Jan 15 03:57:07 CET 1970"). If you pass a long value to a date, that is before 01/01/1970 it will in fact return a date of 01/01/1970. Make sure that your values are not in this situation (lower than 82800000).

Upvotes: 2

leifg
leifg

Reputation: 9008

Works for me. You probably want to multiplz it with 1000, since what you get are the seconds from 1970 and you have to pass the milliseconds from jan 1 1970

Upvotes: 0

Edwin Buck
Edwin Buck

Reputation: 70929

New Date(number) returns a date that's number milliseconds after 1 Jan 1970. Odds are you date format isn't showing hours, minutes, and seconds for you to see that it's just a little bit after 1 Jan 1970.

You need to parse the date according to the correct parsing routing. I don't know what a 1220227200 is, but if it's seconds after 1 JAN 1970, then multiply it to yield milliseconds. If it is not, then convert it in some manner to milliseconds after 1970 (if you want to continue to use java.util.Date).

Upvotes: 0

Magnus Winter
Magnus Winter

Reputation: 931

Those are probably timestamps in seconds and not in milliseconds which is required for the java new Date(long) constructor. Just multiply them by 1000 and you should be allright.

Upvotes: 9

Codemwnci
Codemwnci

Reputation: 54904

It looks like your longs are seconds, and not milliseconds. Date constructor takes time as millis, so

Date d = new Date(timeInSeconds * 1000);

Upvotes: 47

Related Questions