Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I elegantly print the %z (timezone) format in Perl on Windows?

An offshoot of How do I elegantly print the date in RFC822 format in Perl?, but Windows specific.

On windows:

    C:\> perl -MPOSIX
    print strftime('%z', localtime()),"\n";

Yields:

    Central Daylight Time

I was expecting:

    -0500

As anyone would on a Linux system. How can I get the "-0500" on Windows?

UPDATE:

Is this really terrible to do in its place? (Assuming I'm not allowed to install DateTime or package it in any way)

C:\> perl -MPOSIX
sub tzoffset {
    my $t = time();
    my $utc = mktime(gmtime($t));
    my $local = mktime(localtime($t));

    return ($local - $utc);
}

sub zformat {
    my ($tzoffset) = @_;
    my $z = '';
    if ($tzoffset < 0) { 
        $z .= '-';
        $tzoffset *= -1;
    } 
    my $hours = floor($tzoffset / 60 / 60);
    my $minutes = $tzoffset - $hours * 60 * 60;
    $z .= sprintf('%02d%02d', $hours, $minutes);
    return $z;
}

print zformat(tzoffset()),"\n";

The problem I've noticed is that this returns -0600 vs -0500 (which I'd expect), but my guess is that is due to DST calculations or something? I'm mainly looking for a decent approximation, but I can't figure out why mktime() is playing with DST?

UPDATE:

Found out that tzoffset() can be much more "stable" in terms of DST if you just manually force DST off.

sub tzoffset {
    my $t = time();
    my $utc = mktime(gmtime($t));
    my @tmlocal = localtime($t);
    $tmlocal[8] = 0; # force dst off, timezone specific
    my $local = mktime(@tmlocal);

    return ($local - $utc);
}

This way, no matter if you're DST or not, it'll always return -0500 which is what you want from %z.

like image 833
dlamotte Avatar asked Apr 13 '10 18:04

dlamotte


1 Answers

I think the reason you're getting the former is because

  1. %z is Linux specific
  2. On Windows it's somehow going all case-insensitive on you and picking up upper-case Z instead.

From manpage:

%Z    Time zone name or abbreviation, or no bytes if no time
       zone information exists.

Also, "%z" seems to be Linux specific - does not work on Solaris either:

$ perl -MPOSIX -e 'print strftime("%z", localtime()),"\n"' 
%z
$ perl -MPOSIX -e 'print strftime("%Z", localtime()),"\n"' 
EDT

whereas on Linux I get:

$ perl -MPOSIX -e 'print strftime("%z", localtime()),"\n"' 
-0400

If you have DateTime::Format installed, I think it might suport %z based on POD. I don't have it installed so can't test yet

Also DateTime may support it without the DateTime::Format.

like image 73
DVK Avatar answered Nov 15 '22 08:11

DVK