Author image Flávio Soibelmann Glock
and 1 contributors


Date::Tie - ISO dates made easy


    use Date::Tie;

    tie my %date, 'Date::Tie', year => 2001, month => 11, day => 9;
    $date{month} += 12;    # 2003-11-09

    # you can also use OO syntax
    my $date = Date::Tie->new( year => 2001, month => 11, day => 9 );
    $date->{month} += 12;  # 2003-11-09

    $date{weekday} = 0;    # sunday at the start of this week
    $date{weekday} = 7;    # sunday at the end of this week
    $date{weekday} = 14;   # sunday next week 

    $date{tz} = '-0300';   # change timezone
    $date{tzhour}++;       # increment timezone

    # "next month's last day"
    $date{day} = 0;        # this is actually a "-1" since days start in "1"

    # copy a date with timezone
    tie my %newdate, 'Date::Tie', tz => $date{tz}, epoch => $date{epoch};
    tie my %newdate, 'Date::Tie', %date;


Date::Tie is an attempt to simplify date operations syntax.

It works with calendar dates (year-month-day), ordinal dates (year-day), week dates (year-week-day), times (hour:minute:second), decimal fractions (decimal hours, decimal minutes and decimal seconds), and time-zones.

Whenever a Date::Tie hash key receives a new value, it will change the other keys following the ISO date rules. For example:

     print $a{hour}, ":", $a{minute};     #  '00:59'
     print $a{hour}, ":", $a{minute};     #  '01:00'


The default value of a new hash is the current value of gmtime(), with timezone +0000 and with fractional seconds set to zero.


Date::Tie manages a hash containing the keys:

year, month, day, hour, minute, second, yearday, week, weekday, weekyear, epoch, utc_epoch, tz, tzhour, tzminute, frac_hour, frac_minute, frac_second, frac_epoch, frac.

All keys can be read and written to.

year, month, day or monthday, hour, minute, second

These keys are just what they say.

You can use monthday instead of day if you want to make it clear it is not a yearday (ordinal calendar) or a weekday (week calendar).

yearday, week, weekday, weekyear

yearday is the day number in the year.

weekday is the day number in the week. weekday 1 is monday.

week is the week number in the year.

weekyear is the year number, when referring to a week of a year. It is often not equal to year. Changing weekyear will leave you with the same week and weekday, while changing year will leave you with the same month and monthday.


epoch is an internal notation and is not a part of the ISO8601 standard.

This value is system-dependent, and it might overflow for dates outside the years 1970-2038.

epoch is the local epoch. That is, time 20020101T000000+0300 is the same epoch as 20020101T000000+0600.


The system epoch in UTC time, that is, in timezone +0000.

See also the epoch key.

tz, tzhour, tzminute

tz is the timezone as hundreds, like in -0030. It is not always the same as the expression $date{tzhour} . $date{tzminute}, which in this case would be -00-30.

Changing timezone (any of tz, tzhour, or tzminute) changes epoch.

frac_hour, frac_minute, frac_second, frac_epoch

These keys are used for fractional decimal notation:

    $d{hour}   = 13;
    $d{minute} = 30;                 # 0.5 hour
    $d{second} = 00;       
    print $d{frac_hour};             # '13.5'

    $d{frac_minute} = 17.3;
    print "$d{minute}:$d{second}";   # '17:18'
    $d{frac_minute} -= 0.2;
    print "$d{minute}:$d{second}";   # '17:06'

    $d{epoch} = 1234567;
    $d{frac}  = 0.7654321;
    print $d{frac_epoch};            # '1234567.7654321'

Fractional seconds. A value bigger or equal to 0 and less than 1 second.

    $d{frac} =   0.5;
    print $d{frac};              # '.5'

    $d{frac} =   0;
    print $d{frac};              # '.0'

Setting frac does not change second or epoch, unless it overflows:

    $d{second} = 6;
    print $d{second};            # '06'
    $d{frac} =   1.5;
    print $d{second};            # '07'    - frac overflow
    print $d{frac};              # '.5'

To obtain the fractional second or epoch:

    print "$d{second}$d{frac}";  # '07.5'  - concatenation
    print $d{second} + $d{frac}; # '7.5'   - addition
    print $d{epoch} + $d{frac};  # '45673455.5'   - fractional epoch

See also: frac_epoch and frac_second.


Day of year starts with 001.

Day of week starts with 1 and is a monday.

Week starts with 01 and is the first week of the year that has a thursday. Week 01 often begins in the previous year.


Since Date::Tie is based on gmtime() and timegm(), it is expected to work only on years between 1970 and 2038 (this is system-dependent).

Reading time zone -0030 with $date{tzhour} . $date{tzminute} gives -00-30. Use tz to get -0030.

The order of setting hash elements is important, since changing the timezone will change the hour.

These are some ways to make a copy of %d:

    # copy all fields
    #     hash %d MUST be tied do Date::Tie, if you are using timezones
    tie my %b, 'Date::Tie', %d;

    # set timezone, then epoch, ignoring fractional seconds
    tie my %b, 'Date::Tie', tz => $d{tz}, epoch => $d{epoch};

    # set timezone, then epoch and fractional seconds
    tie my %b, 'Date::Tie', tz => $d{tz}, epoch => $d{epoch}, frac => $d{frac};

    # set timezone, then fractional epoch
    tie my %b, 'Date::Tie', tz => $d{tz}, frac_epoch => $d{frac_epoch};

In OO style you can use new to make a copy:

    # make a copy of object
    my $b = $d->new;

    # make a copy of object, then set the copy to next month
    ($b = $d->new)->{month}++;

    # make a copy of object, then set the copy to month 3
    $b = $d->new(month => 3);

If you change month, then day will be adjusted to fit that month:

    $date = (month=>10, day=>31);
    $date{month}++;     #  month=>11, day=>30

If you need to know whether a hash is tied to Date::Tie use perl function tied()


DateTime and

Date::Calc, Date::Manip, Class::Date, and many other good date and time modules!

Date::Tie depends on Tie::Hash, Time::Local and POSIX.

dmoz section on ISO8601 at

Markus Kuhn wrote a summary of ISO8601 International Standard Date and Time Notation, that can be found at


Flávio Soibelmann Glock (


Original idea based on a mail by dLux.

Eduardo M. Cavalcanti, Henrique Pantarotto and Jean contributed bugfixes.

Dan Wright created the utc_epoch key.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 656:

Non-ASCII character seen before =encoding in 'Flávio'. Assuming ISO8859-1