0

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());
    }
}
solvingJ
  • 1,321
  • 1
  • 19
  • 30

2 Answers2

7

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

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • This is really great feedback! I think it answers the core of the original question. I will definitely use the constant. I share your confusion about the value. I did the conversion myself earlier, but thought perhaps I was doing something wrong. It's especially confusing because the .NET library is able to perform sensible queries based on this RowKey field. It seems we'll have to try to ask the developers how this value is actually derived so that we can query it effectively. – solvingJ Aug 24 '16 at 00:35
  • @JerryW. Discrepancy identified and fixed. – Andreas Aug 24 '16 at 00:37
  • Andreas, thanks to your effort and attention to detail, I have achieved my goal. It is really impressive that you were able to deduce the solution and figure out the offset thing, and then you went the extra mile and gave me a working replica. If you had not done all you did, I don't know that I would have been able to make this work. Thanks again. – solvingJ Aug 24 '16 at 04:54
0
long maxSeconds = Instant.MAX.getEpochSecond(); //31556889864403199
int maxNanos = Instant.MAX.getNano(); //999999999

These two values can be used together to create a precise MAX value as number: 31556889864403199,999999999

If you need to print it you need to join them as String.

You can also create a BigDecimal from these two values like:

BigDecimal max = new BigDecimal(Long.toString(maxSeconds) + "." + String.format("%09d", maxNanos));

And operate on it:

BigDecimal now = new BigDecimal(String.format("%d.%09d", Instant.now().getEpochSecond(), Instant.now().getNano()));
System.out.println(max.subtract(now).toString());
pr0gramist
  • 8,305
  • 2
  • 36
  • 48
  • Suppose we have 1 second and 3 nanos. `"1" + "." + "3"` gives `"1.3"`, but the right value is `"1.000000003"` – Roman Aug 24 '16 at 00:10