1

i was playing around with POSIX qw{strftime}; to use as uptime for a program and i found something i didn't know why it happend. I don't use time that much, this was the reason i was messing with it (learning to fill "time" :P) the math gives me | uptime: 01:00:00 where i should be 00:00:00 I put in the line $stop_secs = $stop_secs - "3600"; and "fixed" it, but I wonder where that extra hour came from.

i have no clue why, can anyone explain this or why this happens? thanks.

#!/usr/bin/perl
#
use strict;
use warnings;
use POSIX qw{strftime};


my $start_secs = time();
my $start_time = strftime '%H:%M:%S', localtime $start_secs; # all is: "%Y-%m-%d %H:%M:%S"

my $stop_secs = time();
$stop_secs = $stop_secs - "3600";  #<--- this fix the 1h "bug"? 

my $diff_secs = $stop_secs - $start_secs;
my $diff_time = strftime '%H:%M:%S', localtime $diff_secs;

print " 
    | Time started: $start_time
    | uptime:   $diff_time

\n";
Sounix
  • 13
  • 4

3 Answers3

1

localtime(0) produces information about the time in your local time zone as of the beginning of the epoch. Unless you are in the same time zone as Greenwich, England (and not on daylights savings time), strftime will not convert it to zeros. For example, here in California, I get

$ perl -MPOSIX=strftime -E 'say strftime "%H:%M:%S",localtime(0)'
16:00:00

I don't know if the combination of strftime and a perl function that returns a list of time information is quite the right tool for this job, but if you're going to go that way, use gmtime instead of localtime.

$ perl -MPOSIX=strftime -E 'say strftime "%H:%M:%S",gmtime(0)'
00:00:00
mob
  • 117,087
  • 18
  • 149
  • 283
  • it seems `gmtime` made it worse and gave me 2h wrong time, i look in to how `localtime()` and how it processes the request i make when i use it. but it seems to fix the math – Sounix Apr 25 '20 at 18:09
  • @Sounix, Re "*`gmtime` made it worse*", eh? You are mistaken. `strftime "%H:%M:%S",gmtime(0))` will always return `00:00:00`. 1 s will return `00:00:01`. 60 s will return `00:01:00`, etc. This will work up to but not including 24*60*60. – ikegami Apr 26 '20 at 06:28
  • yep, it made my `localtime` wrong by two hours but it fixed the math :P. But like you explaned it isn't the right tool for the job and i learned something new. thanks for your help. ;-) `result => | uptime: 00:00:00` – Sounix Apr 27 '20 at 02:57
1

time returns a datetime (in a calendar).

localtime, gmtime and POSIX::strftime are meant to handle those calendar dates - not timespans.

I'd suggest looking into DateTime for dates and DateTime::Span for spans.

Silvar
  • 705
  • 3
  • 8
1

localtime($seconds) returns the information about the local date-time corresponding to $seconds seconds past Midnight, Jan 1st, 1970, UTC (1970-01-01T00:00:00Z), ignoring leap seconds.

So let's say that a machine uses Europe/Paris as its time zone. When it was 0 seconds past 1970-01-01T00:00:00Z, the local time would have been 1970-01-01T01:00:00+01:00. On such a machine, you therefore get 01:00:00.

#!/usr/bin/perl
use feature qw( say );
use POSIX qw( strftime );
say strftime("%Y-%m-%dT%H:%M:%S%z", localtime(0)) =~ s/(?=..\z)/:/r;
say strftime("           %H:%M:%S", localtime(0));
$ TZ=Europe/Paris ./a
1970-01-01T01:00:00+01:00
           01:00:00

$ TZ=America/Montreal ./a
1969-12-31T19:00:00-05:00
           19:00:00

You shouldn't be using localtime. You could use gmtime to some extent.

#!/usr/bin/perl
use feature qw( say );
use POSIX qw( strftime );
say strftime("%Y-%m-%dT%H:%M:%SZ", gmtime(0));
say strftime("           %H:%M:%S", gmtime(0));
$ TZ=Europe/Paris ./b
1970-01-01T00:00:00Z
           00:00:00

$ TZ=America/Montreal ./b
1970-01-01T00:00:00Z
           00:00:00

But really, you shouldn't even be using strftime since that's for date-times, not durations. It will work, but only an extent.

  • strftime("%H:%M:%S", gmtime($secs)) will work for durations up to but not including 24*60*60 seconds.
  • strftime("%d:%H:%M:%S", gmtime($secs)) will work for durations up to but not including 31*24*60*60 seconds, if you're ok with representing a day as having 24 hours.
ikegami
  • 367,544
  • 15
  • 269
  • 518