Re: Getting times (weeks, days, hours, minutes, seconds)
by ikegami (Patriarch) on Jul 04, 2010 at 21:09 UTC
|
int to remove fractions. Then remove the minutes from the seconds, and remove the hours from the minutes.
use strict;
use warnings;
my @times = qw( 5:21 8:01 5:37 7:19 5:46 7:44 6:43 7:17 8:02 6:50 7:54
+ 8:44 );
my $total_seconds;
for my $time (@times) {
my ($mins, $secs) = split(/:/, $time);
$total_seconds += $mins*60 + $secs;
}
my $total_minutes = int($total_seconds/60);
$total_seconds -= $total_minutes*60;
my $total_hours = int($total_minutes/60);
$total_minutes -= $total_hours*60;
printf("%s hours, %s minutes, %s seconds\n",
$total_hours,
$total_minutes,
$total_seconds,
);
It is the -> and the printf (which has never made sense to me) that have me stumped.
$t->printf is a method call just like the preceding $t->calc, $t->new_delta and Date::Manip::Delta->new. | [reply] [d/l] [select] |
|
|
Thanks to everyone who responded. I don't want to spam the place responding to everyone, so I hope you all don't mind just this one post. Also, thanks for showing me modules and functions that are new to me. I will look into them further if I need them later. For something as simple as this, I decided to just do a little math myself.
I hope that you all aren't disappointed that I just used return instead of printf in my subroutine. The whole print vs. printf conversation seems best left for a completely independent thread.
Leap seconds? Where have I been? :)
Looks like the -> may have something to do with objects and classes, which I am not versed in yet. I have read over several perldocs on objects and barely get it. I haven't dealt with objects in any code I have written. Objects seems to be another topic left to an independent thread. I think I would need to see a full example all together to begin to grasp the subject.
Again, thank you all for helping me out. Have some cookies!
use strict;
use warnings;
#I made my variables more semantic. @times was just to general, %durat
+ions is a better word, thanks to those who used it. :)
my %durations = (
's1' => [qw(3:58 2:48 4:28 5:06 6:50 5:33 4:05 3:29 4:48 6:19)],
's2' => [qw(5:33 5:08 5:30 6:52 6:56 6:48 6:34 5:43 6:50 8:32 6:22 8
+:39)],
's3' => [qw(5:21 8:01 5:37 7:19 5:46 7:44 6:43 7:17 8:02 6:50 7:54 8
+:44)],
);
# %durations are minutes and seconds.
sub get_duration {
my ($var) = @_;
my $total_seconds;
for my $duration (@{$durations{$var}}) {
my ($minutes,$seconds) = split(':',$duration); # The change here m
+ade the line much easier to read. :)
$total_seconds += ($minutes * 60) + $seconds; # This eliminated my
+ need to create another array then adding the values of that array. :
+)
}
my $total_minutes = int($total_seconds/60); #I totally forgot about
+int. :S
my $total_hours = int($total_minutes/60);
my $print_seconds = $total_seconds % 60;
my $print_minutes = $total_minutes % 60;
return $total_hours.':'.$print_minutes.':'.$print_seconds."\n";
}
print get_duration('s1');
print get_duration('s2');
print get_duration('s3');
Have a nice day!
Lady Aleena
| [reply] [d/l] [select] |
|
|
my ($h,$m,$s) = ...;
$m = "0$m" if $m < 10;
$s = "0$s" if $s < 10;
my $dur = "$h:$m:$s";
vs
my ($h,$m,$s) = ...;
my $dur = sprintf("%d:%02d:%02d", $h,$m,$s);
Right now, you are creating timestamps like 1:3:43 instead of 1:03:43. printf and sprintf are quite apt at formatting this kind of data, but you don't have to use them. Take your pick.
%d Signed 32/64-bit integer
%2d ...space padded (on the left) to occupy (at least) 2 columns
%02d ...zero padded (on the left) to occupy (at least) 2 columns
hope that you all aren't disappointed that I just used return instead of printf in my subroutine.
No, separation of calculation and I/O is a good thing. However,
print get_duration('s1');
should be
print get_duration($durations{s1});
or
print get_duration(@{ $durations{s1} });
(with the corresponding changes within get_duration). There's no reason for %durations to be global.
Leap seconds? Where have I been? :)
That post tries to show why DateTime wasn't a good solution for this problem, not how to solve the problem using DateTime. Sounds like it worked.
I have read over several perldocs on objects and barely get it
In short,
- Objects represent some object (e.g. a specific user, a specific window, a specific timestamp, etc).
- A type of object (e.g. user, window, timestamp) is called a class.
- Objects contain data about that object ("attributes") and the class provides functions to manipulate the objects ("methods").
- Methods can provide access to the attributes of an object (e.g. my $title = $window->get_title() and $window->set_title($title);)
- Methods can provide cause actions to be performed. (e.g. $window->close();)
| [reply] [d/l] [select] |
Re: Getting times (weeks, days, hours, minutes, seconds)
by Proclus (Beadle) on Jul 05, 2010 at 06:22 UTC
|
You should look at DateTime. You can do all sorts of date math with a very easy interface. The examples will guide you through it.
| [reply] |
|
|
The was nothing requiring date math in the OP, but DateTime also does time math. Since the OP is dealing with durations, she'd need DateTime::Duration.
Unfortunately, it doesn't produce the result one would expect because DateTime(::Duration) realises that not every minute has 60 seconds. Some are longer due to leap seconds.
use strict;
use warnings;
use DateTime::Duration qw( );
my @times = qw( 5:21 8:01 5:37 7:19 5:46 7:44 6:43 7:17 8:02 6:50 7:54
+ 8:44 );
my $dur = DateTime::Duration->new();
for my $time (@times) {
my ($mins, $secs) = split(/:/, $time);
$dur += DateTime::Duration->new(
minutes => $mins,
seconds => $secs,
);
}
printf("%s hours, %s minutes, %s seconds\n",
$dur->in_units(qw( hours minutes seconds ))
);
1 hours, 19 minutes, 378 seconds
From the docs, the only conversions possible are:
- years ⇔ months
- weeks ⇔ days
- hours ⇔ minutes
- seconds ⇔ nanoseconds
Now, you can use a reference datetime to determine minute length.
...
my $dur2 = do {
my $ref = DateTime->new(
year => 2006, month => 1, day => 1,
hour => 0, minute => 0, second => 0,
time_zone => 'UTC',
);
$ref + $dur - $ref
};
printf("%s hours, %s minutes, %s seconds\n",
$dur2->in_units(qw( hours minutes seconds ))
);
my $dur3 = do {
my $ref = DateTime->new(
year => 2005, month => 12, day => 31,
hour => 23, minute => 59, second => 59,
time_zone => 'UTC',
);
$ref + $dur - $ref
};
printf("%s hours, %s minutes, %s seconds\n",
$dur3->in_units(qw( hours minutes seconds ))
);
1 hours, 19 minutes, 378 seconds
1 hours, 25 minutes, 18 seconds # All of the minutes had 60 seconds.
1 hours, 25 minutes, 19 seconds # One of the minutes had 61 seconds.
Update: Added example where leap seconds affect the result. | [reply] [d/l] [select] |
|
|
| [reply] |
|
|
Re: Getting times (weeks, days, hours, minutes, seconds)
by jethro (Monsignor) on Jul 05, 2010 at 09:37 UTC
|
$something->func($x);
is nearly the same as
func($something,$x);
with func a subroutine out of the package (called class) that $something belongs to
There is also an easy way to understand printf:
printf("bla %xyz chink %ru wong",$a,$b);
is somewhat equivalent to
print "bla $a chink $b wong";
The printf often does some conversions of the variables, but basically thats it.
Now in the code someone on IRC gave you the printf is not the normal builtin perl printf, since it was called with the -> syntax. Instead it must be subroutine out of the package $t belongs to. What package does $t belong to? Date::Manip::Delta, since $t was created with my $t = Date::Manip::Delta->new;
UPDATE: Added the word 'nearly'
| [reply] [d/l] [select] |
|
|
$something->func($x) and func($something,$x) aren't exactly equivalent. The second one will ignore inheritance.
| [reply] [d/l] [select] |
|
|
$something->func($x)
is rarely equivalent to
func($something, $x)
More like
Class::Or::Superclass::Of::Something::func($something, $x)
Your explanation just reinforces the OP's misconception that printf gets called, but it's not involved one bit. | [reply] [d/l] [select] |
|
|
Not if she reads the complete sentence, and definitely not if she reads the complete post. And if you throw "Class::Or::Superclass::Of::Something::func($something, $x)" at someone unfamiliar with basic concepts of perl OO, you might as well offer a zen koan ;-).
| [reply] |
|
|
|
|
Re: Getting times (weeks, days, hours, minutes, seconds)
by DrHyde (Prior) on Jul 05, 2010 at 10:06 UTC
|
I am very confused. I have never written code that looks like that. It is the -> and the printf (which has never made sense to me) that have me stumped.
$foo->bar() is a method call on an object, and Foo->bar() is a method call on a class. See perlboot and perltoot for tutorials.
printf is one of Date::Manip::Delta's methods, so you can find its documentation there. Or if it's the whole idea of printf() and its friends and relations that confuses you even after reading the sprintf manpage on your system, then I suggest reading chapters 1 and 7 of Kernighan and Ritchie's "The C Programming Language".
| [reply] [d/l] [select] |
Re: Getting times (weeks, days, hours, minutes, seconds)
by roboticus (Chancellor) on Jul 05, 2010 at 12:21 UTC
|
Lady Aleena:
Actually, you weren't that far off. I avoid the decimal bits by removing the surplus seconds before the division.
For example, if you have 77 seconds, you first tell how many leftover seconds you'll get in the answer, like so: $secs = 77 % 60 giving you 17. Then you subtract those 17 seconds from your time in seconds to give you an integral multiple of 60: $t=($t-$secs)/60. You can extend it as far as you like:
#!/usr/bin/perl -w
use strict;
use warnings;
print time_to_string(1234), "\n";
print time_to_string(12345), "\n";
print time_to_string(123456), "\n";
sub time_to_string {
my $t = shift; # t=total time in seconds
my $seconds = $t % 60; $t=($t-$seconds)/60; # t now has minutes
my $minutes = $t % 60; $t=($t-$minutes)/60; # t now has hours
my $hours = $t % 24; $t=($t-$hours) /24; # t now has days
my $str = '';
$str .= "$t days, " if $t>0;
$str .= sprintf "% 2u:% 2u:% 2u", $hours, $minutes, $seconds;
}
Running this gives me:
roboticus@Boink:~$ ./848005.pl
0:20:34
3:25:45
1 days, 10:17:36
roboticus@Boink:~$
...roboticus | [reply] [d/l] [select] |
Re: Getting times (weeks, days, hours, minutes, seconds)
by Marshall (Canon) on Jul 05, 2010 at 14:04 UTC
|
Here is another way... Simply, sum the minutes and seconds and use gmtime() to convert the total number of seconds to hours, minutes, seconds. This of course assumes some time delta from the epoch number of seconds(0) for each item. Which is fine in this case as we are measuring duration, not absolute date values. The year and day of week, etc are all meaningless in this context so just throw them away. Leap seconds, leap years don't matter as long as we are talking about data like your example.
#!/usr/bin/perl -w
use strict;
my @times = qw( 5:21 8:01 5:37 7:19 5:46 7:44 6:43 7:17 8:02 6:50 7:54
+ 8:44 );
my $total_minutes;
my $total_seconds;
foreach my $time (@times)
{
my ($m,$s) = split(':',$time);
$total_minutes += $m;
$total_seconds += $s;
}
my ($h,$m,$s) = (gmtime($total_minutes*60+$total_seconds))[2,1,0];
print "$h hours, $m minutes, $s seconds";
#1 hours, 25 minutes, 18 seconds
The list slice isn't necessary, but I like to line up the left hand side vars so that they are in the order that I use them later. my ($s,$m,$h) would be fine without the slice. | [reply] [d/l] |