#!/usr/bin/perl -w
#

use strict;
use POSIX   qw();
use Time::Local;

my $zulu;
my $local;
my $zone;

sub format_datetime {
    my $datetime    = shift;            # YYYYMMDDhh:mm:ss - Date::Manip compatible format
    my $timezone    = shift || 'GMT';   # expect GMT by default
    my $html_req    = shift || 0;       # output for HTML page? ' ' => '&nbsp;'
    my $result      = '';

    if ($datetime =~ /^(\d{4})(\d{2})(\d{2})(\d{2}):(\d{2}):(\d{2})$/) {
        my $year    = $1;
        my $month   = $2;
        my $day     = $3;
        my $hour    = $4;
        my $minute  = $5;
        my $second  = $6;

        $result = sprintf("%d-%02d-%02d %02d:%02d:%02d %s", $1, $2, $3, $4, $5, $6, $timezone);
        $result =~ s/ /&nbsp;/g if ($html_req);
    }

    return $result;
}

sub is_zulu {
    my $zulu    = shift;
    my $result  = 0;

    if ($zulu =~ /^(\d{14})Z$/) {
        $result = 1
    }

    return $result;
}

sub zulu_to_datetime {
    my $zulu    = shift;
    my $result  = '';

    if (is_zulu($zulu)) {
        $result = join(':', $zulu =~ /^(\d{10})(\d{2})(\d{2})/);
    }

    return $result;
}

sub zulu_to_local_datetime {
    my $zulu        = shift;
    my $time_zone   = shift || 'Europe/Prague';
    my $result      = '';
    my $time;
    my $year;
    my $month;
    my $day;
    my $hour;
    my $minute;
    my $second;

    if (is_zulu($zulu)) {
        ($year, $month, $day, $hour, $minute, $second)  = $zulu =~ /^(\d+)(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/;

        # fix offset
        $month--;
        $year   -= 1900;

        my $already = 0;
        my $original_time_zone;

        # save environment settings
        if (exists $ENV{TZ}) {
            $already            = 1;
            $original_time_zone = $ENV{TZ};
        }

        # do datetime conversion dependint to target timezone
        $ENV{TZ}    = 'Zulu';
        POSIX::tzset();
        $time       = timegm($second, $minute, $hour, $day, $month, $year);
        $ENV{TZ}    = $time_zone;
        POSIX::tzset();
        ($second, $minute, $hour, $day, $month, $year)   = POSIX::localtime($time);

        # fix offset
        $month++;
        $year   += 1900;

        # output formating
        $result = sprintf "%d%02d%02d%02d:%02d:%02d", $year, $month, $day, $hour, $minute, $second;

        # revert environment settings back
        if ($already) {
            $ENV{TZ}    = $original_time_zone;
        } else {
            delete $ENV{TZ};
        }
        POSIX::tzset();
    }

    return $result;
}


$zulu   = '20071213114702Z';
$local  = zulu_to_local_datetime($zulu);
$zone   = 'Europe/Prague';

# should be +1 hour
print "\n", "Winter (delta should be +1 h)", "\n";
print "ZULU : ", format_datetime(zulu_to_datetime($zulu), 'Zulu'), "\n";
print "LOCAL: ", format_datetime($local, $zone), "\n";

$zulu = '20070613114702Z';
$local = zulu_to_local_datetime($zulu, $zone);

# should be +2 hour
print "\n", "Summer (delta should be +2 h)", "\n";
print "ZULU : ", format_datetime(zulu_to_datetime($zulu), 'Zulu'), "\n";
print "LOCAL: ", format_datetime($local, $zone), "\n";

