Linux time man page specifies that the clock time structure contains nanoseconds since epoch. Is this exposed in Java in any api ? In other words , why is there no JDK api like System.currentNanos() that returns nanos since Epoch ?
Note : I know System.nanoTime() returns nanos , but its NOT with reference to Epoch time , and cannot be used across VMs for time comparison.
Edit : I am not asking how to format a date value - I am asking how to query the system for nanotime SINCE epoch ?
Because Java is intended to work across a whole variety of devices, it is not so closely tied to any one such platform.
Related
I already read an answer about if it's possible in Java 8 to get the current microseconds and the answer was no, but is it possible now in Java11?
The solution by using System.nanoTime() * 1000 is too inefficient.
Note: The Goal is NOT to get the exact current time in nanoseconds (for example 12:00 PM), obviously that's not working like this.
I would appreciate any help :)
As before, Instant.now() uses the most accurate time source available to the system. Depending on the system, there may not be anything finer-grained than System.currentTimeMillis.
As mentioned in the comments, System.nanoTime() / 1000 can be used for measuring the time between values, but doesn't give you anything like "the current time" -- you can't tell from it, for example, whether or not it's 3:00 PM.
If you need to measure or calculate e.g. the time between events in your program, there is nothing that will do better for you than System.nanoTime.
The Answer by Wasserman is correct. Here are more thoughts.
Not real-time
You commented:
When you try to do a very exact scheduler
Conventional implementations of Java, and conventional computer hardware, are not “very exact” along the scale of nanosecond and microsecond that you seemed to be targeting.
For “very exact” scheduling, you would have to use special hardware with special software. Look for the buzzword real-time, such as real-time Java.
System.nanoTime()
You said:
The solution by using System.nanoTime() * 1000 is too inefficient. Note: The Goal is NOT to get the exact time in nanoseconds
Be aware that System.nanoTime() does not tell you the current time.
System.nanoTime() tells you the approximate amount of nanoseconds that have elapsed since some arbitrarily chosen moment. In some implementations of Java, that moment may have been when the JVM was launched, or when the computer was booted, or something else. But you cannot count on that origin, nor should you care about the origin.
Represent elapsed time using Duration class.
To capture elapsed time in Java for micro-benchmarking:
long start = System.nanoTime() ;
…
Duration elapsed = Duration.between( start , System.nanoTime() ) ;
You can interrogate the Duration for its parts such as nanoseconds, whole seconds, minutes, and hours.
You said:
System.nanoTime() * 1000 is too inefficient
You must have meant:
( start - System.nanoTime() ) / 1_000
… to get a count of elapsed microseconds.
And, no, dividing or multiplying integers is not “inefficient“. If you care about optimizing for integer division operations, you should not be using conventional Java on conventional hardware, as discussed in section above.
Instant.now()
If you want to capture elapsed time as seen by human clocks:
Instant start = Instant.now() ; // May be precise to milliseconds, microseconds, or such depending on your implementation of Java and your host computer hardware clock.
…
Instant end = Instant.now() ;
To represent that elapsed time unattached to the timeline, use Duration.
Duration elapsed = Duration.between( start , end ) ;
To represent that elapsed time attached to the timeline, write a class storing a pair of Instant objects.
record SpanOfTime ( Instant start , Instant end ) {}
Or better yet, add the ThreeTen-Extra library to your project. This library brings classes that add functionality to the built-in java.time classes. One of these is Interval, with handy comparison methods such as abuts, contains, encloses, overlaps, etc.
I want to use Instant type to put it to MySQL database (timestamp field). Unfortunately, when using POJO and Record#from(), jOOQ doesn't let me do that for some reason. I have the following to my gradle configuration:
forcedTypes {
forcedType {
name = "Instant"
types = "timestamp"
}
}
The code is being generated correctly, but doesn't work and gives me errors in runtime:
Data truncation: Incorrect datetime value: '2021-01-16 05:01:25.457+00:00' for column `test`.`messages`.`time_sent` at row 1
I tried to add my own converter and binder, but they don't seem to work if name is set in gradle config, as a warning appears during build. But without name I can't get jOOQ to generate Instant for timestamp field.
Is there a way to use Instant with SQL timestamp when using jOOQ's POJO?
MySQL's timestamp data type is a bit, well, idiotic.
It stores time as seconds since the epoch (jan 1st 1970, UTC, midnight), in a 32-bit integer. This has a few issues:
There is no room for milliseconds. Your Instant has .457 milliseconds and this needs to be stripped out, which is why JOOQ is refusing to do this; that's destroying data. I assume you don't care about those millis, but JOOQ doesn't know that. You can try to strip the millis out of the instant, if you must, JOOQ would presumably allow saving an Instant, if that Instant has the property that it the epochmillis that it wraps around is divisible by 1000 (has no millis part). Except, that was annoying, so at some point, eventhough it's stored as 32-bit seconds-since-epoch, the data type now also contains, separately, a fractional second, from 0 to 999999. Either you have an old version of MySQL or the underlying table structure that doesn't allow this, or JOOQ isn't aware that MySQL does at least support millis.
At 2038-01-19 03:14:07 UTC, your app explodes. That's it. That's the last timestamp representable by a MySQL TIMESTAMP object. We're less than 18 years removed from this. Therefore this datatype is effectively unusable, and you should use something else. (This may not sound believable to you. Peruse MySQL8's user manual §11.2.2 if you need some convincing, straight from the source). Java's core instant storage system doesn't suffer from the dreaded Y2K38, as java uses millis-since-epoch in 64-bit; we got a few billion years to go before that runs out of numbers.
Note that the printed message is a bit misleading. Instants are stored as milliseconds since epoch and do not have a timezone, that +00.00 in the printout suggests that it does. It doesn't - and thus the fact that mysql's TIMESTAMP type also doesn't isn't the problem.
Solutions
The best solution, by far, is to use a database engine that isn't broken like this. For example, try postgres.
A distant second solution is to peruse JOOQ issue #9665 where #lucaseder (core contributor of JOOQ; he's the genius doing the magic over there :P) says it doesn't work yet, but there's some code there you may be able to use.
Note that if you actually care about zones, this becomes a lot more complicated. There are 3 different ways to represent time; these are distinct and cannot be converted to each other without additional info and caveats; most tools incorrectly silently convert them anyway, and pain ensues when this happens. Thus, you may want to think about which of the 3 kinds of time you have here:
solarflares time: A moment time something happened or will happen, such as a solarflare. If some political entity decides to change timezone, it has no effect. The 'time until event occurs' / 'time since event occurred' goes up by 1 second every second no matter what happens with timezones. In java terms, java.time.Instant.
appointment time: I call my barber in Amsterdam and I have an appointment on Jan 5th, 2023, 14:00. You'd think this is like solarflares time, but, no. If the dutch parliament slams the gavel and adopts a law that the Netherlands will no longer observe daylight savings and will remain in summertime, then the moment that gavel comes down, the # of seconds until my appointment goes up by an hour (is it it down by an hour?). This is not exotic at all - see EU Directive 2000/84/EC - it is, in fact, likely. Solarflares time should not shift like this, and appointment time does. Best represented as year+month+day+hour+minute+second+millis+a full zone (which is Europe/Amsterdam, not silly useless stuff like +0800 or PST). In java terms, ZonedDateTime.
Alarmclock time: Just years, months, day, hour, minute, second. That's it - it doesn't represent anything particular but just the concept. If I set my alarm to wake me up at 08 in the morning and I take a trip across the pacific, the time until my alarm goes off should change drastically as I move timezones. In java terms, LocalDateTime and friends.
I'm assuming you have a solarflares time (for example, to track 'user X change their password at this time'). This answer assumes you meant that. If you did not, my advice would change a bit. Mostly that whole 'do not use mysql' thing would become even stronger: What you really want is the datatype TIMESTAMP WITH TIME ZONE such as postgres has.
I am using JDK8 on Windows and JDK8 on Linux
When I run System.nanoTime()/System.currentTimeMillis() on windows, the result is 49,
System.nanoTime(): 74786833960332
System.currentTimeMillis():1507786236263
When run it on Linux, the result is 26236
System.nanoTime(): 39560110918205325
System.currentTimeMillis():1507786262105
I am confused with the result, that the two values are different so much.
Also, I thought that nanoTime is 1,000,000 times milliseconds, so that the two values above both look wrong to me(that is, both of them should be approximately 1000000)
Apples and Oranges
System.nanotime has nothing to do with current date and time-of-day. Its purpose is for calculating elapsed time.
Your math and your comparison to System.currentTimeMillis() makes no sense at all. The two functions are incomparable.
Read the documentation before posting to Stack Overflow.
For date-time handling you should not be using the System class at all. Instead use the industry-leading java.time classes built into Java 8 and later.
If you want current moment in UTC, call Instant.now().
If you want current moment in a time zone, call ZonedDateTime.now.
In Java 9 and later, both classes use a new implementation of Clock to capture the current moment in a resolution up to nanoseconds. But keep in mind that mainstream computers lack a hardware clock with such fine sensitivity. Microseconds is likely the finest resolution you'll see in the real world as of 2017.
According to System.nanotime() docs it is not system time in nanoseconds and it is not related to System.currenTimeMillis. It is platform dependent (this is why the difference) nanoseconds generator and it is used for measuring time elapsed between two invocations.
From the Java System documentation:
[System.nanoTime] Returns the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds.
This means System.nanoTime() returns the elapsed running time of the JVM in nanos, whereas System.currentTimeMillis() returns the time in milliseconds since midnight, January 1, 1970 UTC.
This results in a non-consistent nanoTime over each run.
For following code for java 8
1. System.out.println(LocalDateTime.now(Clock.systemDefaultZone()));
2. System.out.println(Instant.now(Clock.systemDefaultZone()));
Line 1 print current time by adding offset but line 2 print current time without adding offset.
I checked the source code of both and found that LocaDateTime.now(clock) return clock.instant() return time by adding offset but Instant.now(clock) not doing so.
Why it designed like this? Aren't we expecting same result in both case?
UPDATE: Instant has nothing to do with UTC in the timezone sense. It is related to UTC as a time standard only.
The major difference is the return type. They have different String representations because the types themselves have very different meanings.
Instant#now(Clock) returns Instant. An Instant is "[a]n instantaneous point on the time-line".
LocalDate#now(Clock) returns LocalDate. A LocalTime is "a description of the local time as seen on a wall clock".
As a result Instant#now(Clock) and LocalDate#now(Clock) mean very different things and naturally have different outcomes. The major thing they have in common is a name. Method names are dust. Refer to the types.
On a fixed Clock, both Instant.now(clock) and LocalDate.now(clock) will return constant values. The point of accepting Clock as a parameter is to be able to control things like the reference time or clock resolution.
I'm using the epoch time format to save date. My problem is Java Long is enough to handle this or should I consider Java BigInteger to handle the epoch time?
Assuming you mean UNIX epoch, Java long is more then enough. UNIX epoch is number of seconds since January 1, 1970 and is stored (in UNIX) as a 32-bit int.
Yes, a long is sufficient. But in terms of the best way, consider using native types.
In Java <= 7, java.util.Date is designed for this purpose. It has millisecond precision.
In Java >= 8, java.time.Instant is designed for this purpose. It has nanosecond precision.
In Java you can get the milliseconds since the UNIX Epoch with System.currentTimeMillis() which returns a long, so there's no reason to consider something else.
If by epoch time, you mean seconds since 1970, long will of course do the job, as it can represent millis as well up until end of time ;-)
My point is that you can might integer instead. it will represent time in secs since 1970 up to year 2038.
If you don't need to represent time before now, consider using a special format like stated here. This will help you represent a wider future range.
Another option for representing time only after now, is starting the measure since 2021, by subtracting the seconds: nowSecs - 2021Secs.