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

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());
}
}

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

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());

Related

How can I convert the result of System.nanoTime to a date in Java?

I want to convert the result of System.nanoTime() to a date.
public void tempBan(Player p, Player banner, int timeInSeconds){
Long timeInNano = (long) (timeInSeconds * 10^9);
int newTime = (int) (System.nanoTime() + timeInNano);
// here I want to convert newTime to a date
}
I have converted the seconds into nanoseconds by multiplying by 10^9. Now I need to convert the current system time plus the parameter which I converted into nanoseconds into a date.
Unfortunately, System.nanoTime() is not what you want for this.
To quote the JavaDoc:
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative). The same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin.
You probably want System.currentTimeMillis(), in which case you can use new Date(System.currentTimeMillis() + milliseconds) to get the date for that number of milliseconds in the future.
While you could then subtract System.nanoTime(), scale the value, and add System.currentTimeMillis() to have a similar result... since you're adding System.nanoTime() anyway and therefore have the original number of seconds, you could just use System.currentTimeMillis() directly.
In the theory, you should not use the only System.nanotime(), but you can do a simple trick with this method in order to get nanoseconds of the current time.
public class TimeProvider{
private final static long jvm_diff;
static {
jvm_diff = System.currentTimeMillis()*1000_000-System.nanoTime();
}
public static long getAccurateNow(){
return System.nanoTime()+jvm_diff;
}
}
Even though, you can create your own Clock implementation with this way for using high-level java data time classes.
public class HighLevelClock extends Clock {
private final ZoneId zoneId;
public HighLevelClock(ZoneId zoneId) {
this.zoneId = zoneId;
}
static long nano_per_second = 1000_000_000L;
#Override
public ZoneId getZone() {
return zoneId;
}
#Override
public Clock withZone(ZoneId zoneId) {
return new HighLevelClock(zoneId);
}
#Override
public Instant instant() {
long nanos = TimeProvider.getAccurateNow();
return Instant.ofEpochSecond(nanos/nano_per_second, nanos%nano_per_second);
}
}
Now we can use our clock implementation like the following:
Clock highLevelClock = new HighLevelClock(ZoneId.systemDefault());
System.out.println(LocalDateTime.now(highLevelClock)); //2020-04-04T19:22:06.756194290
System.out.println(ZonedDateTime.now(highLevelClock)); //2020-04-04T19:22:06.756202923+04:00[Asia/Baku]
System.out.println(LocalTime.now(highLevelClock)); //19:22:06.756220764
You can convert it into system time using the below code
public static long convertToUnixMs(final long timeMs) {
final long refMonoMs = monoTimeMs();
final long refUnixMx = System.currentTimeMillis();
return refUnixMx + (timeMs - refMonoMs);
}
public static long monoTimeMs() {
return System.nanoTime() / 1000000;
}
Explanation:
System.nonoTime() is a monotonic time that increases only, it has no idea of what time it is right now, but it would only increase regardless. So it is a good way for measuring elapsing time. But you can not convert this into a sensible time as it has no reference to the current time.
The provided method is a way to convert your stored nano time into a sensible time. First, you have a timeMs that is in nano time that you would like to convert. Then, you created another nanotime (i.e refMonoMs) and another System.currentTimeMillis() (i.e refUnixMx). Then you minus refMonoMs from the timeMs, and add the reference back into it to get the sensible time back.

Set/Get SystemTime in Java /C#

I have this code in java which is about SystemTime:
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
//Gets the time of the boardtime object in milliseconds
public long getMs() {
return super.getTimeInMillis();
}
//Sets the time of the boardtime object in milliseconds
public void setMs(long ms) {
super.setTimeInMillis(ms);
}
I tried to convert it to C#:
For the first part, I used DateTimeFormatInfo class:
private static DateTimeFormatInfo sdf = new DateTimeFormatInfo();
for getting the system time in milliseconds I used TimeSpan:
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
I do not know if what I have done until now is correct or not but I can not find any C# equivalent for the setTime.
This is what I have done until now:
private static DateTimeFormatInfo sdf = new DateTimeFormatInfo();
public long getMs(){
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
return milliseconds;
}
public void setMs(long ms){
}
Thanks in advance
If you just want to set/get the time from milliseconds, you can do this with a C# TimeSpan:
private TimeSpan time
public void setMs(long ms)
{
this.time = TimeSpan.FromMilliseconds(ms);
}
public long getMs()
{
return this.time.TotalMilliseconds;
}
Your getMs() as defined above returns the number of MS since 1/1/0001 (see here). Based on this MSDN page, to set system time from C# you need to construct a SYSTEMTIME struct, initialize it properly, and pass it to the function SetSystemTime(). The page has a simple example that shows how to do that. How do we construct the right SYSTEMTIME struct? One can use the function FileTimeToSystemTime(), which takes the number of ticks since 1/1/1601 (note the different year) and converts it to a SYSTEMTIME.
So, in short:
In your setMs() function, convert the parameter that was passed (ticks since 1/1/0001) to ticks since 1/1/1601 (basically, subtract 1600 years in ticks)
Construct a FILETIME struct from that value
Call FileTimeToSystemTime() to get the corresponding SYSTEMTIME
Call SetSystemTime() and pass that value
If there's an easier way, I'd be interested to know. Hope this helps!
If you want to take the time as milliseconds, then use the TimeSpan.TotalMilliseconds method, constructed from a DateTime object using TimeSpan.FromTicks. Create a DateTime object and manipulate the timestamp using milliseconds, then use the predefined DateTime.AddMilliseconds method by adding resp. subtracting milliseconds:
var now = DateTime.Now; // or new DateTime(2014, 05, 29, 21, 27, 05);
Console.WriteLine(now.ToString("yyyy-MM-dd HH.mm.ss"));
var future = now.AddMilliseconds(1234567);
var past = now.AddMilliseconds(-1234567);
Console.WriteLine(future.ToString("yyyy-MM-dd HH.mm.ss"));
Console.WriteLine(past.ToString("yyyy-MM-dd HH.mm.ss"));
// get milliseconds from current date time object using TimeSpan.TotalMilliseconds
var ts = TimeSpan.FromTicks(now.Ticks);
Console.WriteLine(ts.TotalMilliseconds);
The output is:
2014-05-29 21.27.05
2014-05-29 21.47.40
2014-05-29 21.06.31
63536995625703,1
Have a look at this MSDN article about Custom Date and Time Format Strings for more custom date and time formatting options for a DateTime object.

String to int java.lang.NumberFormatException

I have java program which convert String to int, but the rang of String is 190520141618013381(above the rang of int) when i convert this int the java.lang.NumberFormatException: is thrown
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(format.format(date));
stringBuffer.append(demandCount);
int test_int = Integer.parseInt(stringBuffer.toString()); // exception has been fixed by putting
//long abc_i = Long.parseLong(abc);
log.info("test_int: "+test_int);
my question is that compiler should throw NumberOutOfRangException(if this Exception is available in API) instead java.lang.NumberFormatException:, the format of number(190520141618013381) is right.
The String 190520141618013381 is outside the range of an int but it also doesn't match the accepted format of an int because it is too long.
The compiler doesn't throw this error, it is thrown at runtime.
I believe it is correct to comply with the documentation for this method.
BTW Don't use StringBuffer, it was replaced by StringBuilder ten years ago.
IMHO storing a date as an integer isn't a good idea in general.
A more efficient to get a unique id which contains the time in millis is to do something like this.
private static final AtomicLong TS_COUNTER = new AtomicLong();
public static long nextTimeStamp() {
long time = System.currentTimeMillis() * 1000;
long curr = TS_COUNTER.get();
if (curr < time && TS_COUNTER.compareAndSet(curr, time))
return time;
return TS_COUNTER.incrementAndGet();
}
This will have the time-in-millis * 1000 plus a unique id. This works fine if you average less than one million ids per second.

Strange happenings when getting average milliseconds and converting to time

I am having some strange output when I am attempting to get an average from a long value and converting it to a String (in HH:mm:ss) format. I'm using the Joda time library, which mostly has been a life saver.
Here's what I have so far:
//this is in a static class
public static Duration calculateTime(Date start, Date end) {
Duration duration = new Duration(start.getTime(), end.getTime());
return duration;
}
public static String convertMillisToTime(long milliseconds) {
return String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliseconds),
TimeUnit.MILLISECONDS.toMinutes(milliseconds) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliseconds)),
TimeUnit.MILLISECONDS.toSeconds(milliseconds) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds)));
}
long averageRunTime = 0;
averageRunTime += calculateTime(drs.startTime, drs.endTime).getMillis();
Since this is done in an array list, to get the average, I am taking
averageRunTime = averageRunTime / (long)arrayList.size();
when I get to the point of
convertMillisToTime(averageRunTime);
It's returning a value that is higher than any times I have. IE( I have no job times that are over 11 hours) but this is returning me a String with 11:mm:ss. Not quite sure WHY?
I used the convertMillisToTime from: How to convert milliseconds to "hh:mm:ss" format?
Can anyone point me in the right direction?
Thank you in advance,
RR
Edit: I've modified the code that converts the long to time using TimeUnit. It's strange though, I grabbed three runs (time streams) and got 09:14:17, 08:57:18, 09:10:25 for the length of each run, and the average is coming out as: 10:27:26.
You could just use a formatter from Joda Time instead, for example...
public static final PeriodFormatter PERIOD_FORMATTER = new PeriodFormatterBuilder().printZeroAlways().
appendHours().appendSeparator(":").
appendMinutes().appendSeparator(":").
appendSeconds().appendSeparator(".").
appendMillis().toFormatter();
public static String toString(Duration duration) {
return duration == null ? "[invalid duration]" : duration.toPeriod().toString(PERIOD_FORMATTER);
}

Interval Time subtraction in Java

I was trying to find the difference in time (HH:mm:ss.SSS) in Java, where each time can be more than 24 hours. SimpleDateFormat does not support time which is greater than 24 hours.
For example,
Time A = 36:00:00.00
Time B = 23:00:00.00
I would like to get the answer of 13:00:00.00. (13 hours).
Does any one know whether there are any Java libraries that can perform the subtraction. Also would like to know whether time addition is possible with the Java library.
You don't need a third party library
This is simple math, and doesn't directly appear to have anything to do with Date DateTime or Timestamp instances, but does appear to be interval related, and there is built in functionality into the JDK >= 1.5 with java.util.concurrent.TimeUnit to handle just this type of math without introducing any dependencies.
Here is the code to parse your input and convert it into milliseconds, which you can then convert back into whatever String format you want, I conveniently chose the format you requested.
java.util.concurrent.TimeUnit is a little hidden gem that most people don't know about that kind of snuck in to 1.5. It is kind of criminal that this class is buried in the java.util.concurrent package and no one seems to know about it.
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main
{
private static long parseInterval(final String s)
{
final Pattern p = Pattern.compile("^(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{3})$");
final Matcher m = p.matcher(s);
if (m.matches())
{
final long hr = Long.parseLong(m.group(1)) * TimeUnit.HOURS.toMillis(1);
final long min = Long.parseLong(m.group(2)) * TimeUnit.MINUTES.toMillis(1);
final long sec = Long.parseLong(m.group(3)) * TimeUnit.SECONDS.toMillis(1);
final long ms = Long.parseLong(m.group(4));
return hr + min + sec + ms;
}
else
{
throw new IllegalArgumentException(s + " is not a supported interval format!");
}
}
private static String formatInterval(final long l)
{
final long hr = TimeUnit.MILLISECONDS.toHours(l);
final long min = TimeUnit.MILLISECONDS.toMinutes(l - TimeUnit.HOURS.toMillis(hr));
final long sec = TimeUnit.MILLISECONDS.toSeconds(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
final long ms = TimeUnit.MILLISECONDS.toMillis(l - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms);
}
public static void main(final String[] args)
{
final String s1 = "36:00:00.000";
final String s2 = "23:00:00.000";
final long i1 = parseInterval(s1);
final long i2 = parseInterval(s2);
System.out.println(formatInterval(i1 - i2));
}
}
the output is
13:00:00.000
I assume you meant for the last number to be milliseconds which should have a resolution of 3 digits.
Here's a complete solution using JodaTime. I dare say there's no comparably easy and elegant way to do it using java.util or java.util.concurrent apis:
public static int getHoursBetween(final String date1, final String date2){
final DateTimeFormatter fmt =
DateTimeFormat
.forPattern("HH:mm:ss.SS")
.withChronology(
LenientChronology.getInstance(
GregorianChronology.getInstance()));
return Hours.hoursBetween(
fmt.parseDateTime(date1),
fmt.parseDateTime(date2)
).getHours();
}
(LenientChronology makes sure that values like 38:00:00.00 are supported)
Take a look at Joda-Time, which is a complete library for dealing with times and dates in Java, including arithmetic on intervals.
Try converting time to seconds, subtract then convert back to simple time format.
Here is a sample of how to get the difference between two Dates using Joda-Time (which was mentioned by Jim Garrison earlier. It really is one of the best Time libraries available.
public static void main(String[] args) {
DateTime timeA = new DateTime(2011, 6, 13, 12, 0, 0, 0);
DateTime timeB = new DateTime(2011, 6, 12, 23, 0, 0, 0);
Period period = new Period(timeB, timeA);
System.out.println(period.getHours());
}

Categories

Resources