12

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.

Cel Skeggs
  • 1,827
  • 21
  • 38
  • 1
    It's usually best to state what you want *outside* of the code blocks. While someone CAN read into them to figure out what's going on, the easier you make it, the more likely it is that someone is going to help you. – Cel Skeggs Sep 07 '15 at 17:08
  • How do you want to convert nano seconds to a date exactly? – Bruno Caceiro Sep 07 '15 at 17:45
  • 1
    Down-voters, please post a criticism. Seems like a reasonable Question to me. Date-time work is tricky stuff, and this issue could be a common point of confusion. – Basil Bourque Sep 07 '15 at 22:24
  • See [this similar Question](http://stackoverflow.com/q/20689055/642706) that compares the new java.time framework with its support for nanosecond resolution and the `System.nanoTime()` mentioned here. The Answers there remind us that current computer clocks do not actually produce anything even close to accurate nanosecond readings. – Basil Bourque Sep 08 '15 at 03:10
  • If your goal is to track elapsed time with up to nanoseconds resolution, use `Instant` and `Duration`. Be aware that conventional computer hardware clocks cannot capture current moment with nanosecond precision. – Basil Bourque Jan 03 '18 at 22:20

3 Answers3

17

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.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Cel Skeggs
  • 1,827
  • 21
  • 38
3

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
-4

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.

Tom chan
  • 365
  • 3
  • 18
  • 1
    And where does this method `monoTimeMs()` come from? And what does it have to do with `System.nanoTime()`? – Mark Rotteveel Jan 03 '18 at 15:37
  • apology, added amends – Tom chan Jan 03 '18 at 17:05
  • I still think you don't understand what `System.nanoTime()` actually returns. Please add an explanation what your code does, and what effect it achieves. Especially in light of the accepted answer. – Mark Rotteveel Jan 03 '18 at 19:21
  • added explanation. System.nanoTime() return an increasing time, but it has no reference, so i tried to add a reference back into the nanotime – Tom chan Jan 04 '18 at 10:48
  • I have an issue that I have a bunch of event happened that i recorded using nanotime(), but i want to convert them into Date, so I use the above function to do that – Tom chan Jan 04 '18 at 10:49
  • Well, it looks like you're missing a crucial information here: `timeMs` was created by using `monoTimeMs` (or `System.nanoTime()` in a different way). If not `timeMs - refMonoMs` would be rather bad. But anyway, you don't actually convert `System.nanoTime()` into a date, but rather compute a difference between two calls to `System.nanoTime()` and convert _that_ result to Date. – Tom Jan 04 '18 at 10:54
  • yes, timeMs was created by using another monoTimeMs. I wanted to post this as i have a bunch of events stored in monoTimeMs and I wanted to converted them into Date, and this article misleads to think it can not be done. – Tom chan Jan 04 '18 at 11:34
  • 1
    And it cannot (or should not) be done and you also aren't doing that. You're converting `System.currentTimeMillis() - some millis` and there these "some millis" come from don't actually matter. What Cels answer says is that you can't (or shouldn't) convert the result from a single `System.nanoTime()` call to a Date and expect it to be accurate. – Tom Jan 04 '18 at 11:39
  • not meant to be accurate 2pm - 30000 in MonoTime --> 3 pm - 40000 in monotime 2pm = 3pm - (4000 - 3000) – Tom chan Jan 04 '18 at 17:47