0

I have a string that represents time duration of 54:34:41 i.e. 54 hours, 34 minutes, 41 seconds.

I would like to extract the 54 hours and subtract it from the current system time.

However when I run below I get java.time.format.DateTimeParseException: Text '54:34:41' could not be parsed: Invalid value for HourOfDay (valid values 0 - 23): 54

How can I extract 54 hours and subtract from current time?

private val formatterForTime: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss")
val timeDuration = formatterForTime.parse("54:34:41")

val currentTime = LocalDateTime.now()
val newTime = currentTime.minusHours(timeDuration.get(ChronoField.HOUR_OF_DAY).toLong())
mars8
  • 770
  • 1
  • 11
  • 25
  • 1
    I cannot imagine a scenario where calling `LocalDateTime.now` is the right thing to do. That type lacks the context of a time zone or offset from UTC. So it cannot represent a moment, a specific point on the timeline. – Basil Bourque Jun 04 '22 at 07:53
  • Don’t you want to subtract the 34 minutes 41 seconds too? Related: [Java: How to convert a string (HH:MM:SS) to a duration?](https://stackoverflow.com/questions/8257641/java-how-to-convert-a-string-hhmmss-to-a-duration) – Ole V.V. Jun 04 '22 at 19:42
  • 1
    @OleV.V. correct, the answer below can be applied to minutes and second too. I use the same `split` function and instead pull index `[1]` (minute) and `[2]` (seconds), then use `zdt.minusMinutes` and `zdt.minusSeconds` respectively – mars8 Jun 04 '22 at 20:22

1 Answers1

2

tl;dr

ZonedDateTime
.now( 
    ZoneId.of( "Asia/Tokyo" ) 
)
.minusHours(
    Integer.parseInt( "54:34:41".split( ":" )[0] )
)

Details

Parse hours

Get the number of hours.

int hours = Integer.parseInt( "54:34:41".split( ":" )[0] ) ;

ISO 8601

Your input text for a span-of-time does not comply with the ISO 8601 standard for date-time values. The java.time classes by default use the standard formats when parsing/generating text.

If instead of 54:34:41 you had PT54H34M41S, then we could use:

int hours = Duration.parse( "PT54H34M41S" ).toHours() ;

I recommend you stick with the standard format rather than the ambiguous clock-time format.

Capture current moment

Capture the current moment as seen in a particular time zone.

ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;

Subtract hours

Subtract your hours.

ZonedDateTime earlier = zdt.minusHours( hours ) )
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • thanks Basil. Is there any way to get the Locale ZonedDateTime from the phone/OS? Also, i am surprised there is not a more idiomatic way of parsing date with formatters/built in libraries. this solves my problem so have marked as correct answer. – mars8 Jun 04 '22 at 08:14
  • 1
    @mairs8 `ZoneId.systemDefault()` returns the JVM’s current default time zone. `Locale` has nothing to do with tracking time. – Basil Bourque Jun 04 '22 at 14:57
  • 1
    @mairs8 As for idiomatic, your input text for a span-of-time not attached to the time zone does not comply with the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Durations) standard for date-time values used by default in the *java.time* classes. If instead of `54:34:41` you had `PT54H34M41S`, then we could use `Duration.parse( "PT54H34M41S" ).toHours()`. I recommend you use the standard format rather than the ambiguous clock-time format. – Basil Bourque Jun 04 '22 at 15:01