Jerry W. Jerry W. - 3 months ago 14
Java Question

Java 8 Time - Equivalent of .NET DateTime.MaxValue.Ticks

I've included the whole method below, but really the challenge is simulating DateTime.MaxValue.Ticks in Java 8. I also don't know the equivalent of ".ToString("D19") in Java.

I thought I had figured out how to begin, which was by using Instant.MAX.toEpochMilli(), which I could then multiply by 10000 to get Ticks. Sadly, this simple statement throws an exception, so it's a non-starter:


Caught: java.lang.ArithmeticException: long overflow


Here is the original method. It's used to query Azure Storage Tables for historical metrics.

// Creates a TableQuery for getting metrics by timestamp
private static TableQuery GenerateMetricTimestampQuery(string partitionKey, DateTime startTime, DateTime endTime)
{
return GenerateMetricQuery(
partitionKey,
(DateTime.MaxValue.Ticks - endTime.Ticks + 1).ToString("D19") + "__",
(DateTime.MaxValue.Ticks - startTime.Ticks).ToString("D19") + "__");
}


Here is an example of a RowKey field value:


2519303419199999999__


I've spent a day on this and I'm pretty stumped. Any help would be greatly appreciated.

If possible, I would prefer to do this without JodaTime.

UPDATE1*** Based on a comment, here is an example of the exception in Java.

import java.time.Instant;
public class Tester {
public static void main(String[] args){
System.out.println(Instant.MAX.toEpochMilli());
}
}

Answer

UPDATE Original answer didn't account for offset difference between Java epoch (1970) and .NET ticks (0001). Corrected!

For reference, Long.MAX_VALUE (Java) is:
9,223,372,036,854,775,807

In .NET, DateTime.MaxValue is:
9999-12-31 23:59:59.9999999
3,155,378,975,999,999,999 ticks1 (~ 1/3 of long)

In Java 8, Instant.MAX is:
+1000000000-12-31 23:59:59.999999999
31,556,889,864,403,199,999,999,999 nanos (overflows long)
315,568,898,644,031,999,999,999 ticks2 (overflows long)
31,556,889,864,403,199,999 millis (overflows long)
31,556,889,864,403,199 seconds (~ 1/292 of long)

For reference, your value of 2519303419199999999 is:
2016-08-23 13:28:00
636,075,556,800,000,000 ticks1 (~ 1/14 of long)
14,719,588,800,000,000 ticks2 (~ 1/626 of long)
1) Since 0001-01-01 (.NET)     2) Since 1970-01-01 (Java)

As you can see, Instant.MAX in "ticks" will not fit in a long. Not even milliseconds will fit.

More importantly Instant.MAX is not the same value as DateTime.MaxValue.

I would suggest you just create a constant for the value, e.g.

public static final long DATETIME_MAXVALUE_TICKS = 3155378975999999999L; // .NET: DateTime.MaxValue.Ticks

That way you'll get same string values as you .NET code:

public static final long EPOCH_OFFSET = 62135596800L; // -Instant.parse("0001-01-01T00:00:00Z").getEpochSecond()

private static long getTicks(Instant instant) {
    long seconds = Math.addExact(instant.getEpochSecond(), EPOCH_OFFSET);
    long ticks = Math.multiplyExact(seconds, 10_000_000L);
    return Math.addExact(ticks, instant.getNano() / 100);
}

public static void main(String[] args) {
    Instant startTime = Instant.parse("2016-08-23T13:28:00Z");
    String s = String.format("%19d", DATETIME_MAXVALUE_TICKS - getTicks(startTime));
    System.out.println(s);
}

Output:
2519303419199999999