The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

DateTimeX::Format::Excel

Microsofty conversion of Excel epochs

SYNOPSIS

        #!perl
        use DateTimeX::Format::Excel;

        # From an Excel date number

        my      $parser = DateTimeX::Format::Excel->new();
        print   $parser->parse_datetime( 25569 )->ymd ."\n";
        my      $datetime = $parser->parse_datetime( 37680 );
        print   $datetime->ymd() ."\n";
                $datetime = $parser->parse_datetime( 40123.625 );
        print   $datetime->iso8601() ."\n";

        # And back to an Excel number from a DateTime object

        use DateTime;
        my      $dt = DateTime->new( year => 1979, month => 7, day => 16 );
        my      $daynum = $parser->format_datetime( $dt );
        print   $daynum ."\n";

        my      $dt_with_time = DateTime->new( year => 2010, month => 7, day => 23
                                                                        , hour => 18, minute => 20 );
        my      $parser_date = $parser->format_datetime( $dt_with_time );
        print   $parser_date ."\n";
        
        ###########################
        # SYNOPSIS Screen Output
        # 01: 1970-01-01
        # 02: 2003-02-28
        # 03: 2009-11-06T15:00:00
        # 04: 29052
        # 05: 40382.763888889
        ###########################

DESCRIPTION

Excel uses a different system for its dates than most Unix programs. This module allows you to convert between the Excel raw format and and DateTime objects, which can then be further converted via any of the other DateTime::Format::* modules, or just with DateTime's methods. The DateTime::Format::Excel module states "we assume what Psion assumed for their Abacus / Sheet program". As a consequence the output does not follow exactly the output of Excel. Especially in the Windows range of 0-60. This module attempts to more faithfully follow actual Microsoft Excel with a few notable exceptions.

Excel has a few date quirks. First, it allows two different epochs. One for the Windows world and one for the Apple world. The windows epoch starts in 0-January-1900 and allows for 29-February-1900 (both non real dates). Most of the explanations for the difference between windows implementations and Apple implementations focus on the fact that there was no leap year in 1900 (the Gregorian vs Julian calendars) and the Apple version wanted to skip that issue. Both non real dates appear to have been a known issue in the original design of Lotus 1-2-3 that was carried over for compatibility. I like to think that the original Lotus spreadsheet designer thought that non-programmers wouldn't want to count from 0 so January first was represented as 1. This is never explicitly stated in any documentation I could find. In any case by the time the apple version rolled out more code centric heads were in charge and the apple version starts 1-January-1904. (counting from 0 while avoiding the leap year issue). In both cases the Windows and Apple version use integers from the epoch start to represent days and the decimal portion to represent a portion of a day. Both Windows and Apple Excel will attempt to convert recognized date strings to an Excel epoch for storage with the exception that any date prior to the epoch start will be stored as a string. (31-December-1899 and earlier for Windows and 31-December-1903 and earlier for Apple). Next, Excel does not allow for a time zone component of each number. Finally, in the Windows version when dealing with epochs that do not have a date component just a time component all values will fall between 0 and 1 which is a non real date (0-January-1900).

Caveat utilitor

This explanation is not intended to justify Microsofts decisions with Excel dates just replicate them as faithfully as possible. This module makes the assumption that you already know if your date is a string or a number in Excel and that you will handle string to DateTime conversions elsewhere. see DateTime::Format::Flexible. Any passed strings will die. (As a failure of a Type::Tiny test) This module also makes several unilateral decisions to deal with corner cases. When a 0 date is requested to be converted to DateTime it will use Carp to cluck that it received a bad date and then provide a DateTime object dated 1-January-1900 (Excel would provide 0-January-1900). If a value between 0 and 1 is requested to be converted to a DateTime object the module will NOT cluck and provide an object dated 1-January-1900 with the appropriate time component. All Apple times are provide as 1-January-1904. Any requested numerical conversion for Windows >= 60 and < 61 will cluck and provide a DateTime object dated 1-March-1900 (Excel would provide 29-Febrary-1900). All requests for conversion of negative numbers to DateTime objects will die . If a DateTime object is provided for conversion to the Excel value and it falls earlier than 1-January-1900 for Windows and 1-January-1904 for Apple then the DateTime object itself will be returned. If you accept the output of that method as a scalar, DateTime will stringify itself and give you a text equivalent date. For time zones you can pass a time zone with the excel number for conversion to the DateTime object. In reverse, the conversion to Excel Epoch uses the ->jd method for calculation so the time zone is stripped out. No clone or duration calculations are provided with this module. Finally this is a Moose based module and does not provide a functional interface. (Moose would allow it I just chose not to for design purposes).

Attributes

Data passed to new when creating an instance (parser). For modification of these attributes see the listed "Methods" of the instance.

system_type

    Definition: This attribute identifies whether the translation will be done for Windows Excel => 'win_excel' or Apple Excel => 'apple_excel'.

    Default win_excel (0-January-1900T00:00:00 = 0, range includes 29-February-1900)

    Range win_excel|apple_excel (1-January-1904T00:00:00 = 0)

Methods

These include methods to adjust attributes as well as providing methods to provide the conversion functionality of the module.

get_system_type

    Definition: This is the way to see whether the conversion is Windows or Apple based

    Accepts:Nothing

    Returns: win_excel|apple_excel

set_system_type( $system )

    Definition: This is the way to set the base epoch for the translator

    Accepts: win_excel|apple_excel (see the "DESCRIPTION" for details)

    Returns: Nothing

parse_datetime( @arg_list )

    Definition: This is how positive excel numbers are translated to DateTime objects

    Accepts: @arg_list - the order is important!

      0. $the_excel_number_for_translation - must be positive - no strings allowed

      1. 'time_zone' (the only useful option - other values here will ignore position 2)

      2. A recognizable time zone string or DateTime::TimeZone object

      example: ( 12345, time_zone => 'America/Los_Angeles' )

    Returns: A DateTime object set to match the passed values. A floating time zone is default.

format_datetime( $date_time )

    Definition: This is how DateTime objects can be translated to Excel epoch numbers

    Accepts: A DateTime object

    Returns: An excel epoch number or DateTime object if it is before the relevant epoch start.

THANKS

Dave Rolsky (DROLSKY) for kickstarting the DateTime project. Iain Truskett, Dave Rolsky, and Achim Bursian for maintaining DateTime::Format::Excel. I used it heavily till I wrote this. Peter (Stig) Edwards and Bobby Metz for contributing to DateTime::Format::Excel.

SUPPORT

TODO

    1. Nothing yet

AUTHOR

Jed Lund
jandrew@cpan.org

COPYRIGHT

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

The full text of the license can be found in the LICENSE file included with this module.

This software is copyrighted (c) 2014 by Jed Lund

DEPENDENCIES

SEE ALSO

Build from Source - (for example git)

    1. Download a compressed file with the code

    2. Extract the code from the compressed file

    3. Change (cd) into the extracted directory

(For Windows find what version of make was used to compile your perl)

        perl  -V:make

Then

        >perl Makefile.PL

        >make

        >make test

        >make install

        >make clean
        (use the windows make version as appropriate (dmake?))