theprasunranjan
theprasunranjan

Reputation: 105

How to add a series of string inputs that each represent a span of time, in Android?

I am fetching a list of times from server and want to add to show the total time taken. But unable to find how to do. Because the time is in like a normal sentence.

15 min 24 s
1 min 56 s
18 min 3 s
2 h 48 min 46 s

How to add these data?

Upvotes: 0

Views: 69

Answers (1)

Basil Bourque
Basil Bourque

Reputation: 339362

tl;dr

Use java.time.Duration class with standard ISO 8601 input strings.

Duration total = 
    Duration
    .parse(
        "PT" + 
        "2 h 48 min 46 s"
        .replace( "h" , "H" ) 
        .replace( "min" , "M" )
        .replace( "s" , "S" ) 
        .replace( " " , "" )    
    )
    .plus(
        … another `Duration` object
    )

ISO 8601

Educate the publisher of that data about the ISO 8601 standard that defines many formats for communicating date-time values as text.

The standard format for a span of time unattached to the timeline is PnYnMnDTnHnMnS where the P marks the beginning (think of that as "p" for "period") and the T separates any years-months-days from any hours-minutes-seconds.

Convert your inputs

Your example inputs could be converted to ISO 8601 format.

Replace min with M. Replace h with H. And replace s with S.

Also, delete any SPACE characters. Prepend with PT.

String input = "2 h 48 min 46 s" ;
String inputIso8601 = 
        "PT" + 
        input
        .replace( "h" , "H" ) 
        .replace( "min" , "M" )
        .replace( "s" , "S" ) 
        .replace( " " , "" )      
;

Duration

The modern java.time classes in Java include Duration. That class represents a span of time unattached to the timeline on a scale of hours-minutes-seconds.

That class knows how to parse and generate strings in standard ISO 8601 format.

Duration d = Duration.parse( inputIso8601 ) ;

That class also knows how to do math, adding and subtracting durations.

Duration dTotal = d1.plus( d2 ) ;

Example

Let's make a method of that conversion code.

public String convertInputToIso8601 ( String input )
{
    String inputIso8601 =
            "PT" +
                    input
                            .replace( "h" , "H" )
                            .replace( "min" , "M" )
                            .replace( "s" , "S" )
                            .replace( " " , "" );
    return inputIso8601;
}

Let's use your example inputs.

    List < String > inputs = List.of(
            "15 min 24 s" ,
            "1 min 56 s" ,
            "18 min 3 s" ,
            "2 h 48 min 46 s"
    );

Test converting the format of those inputs.

    List < String > inputsIso8601 = 
        inputs
        .stream()
        .map( this :: convertInputToIso8601 )
        .collect( Collectors.toList() )
    ;

Dump to console.

    System.out.println(
            inputsIso8601
    );

[PT15M24S, PT1M56S, PT18M3S, PT2H48M46S]

That looks good. Now parse as Duration objects.

    List < Duration > durations = 
        inputsIso8601
        .stream()
        .map( Duration :: parse )
        .collect( Collectors.toList() )
    ;

Dump to console.

    System.out.println( durations );

[PT15M24S, PT1M56S, PT18M3S, PT2H48M46S]

That also looks good. Now do the math. The java.time classes use immutable objects. This means our math operations result in a new fresh object, rather than altering (mutating) the original.

Using conventional syntax to sum the durations.

    Duration total = Duration.ZERO;
    for ( Duration duration : durations )
    {
        total = total.plus( duration );
    }

Using streams to sum the durations.

Duration total = 
    durations
    .stream()
    .reduce(
        Duration.ZERO , 
        Duration::plus
    )
;

Dump to console.

    System.out.println( "total = " + total );

total = PT3H24M9S

That worked. Your inputs totaled almost three and a half hours.

Here is that code again, all together.

    List < String > inputs = List.of(
            "15 min 24 s" ,
            "1 min 56 s" ,
            "18 min 3 s" ,
            "2 h 48 min 46 s"
    );

    List < String > inputsIso8601 = inputs.stream().map( this :: convertInputToIso8601 ).collect( Collectors.toList() );
    System.out.println( inputsIso8601 );

    List < Duration > durations = inputsIso8601.stream().map( Duration :: parse ).collect( Collectors.toList() );
    System.out.println( durations );

    Duration total = durations.stream().reduce( Duration.ZERO , Duration::plus ) ;

    System.out.println( "total = " + total );

I imagine we could combine those three streaming statements into a single one. But reading and debugging would likel’y be more difficult.


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.

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

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

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

Where to obtain the java.time classes?

Upvotes: 3

Related Questions