-1

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;
user9754798
  • 133
  • 8
  • Try using BigDecimal instead and see if it works. – Goion Sep 13 '19 at 23:23
  • 5
    Note that `getSeconds()` returns a `long`, so if your duration is less than one second, you'll get 0.0 no matter what. – SDJ Sep 13 '19 at 23:30
  • @Marvin If the difference is milliseconds it gives 0 – Goion Sep 13 '19 at 23:30
  • 1
    `long hours = TimeUnit.SECONDS.toHours(duration.getSeconds());` – Elliott Frisch Sep 13 '19 at 23:32
  • 1
    I'm not sure if I'm getting the issue here. If there is less than 1 second between startTime and endTime, should durationInHours really be something else than 0? – Marvin Sep 13 '19 at 23:32
  • @SDJ Is correct. OP should use `duration.getNano()` to get time. – Goion Sep 13 '19 at 23:33
  • @ElliottFrisch [`Duration.toHours`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/Duration.html#toHours()) is a shorter way to get a whole number of total elapsed hours. – Basil Bourque Sep 14 '19 at 03:28

1 Answers1

2

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" ) ;
Community
  • 1
  • 1
Basil Bourque
  • 218,480
  • 72
  • 657
  • 915