'Get Human readable time from nanoseconds
I am trying to implement an ETA feature Using System.nanoTime()
startTime = System.nanoTime()
Long elapsedTime = System.nanoTime() - startTime;
Long allTimeForDownloading = (elapsedTime * allBytes / downloadedBytes);
Long remainingTime = allTimeForDownloading - elapsedTime;
But I cannot figure how to get a human readable form of the nanoseconds; for example: 1d 1h
, 36s
and 3m 50s
.
How can I do this?
Solution 1:[1]
If remainingTime
is in nanoseconds, just do the math and append the values to a StringBuilder
:
long remainingTime = 5023023402000L;
StringBuilder sb = new StringBuilder();
long seconds = remainingTime / 1000000000;
long days = seconds / (3600 * 24);
append(sb, days, "d");
seconds -= (days * 3600 * 24);
long hours = seconds / 3600;
append(sb, hours, "h");
seconds -= (hours * 3600);
long minutes = seconds / 60;
append(sb, minutes, "m");
seconds -= (minutes * 60);
append(sb, seconds, "s");
long nanos = remainingTime % 1000000000;
append(sb, nanos, "ns");
System.out.println(sb.toString());
// auxiliary method
public void append(StringBuilder sb, long value, String text) {
if (value > 0) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(value).append(text);
}
}
The output for the above is:
1h 23m 43s 23402000ns
(1 hour, 23 minutes, 43 seconds and 23402000 nanoseconds).
Solution 2:[2]
I would say both of these answers are correct, but anyways here is a little shorter version of a function that accepts nano time and returns human-readable String.
private String getReadableTime(Long nanos){
long tempSec = nanos/(1000*1000*1000);
long sec = tempSec % 60;
long min = (tempSec /60) % 60;
long hour = (tempSec /(60*60)) % 24;
long day = (tempSec / (24*60*60)) % 24;
return String.format("%dd %dh %dm %ds", day,hour,min,sec);
}
For maximum accuracy, instead of integer division, you can use float division and round up.
Solution 3:[3]
It is my old code, you can convert it to days also.
private String calculateDifference(long timeInMillis) {
String hr = "";
String mn = "";
long seconds = (int) ((timeInMillis) % 60);
long minutes = (int) ((timeInMillis / (60)) % 60);
long hours = (int) ((timeInMillis / (60 * 60)) % 24);
if (hours < 10) {
hr = "0" + hours;
}
if (minutes < 10) {
mn = "0" + minutes;
}
textView.setText(Html.fromHtml("<i><small;text-align: justify;><font color=\"#000\">" + "Total shift time: " + "</font></small; text-align: justify;></i>" + "<font color=\"#47a842\">" + hr + "h " + mn + "m " + seconds + "s" + "</font>"));
return hours + ":" + minutes + ":" + seconds;
}
}
Solution 4:[4]
Here's my suggestion. It's based on the fact that the units in TimeUnit.values()
are sorted from smallest (nanoseconds) to longest (days).
private static String getHumanReadableTime(long nanos) {
TimeUnit unitToPrint = null;
String result = "";
long rest = nanos;
for(TimeUnit t: TimeUnit.values()) {
if (unitToPrint == null) {
unitToPrint = t;
continue;
}
// convert 1 of "t" to "unitToPrint", to get the conversion factor
long factor = unitToPrint.convert(1, t);
long value = rest % factor;
rest /= factor;
result = value + " " + unitToPrint + " " + result;
unitToPrint = t;
if (rest == 0) {
break;
}
}
if (rest != 0) {
result = rest + " " + unitToPrint + " " + result;
}
return result.trim();
}
Output for getHumanReadableTime(139543185092L)
will be
2 MINUTES 19 SECONDS 543 MILLISECONDS 185 MICROSECONDS 92 NANOSECONDS
Solution 5:[5]
java.time
You can use java.time.Duration
which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
Demo:
import java.time.Duration;
public class Main {
public static void main(String[] args) {
long elapsedTime = 12345678987654321L;
Duration duration = Duration.ofNanos(elapsedTime);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedElapsedTime = String.format(
"%02d Day %02d Hour %02d Minute %02d Second %d Millisecond %d Nanosecond", duration.toDays(),
duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
duration.toMillis() % 1000, duration.toNanos() % 1000000L);
System.out.println(formattedElapsedTime);
// ##############################################################################
// ####################################Java-9####################################
formattedElapsedTime = String.format("%02d Day %02d Hour %02d Minute %02d Second %d Millisecond %d Nanosecond",
duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
duration.toMillisPart(), duration.toNanosPart() % 1000000L);
System.out.println(formattedElapsedTime);
// ##############################################################################
}
}
Output:
PT3429H21M18.987654321S
142 Day 21 Hour 21 Minute 18 Second 987 Millisecond 654321 Nanosecond
142 Day 21 Hour 21 Minute 18 Second 987 Millisecond 654321 Nanosecond
Learn more about the modern date-time API from Trail: Date Time.
- For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
- If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | slashdottir |
Solution 3 | wonderPub |
Solution 4 | Mathias Ricken |
Solution 5 | Community |