NAME
    Time::Local::TZ - time converter functions with localtime-based
    interface

SYNOPSIS
      use Time::Local::TZ qw/:const :func/;

      # get localtime-like result for given timezone and unixtime
      ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = tz_localtime("Europe/Moscow" => $epoch);
      ($asctime) = tz_localtime("Europe/Moscow" => 0);      # Thu Jan  1 03:00:00 1970

      # get unixtime for given timezone and localtime data
      $epoch = tz_timelocal("Europe/Moscow" => $sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
      $epoch = tz_timelocal("Europe/Moscow" => $sec,$min,$hour,$mday,$mon,$year);    # the same

      # truncate unixtime to the beginning of minute/hour/day/month/year (of course, in given timezone)
      $epoch2 = tz_truncate("Europe/Moscow", $epoch, TM_HOUR());

      # get offset (in seconds) between given timezone and UTC (for the given moment)
      $tz_offset_seconds = tz_offset("Europe/Moscow" => $epoch);
      $tz_offset_seconds = tz_offset("Europe/Moscow");   

      # convert localtime data from one timezone to another
      @localtime_berlin = tz_localtime("Europe/Berlin", tz_timelocal("Europe/Moscow", @localtime_moscow));

      # constants to navigate @localtime (and to use with tz_offset function)
      @localtime = tz_localtime("UTC", $epoch);
      $date_str = sprintf "%04d-%02d-%02d", @localtime[TM_YEAR()+1900, TM_MON()+1, TM_MDAY()];   # 1970-01-01
      $time_str = sprintf "%02d:%02d:%02d", @localtime[TM_HOUR(),      TM_MIN(),   TM_SEC() ];   # 13:25:59
      $weekday = $localtime[ TM_WDAY() ];
      $yearday = $localtime[ TM_YDAY() ];
      $isdst   = $localtime[ TM_ISDST() ];

DESCRIPTION
    This module provides a set of functions to convert time between
    timezones and do some other timezone-dependant operations. Most
    functions work with localtime-like arrays, so they can be easily
    integrated with other modules supporting this format. Module is written
    in XS, so it is fast enough.

FUNCTIONS
    @localtime = tz_localtime($timezone_name, $epoch)
        Works similar to build-in "localtime" function, but works with
        timezone you provide, instead of system timezone. Both arguments are
        mandatory.

        In scalar context, "tz_localtime" returns the asctime(3) value
        (without trailing "\n", like "localtime"):

          $date_string = tz_localtime("Europe/Moscow" => time());  # e.g., "Thu Apr 27 15:35:34 2017"

        In list context, converts time provided to a 9-element list with the
        time analyzed for the given timezone:

          #  0    1    2     3     4    5     6     7     8
          ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = tz_localtime("Europe/Moscow" => time);

          @localtime = tz_localtime("Europe/Moscow" => time);
          $date_string = POSIX::strftime("%d %B %Y, %H:%M", @localtime);

        Values $mday, $year, $wday, $yday have special format, which can
        confuse beginners. See "localtime" function for details.

    $epoch = tz_timelocal($timezone_name, @localtime)
        Works similar to "timelocal" function from "Time::Local" module, but
        works with timezone you provide, instead of system timezone. Returns
        unixtime value for the "localtime" data and timezone provided. All
        arguments are mandatory, except $wday, $yday, $isdst.

          $epoch = tz_timelocal("Europe/Moscow" => $sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
          $epoch = tz_timelocal("Europe/Moscow" => $sec,$min,$hour,$mday,$mon,$year);

          $data_string = "2017-04-27 15:35:34";
          @localtime = POSIX::strptime($data_string, "%Y-%m-%d %H:%M:%S");
          $epoch = tz_timelocal("Europe/Moscow" => @localtime);

    $epoch = tz_truncate($timezone, $epoch, $unit)
        This function calculates "tz_localtime" for the timezone and
        unixtime provided, resets fields with index smaller than $unit and
        calculates unixtime back. This can be useful to get unixtime for
        first second of the interval unit (year/month/day/hour/minute) which
        $epoch belongs to. All arguments are mandatory. It is recommended to
        use "TM_*" constants from this module to specify $unit.

          $data_string = "1970-03-08 05:25:45";
          @localtime = POSIX::strptime($data_string, "%Y-%m-%d %H:%M:%S");
          $epoch = tz_timelocal("Europe/Moscow" => @localtime);              # 5711145
  
          $epoch2 = tz_truncate("Europe/Moscow" => $epoch, TM_HOUR());       # 5709600
          print tz_localtime("Europe/Moscow" => $epoch2);                    # Sun Mar  8 05:00:00 1970
  
          $epoch2 = tz_truncate("Europe/Moscow" => $epoch, TM_YEAR());       # -10800
          print tz_localtime("Europe/Moscow" => $epoch2);                    # Thu Jan  1 00:00:00 1970
  
          # of course, in other timezones this alignment is wrong:
          print tz_localtime("Europe/Berlin" => $epoch2);                    # Wed Dec 31 22:00:00 1969

    $offset_seconds = tz_offset($timezone, $epoch)
        Calculates offset (in seconds) from UTC to provided timezone, actual
        for the given unixtime. Both arguments are mandatory.

          print tz_offset("Europe/Moscow", 1293829200); # 10800 (+3 hours for the date 2011-01-01)
          print tz_offset("Europe/Moscow", 1309464000); # 14400 (+4 hours for the date 2011-07-01)

  CONSTANTS
    TM_SEC, TM_MIN, TM_HOUR, TM_MDAY, TM_MON, TM_YEAR, TM_WDAY, TM_YDAY,
    TM_ISDST
        These constants can be useful to navigate on "localtime" and
        "tz_localtime" arrays:

            @localtime = tz_localtime("Europe/Moscow" => time);
            printf "Time is is %02d:%02d:%02d", @localtime[ TM_HOUR(), TM_MIN(), TM_SEC() ];

        It is recommended to use them with "tz_truncate" function:

          $epoch2 = tz_truncate("Europe/Moscow" => $epoch, TM_HOUR());       # 5709600

NOTES AND CAVEATS
    This module uses your system "tzdata" - set of rules for all the
    timezones around the world. These rules are refreshed regulary (up to
    several times per month), so you should update them too (if you want to
    work with timezones correctly). If you don't want to do this, take a
    look on "DateTime::TimeZone", which have its own timezones database
    inside. Anyway, you should update it on a regular basis too.

    This module works with process environment, so it is not thread-safe.

    This module works with mod_perl2 (at least in non-threaded mode).
    mod_perl2 has problem with %ENV. Unlike mod_perl1 and usual perl
    programs %ENV under mod_perl2 is untied from process environment. So,
    even if you change $ENV{TZ}, built-in functions (like "localtime") will
    know nothing about it, because real process environment is untouched.
    This module works with environment bypassing perl %ENV, so in mod_perl2
    prefork mode it works fine.

    If you have problems running this module tests, please refresh your
    "tzdata".

SEE ALSO
    To get more information about "localtime" format, see "localtime" in
    perlfunc and "timelocal" in Time::Local.

    If you are interested in useful functions to work with "localtime" data,
    see "strftime" in POSIX and POSIX::strptime.

    If you want to know more on alternative modules to convert time between
    timezones, see DateTime and DateTime::TimeZone.

AUTHOR
    Sergey Panteleev, <bambr@cpan.org>

COPYRIGHT AND LICENSE
    Copyright (C) 2017 by Sergey Panteleev

    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself, either Perl version 5.8.8 or, at
    your option, any later version of Perl 5 you may have available.

