-2

I have a .NET INT64 value(result from DateTime.toBinary()) as -8586018589234214115 from JSON response. How do I convert that value into valid java Date?

Thanks, Sandeep

  • If by *java Date* you meant `java.util.Date`, don’t use that class. It is poorly designed and long outdated. Instead use `Instant` or `ZonedDateTime` or other classes from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Dec 16 '20 at 04:19

3 Answers3

2
  1. Convert the value (e.g. -8586018589234214115) to DateTime object (say, theDateTimeObject) using DateTime.FromBinary(Int64)
  2. Convert theDateTimeObject to DateTimeOffset as DateTimeOffset dateTime = DateTime.SpecifyKind(theDateTimeObject, DateTimeKind.Utc)
  3. Pass the value of DateTimeOffset.ToUnixTimeMilliseconds into java.time.Instant#ofEpochMilli to get an object of Instant which you can convert to other date-time types.

Demo:

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        long millis = 1608075095347L;
        Instant instant = Instant.ofEpochMilli(millis);
        System.out.println(instant);

        // You can derive other date-time objects from Instant e.g.
        OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);
        ZonedDateTime zdt = instant.atZone(ZoneOffset.UTC);
        LocalDateTime ldt = odt.toLocalDateTime();
        System.out.println(odt);
        System.out.println(zdt);
        System.out.println(ldt);
    }
}

Output:

2020-12-15T23:31:35.347Z
2020-12-15T23:31:35.347Z
2020-12-15T23:31:35.347Z
2020-12-15T23:31:35.347

Note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API. Learn more about the modern date-time API at Trail: Date Time.

Note: For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.

If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
2

The Binary value is:

A 64-bit signed integer that encodes the Kind property in a 2-bit field and the Ticks property in a 62-bit field.

Since the Kind property is useless to us, we can simply mask it out using value & ((1L << 62) - 1) to get the Ticks property.

A Tick is:

A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond (see TicksPerMillisecond) and 10 million ticks in a second.

The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001.

Which means we can convert like this:

private static final long NANOS_PER_TICK = 100L;
private static final long TICKS_PER_SECOND = 1000000000L / NANOS_PER_TICK;
private static final long YEAR_OFFSET = -62135596800L;
// Seconds from Epoch to 12:00:00 midnight, January 1, 0001, calculated using:
//   OffsetDateTime.of(1, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toEpochSecond()
static Instant fromDateTimeBinary(long value) {
    long ticks = value & ((1L << 62) - 1);
    return Instant.ofEpochSecond(ticks / TICKS_PER_SECOND + YEAR_OFFSET,
                                 ticks % TICKS_PER_SECOND * NANOS_PER_TICK);
}

Test

long dateTimeBinary = -8586018589234214115L;
System.out.println(dateTimeBinary + " -> " + fromDateTimeBinary(dateTimeBinary));

Output

-8586018589234214115 -> 2020-09-10T14:26:02.056169300Z

Warning: The -8586018589234214115 value specifies a Kind value of 2=Local (the time represented is local time), but we don't know what the "local" time zone was, so the result of converting to UTC may be wrong.


We can also convert the other way:

static long toDateTimeBinary(Instant dateTime) {
    long ticks = (dateTime.getEpochSecond() - YEAR_OFFSET) * TICKS_PER_SECOND
               + dateTime.getNano() / NANOS_PER_TICK;
    return (0x01L/*Kind=UTC*/ << 62) | ticks;
}

Test

Instant now = Instant.now();
System.out.println(now + " -> " + toDateTimeBinary(now));

Output

2020-12-16T01:51:17.066065200Z -> 5249122821198048556

See also: Java 8 Time - Equivalent of .NET DateTime.MaxValue.Ticks

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thank you very much for the doc link! I have updated [my answer to the linked original question](https://stackoverflow.com/a/51357072/5772882) accordingly. – Ole V.V. Dec 16 '20 at 05:20
0

It would be better to convert to unix time .net DateTimeOffset.ToUnixTimeMilliseconds and then use the java.util.Date java constructor to parse it

  • It’s a suggestion. I recommend you don’t use `Date` in Java. 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. Dec 16 '20 at 04:17