in reply to Convert time string to seconds

Moritz has the answer to your question.

I have some concerns about your approach.

The formats you list,

min:sec,frac e.g. "5:29,11" sec,frac e.g. "29,11" sec e.g. "29" ,frac e.g. ",11" min:sec e.g. "5:29" someth. else e.g. "abc"

are not normalized. In consequence, you provide no coverage of possibilities such as 5:29,3, which appears to be at least theoretically possible in your schema. Were you to begin by normalizing the data to mm:ss,frac, writing a reliable conversion to seconds would be both more reliable and easier (and which is left as an exercise for the user).

That said, and accepting the un-normalized data, suhailck's solution has much to commend it, but also has a couple glitches:

  1. Its initial test of the string won't correctly handle mixed alphanumerics, such as 1abc
  2. Its use of $3/10**2 in calculation of the decimal portion fails to consider the possiobility (again, not in your schema, but, ISTM, distinctly possible) of a single-digit, decimal fraction, such as .3 or a decimal fraction where length > 2, as, for example, .303

So, in part TIMTOWTDI, and in part, perhaps by way of improvement:

#!/usr/bin/perl use strict; use warnings; # 855222 # 1) min:sec,frac e.g. "5:29,11" # 2) sec,frac e.g. "29,11" # 3) sec e.g. "29" # 4) ,frac e.g. ",11" # 5) min:sec e.g. "5:29" # 6) someth. else e.g. "abc" my $seconds; my @times=("5:29,11", "29,11", "29:00", "29:00,3", "29:00,303","29:13, +07", ",11", "0:11", "5:29", "abc", "1abc"); for my $time(@times) { no warnings 'uninitialized'; if ($time =~ /[a-z]/i) { # won't catch non-"time-ish" symbols s +uch as ?, #, @, etc # $seconds = -1; # my personal preference is for an explicit er +ror statement print "Data not recognized: $time\n"; next; } else { ($seconds = $time) =~ s<^(?:(\d+):)?(\d+)?(?:,(\d+))?$><$1*60+$2+$ +3/(10**length($3))>e; } print "$time = $seconds \n"; }

which produces:

5:29,11 = 329.11 29,11 = 29.11 29:00 = 1740 29:00,3 = 1740.3 29:00,303 = 1740.303 29:13,07 = 1753.07 ,11 = 0.11 0:11 = 11 5:29 = 329 Data not recognized: abc Data not recognized: 1abc

Replies are listed 'Best First'.
Re^2: Convert time string to seconds
by Dirk80 (Pilgrim) on Aug 17, 2010 at 11:20 UTC

    Thank you all for your answers.

    Now I wrote the following code. It is a bit longer, but more readable I think. And so I'm sure that it really is doing what I want. And I also wrote a function which is doing the way back.

    use strict; use warnings; my @time_str_list = ( "abc", "1abc", ":", ":,", "5:29,11", "29,11", "2 +9:00", "29:00,3", "29:00,303", "9:13,07", ",11", "0:11", "5:29" ); my $seconds; for my $time_str ( @time_str_list ) { &convertTimeStrToSeconds($time_str, \$seconds); next unless defined $seconds; print("$time_str\n"); print("$seconds\n"); &convertSecondsToTimeStr($seconds, \$time_str); next unless defined $time_str; print("$time_str\n"); print("\n"); } sub convertTimeStrToSeconds { my ($time_str, $ref_seconds) = @_; # 1) min:sec,frac e.g. "5:29,11" # 2) sec,frac e.g. "29,11" # 3) sec e.g. "29" # 4) ,frac e.g. ",11" # 5) min:sec e.g. "5:29" # 6) someth. else e.g. "abc" $$ref_seconds = undef; # 6) # remove leading and trailing whitespace characters $time_str =~ s/^\s+|\s+$//g; # valid time string if( ($time_str =~ m/^(?<min>\d+):(?<sec>\d+),(?<frac>\d+)$/) ||# 1 +) ($time_str =~ m/^(?<sec>\d+),(?<frac>\d+)$/) || # 2) ($time_str =~ m/^(?<sec>\d+)$/) || # 3) ($time_str =~ m/^,(?<frac>\d+)$/) || # 4) ($time_str =~ m/^(?<min>\d+):(?<sec>\d+)$/) ) # 5) { no warnings 'uninitialized'; # intention: undef treated as zer +o $$ref_seconds = ($+{'min'} * 60.0) + $+{'sec'} + ($+{'frac'}/( +10**length($+{'frac'}))); } } sub convertSecondsToTimeStr { my ($seconds, $ref_time_str) = @_; $$ref_time_str = undef; if( $seconds > 0 ) { my $min = int($seconds / 60.0); my $sec = $seconds % 60.0; my $frac = int(sprintf("%.2f", ($seconds - int($seconds))*100. +0)); $$ref_time_str = "$min:" if( $min > 0 ); $$ref_time_str .= sprintf("%02d", $sec) if ( ($min > 0) || ($s +ec > 0) ); $$ref_time_str .= ",$frac" if ( $frac > 0 ); } }

    With the error handling you are right. To set $seconds to -1 is not that good. Error handling is in general for me a difficult thing. I'm not sure what is the best way. Now I'm setting the output parameter to undef. Is this good style? Of course I could print a error message. Or I could return undef. Let's assume this function would be part of an official module. What would be the best error handling?

    Thank you and Greetings

    Dirk

      Narrowly re your last two sentences: before publishing, you should probably check that you're not merely duplicating the capabilities already available in some Time::... or Date::... module.

      Then, assuming you do publish, please make the error message clear and specific -- tell precisely what the problem is. The expert won't mind and the occasional coder will be thankful.