2010-01-26 10 views
9

Necesito obtener el desplazamiento UTC de la zona horaria actual en Perl en una plataforma cruzada (Windows y varios sabores de Unix). Debe cumplir con este formato:¿Cuál es la mejor manera de obtener el desplazamiento UTC en Perl?

zzzzzz, lo que representa ± hh: mm en relación a UTC

Parece que yo debería ser capaz de hacerlo a través de strftime(), pero no parece se consistente.

Unix:

Input: perl -MPOSIX -e "print strftime(\"%z\", localtime());" 
Output: -0700 

de Windows:

Input: perl -MPOSIX -e "print strftime(\"%z\", localtime());" 
Output: Mountain Standard Time 

Aunque parece que Unix es que me da lo que quiero (o al menos algo parecido), Windows no lo es. Estoy bastante seguro de que puedo hacerlo con Date::Time o similar, pero realmente me gustaría no tener ninguna dependencia que no puedo garantizar que tenga un usuario debido a nuestra amplia base de instalación.

¿Me falta algo obvio aquí? Gracias por adelantado.

Respuesta

14

Time::Local debe hacer el truco

use Time::Local; 
@t = localtime(time); 
$gmt_offset_in_seconds = timegm(@t) - timelocal(@t); 
+2

'Time :: Local' es un módulo básico en todas las distribuciones de Perl 5. – mob

+0

Esta es una gran solución; solo le dio una prueba rudimentaria, pero parece funcionar como debería. Gracias. – Morinar

-1

una manera portátil es comparar la salida de localtime con gmtime

$t = time; 
    @a = localtime($t); 
    @b = gmtime($t); 

    $hh = $a[2] - $b[2]; 
    $mm = $a[1] - $b[1]; 
    # in the unlikely event that localtime and gmtime are in different years 
    if ($a[5]*366+$a[4]*31+$a[3] > $b[5]*366+$b[4]*31+$b[3]) { 
     $hh += 24; 
    } elsif ($a[5]*366+$a[4]*31+$a[3] < $b[5]*366+$b[4]*31+$b[3]) { 
     $hh -= 24; 
    } 
    if ($hh < 0 && $mm > 0) { 
     $hh++; 
     $mm = 60-$mm; 
    } 
    printf "%+03d:%02d\n", $hh, $mm; 

Alguien señalando que esto ya está implementado en un módulo en algún lugar de 5, 4, 3, ...

+0

Puede explicar el cálculo en el caso DECLARACIÓN - ¿por qué multiplicar el año por el número de días en un año bisiesto? ¿Por qué Mes * 31? ¿Por qué agregar el día? Gracias. –

+0

@Kevin Friedman - es una prueba para ver si '@a [5,4,3]' y '@b [5,4,3]' representan el mismo día. Combino el año, el mes y el día en un solo número para que pueda salir adelante con una comparación en lugar de tres. Podrías usar números más grandes que 366 y 31 y todavía obtendrías el resultado correcto. – mob

+0

Deberías usar los campos de bit en lugar de la multiplicación si quieres ser rápido: '($ a [5] << 13) | ($ a [4] << 5) | $ a [3]'. Además, el operador '<=>' que podría usarse para reemplazar la instrucción if. – dolmen

0

" Realmente me gustaría no tener ninguna dependencia que no puedo garantizar que tenga un usuario debido a nuestra amplia base de instalación "

¿Qué le parece incluir una copia personalizada de la fecha :: Tiempo (lo llamaremos My :: Date :: Time) en su instalación? Por ejemplo,

use lib 'my-module/dependencies/'; 

use My::Date::Time; 
0

Puede calcular la diferencia entre localtime($t) y gmtime($t). Aquí está mi versión inspirada por mob 's answer:

use strict; 
use warnings;  

sub tz_offset 
{ 
    my $t = shift; 
    my @l = localtime($t); 
    my @g = gmtime($t); 

    my $minutes = ($l[2] - $g[2] + ((($l[5]<<9)|$l[7]) <=> (($g[5]<<9)|$g[7])) * 24) * 60 + $l[1] - $g[1]; 
    return $minutes unless wantarray; 
    return (int($minutes/60), $minutes % 60); 
} 

push @ARGV, time; 
foreach my $t (@ARGV) { 
    printf "%s (%d): %+03d%02u\n", scalar localtime($t), $t, tz_offset($t); 
} 
Cuestiones relacionadas