2

I have this unix timestamp in milliseconds: -62135769600000

I tried to convert the timestamp using java and javascript, but I got two different response. look below:

Date d = new Date(-62135769600000L);
System.out.println(d); // output = Sat Jan 01 00:00:00 GMT 1
d = new Date(-62135769600000L)
console.log(d) // output = Fri Dec 29 0000 19:00:00 GMT-0500 (EST)

As you can see, we have two different results. I want to understand why and if possible how to fix that.

hubert
  • 2,997
  • 3
  • 20
  • 26
  • 1
    Have you tried the code with a more reasonable timestamp, like the timestamp of right now instead of some wonky negative value!? – luk2302 Feb 17 '21 at 16:25
  • Java Date and LocalDate do not have the concept of timezone. You should consider moving to java LocalDateTime – possum Feb 17 '21 at 16:25
  • 2
    I recommend that in Java you don’t use `java.util.Date`. That class is poorly designed and long outdated. Instead use `Instant` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Feb 17 '21 at 16:45
  • 1
    It’s probably the difference between [Julian](https://en.wikipedia.org/wiki/Julian_calendar) and [proleptic Gregorian](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar) calendars. `java.util.Date` uses Julian, I don’t know about JavaScript. – Ole V.V. Feb 17 '21 at 16:48
  • 2
    @OleV.V. yes it is; j.u.Date 'normalizes' to a calendar anytime you do silly things with it (as in, turning an epochmillis into human concepts, which toString itself also does), and that normalizer code will use julian if the timestamp is before a hardcoded cutoff, which OP's near-year-0 timestamp most definitely is. See my answer. – rzwitserloot Feb 17 '21 at 16:49
  • @luk2302 this date is coming from the data base. Is a rest endpoint and I consume that in SPA application. I don't know what it means. But it is a correct date. – hubert Feb 17 '21 at 19:17
  • No, that is most likely not a valid date, does year 0 make sense in your context? I doubt it - this is probably a placeholder / dummy / invalid marker and should not be parsed / displayed – luk2302 Feb 17 '21 at 19:19

2 Answers2

3

First, a lesson: java.util.Date is dumb, broken, and should never be used. The right way to do time stuff in java is with the java.time package.

Then, to explain your observed differences:

  • javascript is reporting the time by translating the moment-in-time as represented by using the gregorian calendar, and as if you were in the EST timezone.
  • java's Date is reporting the time as if it was the julian calendar, and at the GMT timezone.

The timezone difference explains why javascript prints 19:00 and java prints 00:00, as well as 1 date's worth of difference. When you clap your hands at 19:00 in New York on dec 29th, at that very instant in time, it is exactly midnight, dec 30th, in london. The remaining exactly 48 hours (2 days) of difference is because of the julian calendar.

The right way, in java:

Instant i = Instant.ofEpochMilli(-62135769600000L);
System.out.println(i.atZone(ZoneOffset.UTC));
> 0000-12-30T00:00Z

The calendar system commonly used today is called the gregorian calendar. It is a modification of what was used before, the julian calendar, which was in use in roman times.

The world did not switch from julian to gregorian on the same day. In fact, russia was very late and switched only in 1918: You bought a newspaper in moscow and it read 'January 31st, 1918' (but in russian). If you then hopped on a horse and rode west until you hit prague or berlin or amsterdam, all overnight, and asked: Hey, what date is today? They'd tell you: It's February 13th.

THen you ride back to moscow the next day and buy another newspaper. It reads 'February 14th, 1918'. What happened to february 1st - 13? They never existed. That was the time russia switched.

FUN FACT: The 'october revolution', which refers to when the tzars were overthrown, happened in november. Russia, still on the julian, were in october when that happened. The rest of the world using roman-inspired calendars were all on gregorian, and they called it november then.

Even though this is a dumb thing to do, java.util.Date tries to surmise what you really wanted and has an arbitrary timestamp: When you make a Date object that predates this, it renders times in julian calendar.

This is silly (the world didn't switch all in one go), so neither javascript nor java.time do this.

That explains the 2 days.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72
1

That is because both Date and Date have two very different implementations.

There are actually two differences here: the format of the output text and the actual date represented by the output.

The different date

I'm still investigating why Java's Date would return 1 January 0001 Well, rzwitserloot already found out and mentioned this in his answer, while I was eating. Java's Date uses the calendar which was in use at that time, while both Java's JSR 310 Date and Time API and JavaScript's Date uses the Gregorian calendar. This is called a proleptic calendar – a calendar which is applied to dates before its introduction.

I do know that JavaScript returns the correct date value. Java's Date is broken, don't use it. Instead, you should use the modern Java Date and Time API, available in the java.time package.

The following Java code returns the correct date:

OffsetDateTime odt = Instant.ofEpochMilli(-62135769600000L)
    .atOffset(ZoneOffset.ofHours(-5));
System.out.println(odt);

The different formatting

Both Java's and JavaScript's Date implement toString() in a different way. toString(). toString()` always returns a textual representation of the object on which the method is called — but how completely depends on what the author had in mind.

You should never rely on toString() to be in a certain format. If you do want to format your string, use DateTimeFormatter in Java.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130