Home > OS >  Parse time/duration expression containing #d #h #m #s and calculate the equivalent total seconds
Parse time/duration expression containing #d #h #m #s and calculate the equivalent total seconds

Time:01-12

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: seconds calculator

CodePudding user response:

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

CodePudding user response:

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, '           
  • Related