2010-01-26 8 views
9

Ho bisogno di ottenere lo scostamento UTC del fuso orario corrente in Perl in un modo multipiattaforma (Windows e varie versioni di Unix). Esso dovrebbe incontrare questo formato:Qual è il modo migliore per ottenere lo scostamento UTC in Perl?

zzzzzz, che rappresenta ± hh: mm in relazione al UTC

Sembra che dovrei essere in grado di farlo tramite strftime(), ma non sembra essere coerente

Unix:

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

di Windows:

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

Mentre sembra che Unix mi sta dando quello che voglio (o almeno qualcosa di simile), Windows non è. Sono abbastanza sicuro di poterlo fare con Date::Time o simili, ma mi piacerebbe davvero non avere alcuna dipendenza che non posso garantire a un utente a causa della nostra ampia base di installazione.

Mi manca qualcosa di ovvio qui? Grazie in anticipo.

risposta

14

Time::Local dovrebbe fare il trucco

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

'Time :: Local' è un modulo principale in tutte le distribuzioni di Perl 5. – mob

+0

Questa è un'ottima soluzione; gli ha dato solo un test rudimentale, ma sembra funzionare proprio come dovrebbe. Grazie. – Morinar

-1

Un modo portatile è quello di confrontare l'output di 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; 

Qualcuno sottolineando che questo è già implementato in un modulo da qualche parte in 5, 4, 3, ...

+0

si può spiegare il calcolo in se statment - il motivo per cui moltiplicare l'anno per il numero di giorni in un anno bisestile? perché mese * 31? Perché aggiungere il giorno? Grazie. –

+0

@Kevin Friedman - è un test per vedere se '@a [5,4,3]' e '@b [5,4,3]' rappresentano lo stesso giorno. Combino anno, mese e giorno in un unico numero in modo da poter ottenere con un confronto anziché tre. Potresti usare numeri più grandi di 366 e 31 e otterrai comunque il risultato giusto. – mob

+0

Dovresti usare i campi di bit invece della moltiplicazione se vuoi essere veloce: '($ a [5] << 13) | ($ a [4] << 5) | $ a [3]'. Inoltre, l'operatore '<=>' che potrebbe essere usato per sostituire l'istruzione if. – dolmen

0

" Mi piacerebbe davvero non avere alcuna dipendenza che non posso garantire un utente a causa della nostra ampia base di installazione "

Come includere una copia personalizzata di Date :: Tempo (lo chiameremo My :: Date :: Time) nella tua installazione? Ad esempio,

use lib 'my-module/dependencies/'; 

use My::Date::Time; 
0

È possibile calcolare la differenza tra localtime($t) e gmtime($t). Qui è la mia versione ispirata 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); 
} 
Problemi correlati