I'm trying to convert the number of seconds contained in a duration into hours by dividing the duration.getSeconds() value by 60 twice.
However when I do this the number is being converted into 0.0, instead of an actual value. I imagine this is because the number is too small to be represented, however I have used doubles to try and represent the number and it still doesn't work.
In the below code please assume startTime and endTime are valid LocalTimes produced by two separate calls to LocalTime.now()
Duration duration = Duration.between(startTime, endTime); //duration in sec
double durationInSec = duration.getSeconds();
double durationInHours = durationInSec / 60 / 60;
Works for me
LocalTime start = LocalTime.of ( 11 , 30 );
LocalTime stop = start.plusHours ( 2 );
Duration d = Duration.between ( start , stop );
double seconds = d.toSeconds ();
double hours = seconds / 60 / 60;
See this code run live at IdeOne.com.
start.toString() = 11:30
stop.toString() = 13:30
d.toString() = PT2H
seconds = 7200.0
hours = 2.0
Tip: When you know you want to work with fractions of double, append d to your numeric literals to avoid any confusion over the compiler's integer-to-fraction conversion and up/downscaling the types. Be explicit. So in your code, append each 60 with a d. May not be necessary here, but removes ambiguity for the reader at least.
double hours = seconds / 60d / 60d ;
<1 second = 0 hours
As others commented, if your elapsed time was less than a full second, your code results in a zero.
A Duration is internally represented by a count of whole seconds plus a fractional second as a count of nanoseconds. Your call to Duration::getSeconds() retrieves the whole seconds, without the fractional second. So for a duration of PT0.5S, getSeconds returns zero. Zero divided by sixty divided by sixty equals zero.
Duration d = Duration.parse ( "PT0.5S" ); // Half a second.
double hours = d.getSeconds () / 60d / 60d;
hours: 0.0
You should instead call Duration::toNanos to get a total number of nanoseconds elapsed. And adjust your division.
Duration d = Duration.parse ( "PT0.5S" ); // Half a second.
long nanos = d.toNanos () ;
double hours = nanos / 1_000_000_000d / 60d / 60d ;
hours: 1.388888888888889E-4
Avoid fractional hours
By the way, let me suggest that fractional hours is a poor way to handle spans-of-time. Hours, minutes, seconds, and such are not amenable to such decimal math.
Besides that, the floating-point types such as double are inherently inaccurate.
Use the Java classes intended for this purpose: Duration and Period. When reporting or exchanging textually the value of these objects, use standard ISO 8601 format. As seen above, 2 hours is represented by PT2H.
The java.time classes use ISO 8601 formats by default when parsing/generating strings. No need to specify a formatting pattern.
Duration d = Duration.parse( "PT2H" ) ;
Related
I am using java timer, but my problem is every time exceeding 60 seconds, I like my code working like;
1 minutes 59 seconds,
2 minutes 0 seconds..
My code is below.
private long lastReceivedMessage = System.currentTimeMillis();
#Scheduled(fixedDelayString = "${listenScheduled}", initialDelay = 1000)
private void distanceBetweenLastReceivedMessageAndCurrentTime() {
long currentTime = System.currentTimeMillis() - lastReceivedMessage;
logger.info("has threw 'INFO' event due to is not running as an expected since {} {} {} {} ", TimeUnit.MILLISECONDS.toMinutes(currentTime), "minutes", TimeUnit.MILLISECONDS.toSeconds(currentTime), "seconds");
java.time classes
Capture the current moment using java.time.Instant.
Instant then = Instant.now() ;
…
Duration d = Duration.between( then , Instant.now() ) ;
String output = d.toString() ;
The toString method generates text in standard ISO 8601 format: PnYnMnDTnHnMn. I suggest you report using that format. The format uses a P to mark the beginning. A T separates any years-months-days from any hours-minutes-seconds. So, two and a half minutes is PT2M30S.
If you insist on your format, call the to…Part methods on Duration.
It is not going to automatically separate the minutes and seconds. Also, I would recommend breaking up that logger.info statement for readability.
One way to do it is to convert it to seconds first, set the modulus (remainder) of the seconds and 60 as your seconds, then divide the minutes for the minutes value. Or you could just skip the conversion and divide + modulus by 60000.
long msElapsed = 660_000; //5min 30sec
long secElapsed = msElapsed / 1000;
long minutes = secElapsed / (long) 60;
long seconds = secElapsed % 60;
System.out.printf("%d %d",(int)minutes,(int)seconds);
I want to show a number in a format XX:00 in Java. How can I do it?
Ex: int number = 12;
show 12:00.
double i = 12;
show 12:00
Showing a double number
If 12.0 is a fractional number to be printed with colon as decimal separator:
double i = 12;
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setDecimalSeparator(':');
NumberFormat format = new DecimalFormat("00.00", dfs);
System.out.println(format.format(i));
Output:
12:00
If i was 12.75 instead of 12, the fraction would be printed too:
12:75
It rounds to the nearest number with two decimals, so 12.756 would be printed as 12:76.
Showing a duration in hours and minutes
If instead your 12:00 denotes an amount of time, a duration in hours and minutes, we want something different because there are 60 minutes in an hour, not 100. Here’s the Java 9 and later version:
long totalMinutes = (long) (i * TimeUnit.HOURS.toMinutes(1));
Duration dur = Duration.ofMinutes(totalMinutes);
System.out.format("%02d:%02d%n", dur.toHours(), dur.toMinutesPart());
This prints
12:00
or in the 12.75 case:
12:45
12.75 equals 12 and three quarters, and the 45 printed also equals three quarters of an hour, so this is what we wanted. It rounds down, so even though 12.759 equals 12 hours 45 minutes 32.4 seconds, it’s still printed as 12:45.
Java 8 and earlier:
The toMinutesPart method I have used was introduced in Java 9. In Java 8 (and earlier) you may still use the Duration class, but it’s less advantageous, so you may also do without it:
int hours = (int) i;
long minutesOnly = totalMinutes - TimeUnit.HOURS.toMinutes(hours);
System.out.format("%02d:%02d%n", hours, minutesOnly);
Now the result is the same as above.
double i = 12;
String.format("%.0f:00", i); // returns 12.00
I am trying to calculate the difference between two times, which are represented as longs in the Format HHmm 24 hour time. E.g 4:30pm is represented by the long 0430.
I am happy for the difference to be in minutes.
Is there a simple calculation that can be done to achieve this? I am aware of Java's Date class, however I want to avoid having to store dummy date information just for a calculation on time.
Thanks!
Putting aside the fact that this is a really, really bad way to store times, the easiest way to do this is to convert the HHMM time to minutes since the start of the day:
long strangeTimeFormatToMinutes(long time) {
long minutes = time % 100;
long hours = time / 100;
return minutes + 60 * hours;
}
Then just use plain old subtraction to get the difference.
You may also want to add validation that minutes and hours are in the ranges you expect, i.e. 0-59 and 0-23.
You mentioned that you didn't want to use the Date class because it required you to use a dummy date. The LocalTime class does not require that.
LocalTime start = LocalTime.of(6,15,30,200); // h, m, s, nanosecs
LocalTime end = LocalTime.of(6,30,30,320);
Duration d = Duration.between(start, end);
System.out.println(d.getSeconds()/60);
Pad zeros
First convert your integer to a 4-character string, padding with leading zeros.
For example, 430 becomes 0430 and parsed as 04:30. Or, 15 becomes 0015 and parsed as quarter past midnight, 00:15.
String input = String.format( "%04d", yourTimeAsInteger );
LocalDate
The LocalTime class represents a time-of-day value with no date and no time zone.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "HHmm" );
LocalTime ld = LocalTime.parse( input , f ) ;
Hello I'm able to get the seconds, minutes, hours and days, but when I try to get the years the problem comes up.
I'm using the following code:
Calendar startDate = new GregorianCalendar(year, month, day);
Calendar date = Calendar.getInstance();
long diff = date.getTimeInMillis() - startDate.getTimeInMillis();
long seconds = diff / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
long days = hours / 24;
double years = date.get(Calendar.YEAR) - startDate.get(Calendar.YEAR);
Let's say the start date is 07/25/1994 and the end date is 07/28/2015
the result that I get is (21.0) instead of the of 20.97 . I need to get the exact age in YEARS for the users so; can you help me guys out?. Thanks!
Use BigDecimal instead of double and long. When you want precise calculations of floating point numbers, always use BigDecimal. Floating point math is not reliable in java. Simple example is System.out.println(2.00 - 1.10); guess what, it doesnt print .90.
You need to cast your variables:
double years = (double) date.get(Calendar.YEAR) - (double) startDate.get(Calendar.YEAR);
Is your question about elapsed time or about decimal number calculation?
If the first, you should know that decimal numbers for elapsed years is somewhat odd. If the second, you should change the title of your Question.
Elapsed Time
For Android, you should be using the Joda-Time library rather than the old java.util.Date/.Calendar classes. The old classes are notoriously troublesome.
The ISO 8601 standard defines string formats for various kinds of date-time values. For a span of time in terms of a count of years, months, days, hours, minutes, and seconds, the format is PnYnMnDTnHnMnS where P defines the beginning and T separates the days portion from hours portion. The Question is about a span of P21Y3D, or 21 years and 3 days. The Joda-Time library uses this standard format for both parsing and generating such strings.
LocalDate start = new LocalDate( 1994, 7, 25 ); // 07/25/1994
LocalDate stop = new LocalDate( 2015, 7, 28 ); // 07/28/2015
Period period = new Period( start, stop );
System.out.println("start: " + start + " to stop: " + stop + " is " + period );
When run.
start: 1994-07-25 to stop: 2015-07-28 is P21Y3D
Decimal Number Calculation
If you are just asking about the decimal numbers, then the answer by Samrat Dutta is correct: Use BigDecimal if you care about accuracy. Otherwise you are using primitives with floating-point calculations. Floating-point trades off accuracy for speed of execution. As a general rule, if in doubt about which to use for business problems, go with BigDecimal rather than floating-point.
What do you mean by "exact age in years"? Here's the number of years with up to 200 decimal places:
21.00752908966461327857631759069130732375085557837097878165639972621492128678986995208761122518822724161533196440793976728268309377138945927446954140999315537303216974674880219028062970568104038329911020
Integer days = Days.daysBetween( start, stop ).getDays( );
BigDecimal daysPerYear = new BigDecimal( 365.25 ); // Approximate.
int scale = 200; // Number of fractional digits desired.
BigDecimal years = new BigDecimal( days ).divide( daysPerYear, scale, RoundingMode.HALF_EVEN ); // Banker's rounding.
System.out.println( "days: " + days + " ÷ " + daysPerYear + " = " + years + " years." );
When run.
days: 7673 ÷ 365.25 = 21.00752908966461327857631759069130732375085557837097878165639972621492128678986995208761122518822724161533196440793976728268309377138945927446954140999315537303216974674880219028062970568104038329911020 years.
As I said, you may find P21Y3D makes more sense than this decimal number.
I created a filter that monitors the length of a request.
long start = System.nanoTime();
...
long end = System.nanoTime();
How can I get the number of milliseconds from this now?
(end - start) / 1000000
1 microsecond = 1000 nanoseconds
1 millisecond = 1000 microseconds
Note, that the result will be rounded down, but you usually don't get true nanosecond accuracy anyway (accuracy depends on the OS). From the Javadoc on nanoTime():
This method provides nanosecond precision, but not
necessarily nanosecond accuracy.
Also note that you can use the TimeUnit class to help with conversion. With older versions of Java, the following code might be an example to transform a processing time into some other time format:
long startTime = System.nanoTime();
//Processing in-between.
long endTime = System.nanoTime();
long duration = endTime - startTime;
duration = TimeUnit.SECONDS.convert(duration, TimeUnit.NANOSECONDS);
Note that newer versions of Java have shortcuts in the TimeUnit class.
The above sample will turn nanoseconds long into seconds. Also note that this truncates it so you do lose some precision. Therefore, if you switch to minutes then you will lose the precision of seconds. If you want to get a result of "12 minutes and 32 seconds" then you would have to do further processing with this solution.
TimeUnit#toMillis(long) (since Java 5)
TimeUnit.NANOSECONDS.toMillis(end - start);
OR
Duration#toMillis() (since Java 8)
Duration.ofNanos(end - start).toMillis()
OR
Duration#between(Temporal, Temporal) (since Java 8)
Instant start = Instant.now();
...
Instant end = Instant.now();
Duration.between(start, end).toMillis()
OR
ChronoUnit.html#between(Temporal, Temporal) (since Java 8)
Instant start = Instant.now();
...
Instant end = Instant.now();
ChronoUnit.MILLIS.between(start, end)
Just subtract them and divide result by 10^6.
1 nanosecond is 10^-9 seconds and, correspondingly, 10^-6 milliseconds.
http://en.wikipedia.org/wiki/Nano-
You could just use System.currentTimeMillis().
Caveat:
Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
To get a meaningful result:
void procedure ( ... )
{
...
}
double measureProcedure ( double epsilon , ... )
{
double mean ;
double stderr = 2 * epsilon ;
while ( stderr > epsilon )
{
long start = System.nanoTime();
procedure ( ... ) ;
long end = System.nanoTime();
// recalculate mean , stderr
}
return ( mean / 1000000 ) ;
}