skip to Main Content

I have a program that calculates the amount of Days, Hours, Minutes or Seconds that are given but it is only capable of taking in 1 argument such as "1d" = 86400 seconds.

Now I want it to calculate when receiving "1d 3h 16m 2s" and convert it to the amount of seconds. Also when given a wrong input, I want it to tell the user something like "wrong input".

How could I make that work?

This is the code I have so far (which works for a single value) — now I need to modify it for the extended input data

<?php 

switch (substr((string)$argv[1], -1)) {
    case "d":
        echo ((int)$argv[1] * 86400);
        break;
    case "h":
        echo ((int)$argv[1] * 3600);
        break;
    case "m":
        echo ((int)$argv[1] * 60);
        break;
    case "s":
        echo ((int)$argv[1] * 1);
        break;
}

?>



2

Answers


  1. To match several unit time I used preg_match_all() function and then use a switch iteration for each time unit. Calculate the seconds for each unit and sum it.

    <?php
       $input = '1d 3h 16m 2s';
        $seconds = 0;
        $pattern = "/(d+)(d|h|m|s)/";
    
        preg_match_all($pattern, $input, $matches);
    
        for ($i = 0; $i < count($matches[0]); $i++) {
            switch ($matches[2][$i]) {
                case "d":
                    $seconds += (int)$matches[1][$i] * 86400;
                    break;
                case "h":
                    $seconds += (int)$matches[1][$i] * 3600;
                    break;
                case "m":
                    $seconds += (int)$matches[1][$i] * 60;
                    break;
                case "s":
                    $seconds += (int)$matches[1][$i];
                    break;
                default:
                    echo "Invalid input format";
                    return;
            }
        }
    
        echo $seconds;
    

    PHP online : https://onlinephp.io/c/f7d8c

    Login or Signup to reply.
  2. Assuming you don’t have any higher units to parse and the units are always in big-endian order, you can use a single regex patter to parse all of data in the string, then use simple arithmetic to calculate the seconds.

    The regex will attempt to capture the number of each optional unit. Even if a given unit does not exist, the matches array will still hold the place so that the elements are always consistently placed. The subpatterns are rather repetious so this will make it easier to extend/reduce if needed.

    Code: (Demo)

    preg_match('/^(?:(d+)d ?)?(?:(d+)h ?)?(?:(d+)m ?)?(?:(d+)s)?$/', $input, $m);
    echo ((int) ($m[1] ?? 0) * 86400)
         + ((int) ($m[2] ?? 0) * 3600)
         + ((int) ($m[3] ?? 0) * 60)
         + (int) ($m[4] ?? 0) . " seconds";
    

    If your input data is consistently formatted and always contains each unit, then the process is much simpler because sscanf() can parse the numbers directly to integers. (Demo)

    sscanf($input, '%dd %dh %dm %ds', $d, $h, $m, $s);
    echo $d * 86400 + $h * 3600 + $m * 60 + $s;
    

    If units are not guaranteed to exist or may exist in any order, you can use this functional-style snippet to parse the expression. It isolates each number-unit pair, leverages a lookup array to multiply the number by the appropriate factor, then sum the calculations. (Demo)

    define('UNIT_TO_SECONDS', ['d' => 86400, 'h' => 3600, 'm' => 60, 's' => 1]);
    
    echo array_reduce(
             preg_match_all('/(d+)([dhms])/', $input, $m, PREG_SET_ORDER) ? $m : [],
             fn($sum, $parts) => $sum + UNIT_TO_SECONDS[$parts[2]] * (int) $parts[1],
             0 // initialize $sum with 0 value
         );
    

    As for signalling to the user that an invalid expression has been passed in, you could check for a falsey return valud from preg_match(), sscanf(), or preg_match_all() before processing further. If one of the preg_ functions returns 0, then something went wrong. If sscanf() returns false, then something went wrong. You will need to clarify if 1d 3d is an invalid input as well as expressing how variable your data is allowed to be before we can confidently offer advice on the validation.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search