peter Schiza
peter Schiza

Reputation: 387

Parse period of time in Java

I want to be able to parse period of time (days, hours, minutes) + optional string so the input looks like this: <time>(white_spaces)<optional_string>. As i know regex is the right tool for such things so i came up with such expression:

Pattern.compile("((?<days>\\d+)d)?((?<hours>\\d+)h)?((?<minutes>\\d+)m)?\\s+?(?<reason>.+)?");

Basically it works as expected however in this expression all times groups (days, hours, minutes) are optional and i want the input to atleast contain minutes group. However if hours or days are specified, minutes are not required. Also, all combinations of time groups (d+h, h+m, d+m, d+h+m) are possible. So how can i correct my expression? Or maybe there is other way to parse period of time?

EDIT: examples of inputs:

12h64m - correct

12d43m dsd - correct

- empty string - not correct

12m - correct

12d32h43m - correct

sdsds - not correct - no "time group specified"

Upvotes: 1

Views: 4654

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 338785

tl;dr

Duration.parse( 
    "P"
    .concat( "12d32h43m".replace( "d" , "DT" ) )
    .toUpperCase()
).toHoursPart()

8

You said:

As i know regex is the right tool for such things

Nope. No need for regex.

ISO 8601

Your input string format is close to the format formally defined by the ISO 8601 standard: PnYnMnDTnHnMnS

The P marks the beginning. The T separates any years-months-days from any hours-minutes-seconds.

Convert your input to conform with the standard.

String input =  "P".concat( "12d32h43m".replace( "d" , "DT" ) ).toUpperCase() ;

P12DT32H43M

java.time

Java has a class for that, Duration (and Period). No need for regex.

You can interrogate for each part. Call to…Part methods added in Java 9. For Java 8, see this Question and this Question.

long daysPart = d.toDaysPart() ;
int hoursPart = d.toHoursPart() ;

Entire example:

String input = "P".concat( "12d32h43m".replace( "d" , "DT" ) ).toUpperCase();
Duration d = Duration.parse( input );
long daysPart = d.toDaysPart();
int hoursPart = d.toHoursPart();
long hoursTotal = d.toHours(); // Total elapsed hours of entire duration.

Dump to console. Notice the math. Your input of 32 hours is recalculated to be 8, and days went from 12 to 13 (an extra 24-hour chunk = a day).

System.out.println( "input: " + input );
System.out.println( "d.toString()" + d );
System.out.println( "daysPart: " + daysPart );  // 13, not the 12 days seen in the input string. 24 hours were taken from the excessive `32h` of the input string, leaving 8 in the hours part.
System.out.println( "hoursPart: " + hoursPart );
System.out.println( "hoursTotal: " + hoursTotal );  // ( ( 13 * 24 ) + 8 ) = ( 312 + 8 ) = 320 

input: P12DT32H43M

d.toString()PT320H43M

daysPart: 13

hoursPart: 8

hoursTotal: 320

Duration versus Period

Use Duration for hours-minutes-seconds values. Use Period for years-months-days values.

  • In a Duration, “days” are understood to be generic chunks of 24-hours unrelated to dates and the calendar.
  • If you want dates, you should be using the Period class.
  • If you want both, think again. It usually does not make sense to mix the two concepts, though this may seem counter-intuitive at first thought. But if you insist, see the PeriodDuration class available in the ThreeTen-Extra project.

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Upvotes: 11

user unknown
user unknown

Reputation: 36229

((?<minutes>\\d+)m)? means, the minutes group is optional. But you want it to be mandatory, so remove the trailing question mark.

Upvotes: 0

Related Questions