thiagu
thiagu

Reputation: 71

Laravel excel import, date column in excel cell returns as floating value. How to solve this?

By using Maatwebsite/Laravel-Excel to import excel sheet, here I faced an issue date time column of the excel sheet returns float value. How to solve this? Example : Consider Cell value "08-04-2016 13:08:29" and returns as "42104.487060185" when import.

Upvotes: 7

Views: 8484

Answers (4)

Leonardo Jauregui
Leonardo Jauregui

Reputation: 316

That "floating number" is an excel timestamp, that way it stores the date and time data internally.

for example:

123213.0: it's just a date
213233.1233: is a date and time
0.1233: it's one hour

To solve this you must convert that floating point number to a date.

if your need involves resolving datetime fields dynamically, I have written a method that is responsible for automatically detecting if the value is a datetime dynamically (regardless of whether or not you know if there will be a datetime in that column) or I have tried various data types and it works fine

   /**
 * @param Cell $cell
 * @param $value
 * 
 * @return boolean;
 */
public function bindValue(Cell $cell, $value)
{
    $formatedCellValue = $this->formatDateTimeCell($value, $datetime_output_format = "d-m-Y H:i:s", $date_output_format = "d-m-Y", $time_output_format = "H:i:s" );
    if($formatedCellValue != false){
        $cell->setValueExplicit($formatedCellValue, DataType::TYPE_STRING);
        return true;
    }

    // else return default behavior
    return parent::bindValue($cell, $value);
}


/**
 * 
 * Convert excel-timestamp to Php-timestamp and again to excel-timestamp to compare both compare
 * By Leonardo J. Jauregui ( @Nanod10 | siskit dot com )
 * 
 * @param $value (cell value)
 * @param String $datetime_output_format
 * @param String $date_output_format
 * @param String $time_output_format
 * 
 * @return $formatedCellValue
 */
private function formatDateTimeCell( $value, $datetime_output_format = "Y-m-d H:i:s", $date_output_format = "Y-m-d", $time_output_format = "H:i:s" )
{

    // is only time flag
    $is_only_time = false;
    
    // Divide Excel-timestamp to know if is Only Date, Only Time or both of them
    $excel_datetime_exploded = explode(".", $value);

    // if has dot, maybe date has time or is only time
    if(strstr($value,".")){
        // Excel-timestamp to Php-DateTimeObject
        $dateTimeObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
        // if Excel-timestamp > 0 then has Date and Time 
        if(intval($excel_datetime_exploded[0]) > 0){
            // Date and Time
            $output_format = $datetime_output_format;
            $is_only_time = false;
        }else{
            // Only time
            $output_format = $time_output_format;
            $is_only_time = true;
        }
    }else{
        // Only Date
        // Excel-timestamp to Php-DateTimeObject
        $dateTimeObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
        $output_format = $date_output_format;
        $is_only_time = false;
    }
        
    // Php-DateTimeObject to Php-timestamp
    $phpTimestamp = $dateTimeObject->getTimestamp();

    // Php-timestamp to Excel-timestamp
    $excelTimestamp = \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel( $phpTimestamp );
        
    // if is only Time
    if($is_only_time){
        // 01-01-1970 = 25569
        // Substract to match PhpToExcel conversion
        $excelTimestamp = $excelTimestamp - 25569;
    }

    /* 
    // uncoment to debug manualy and see if working
    $debug_arr = [
            "value"=>$value,
            "value_float"=>floatval($value),
            "dateTimeObject"=>$dateTimeObject,
            "phpTimestamp"=>$phpTimestamp,
            "excelTimestamp"=>$excelTimestamp,
            "default_date_format"=>$dateTimeObject->format('Y-m-d H:i:s'),
            "custom_date_format"=>$dateTimeObject->format($output_format)
        ];
        
    if($cell->getColumn()=="Q"){
        if($cell->getRow()=="2"){
            if(floatval($value)===$excelTimestamp){
                dd($debug_arr);
            }
        }
    }

    */
    
    // if the values match
    if( floatval($value) === $excelTimestamp ){
        // is a fucking date! ;)
        $formatedCellValue = $dateTimeObject->format($output_format);
        return $formatedCellValue;
    }else{
        // return normal value
        return false;
    }
    
}

Upvotes: 0

SlyDave
SlyDave

Reputation: 1265

Known bug, see https://github.com/Maatwebsite/Laravel-Excel/issues/404 for details.

But basically, when using chunk() to read the cells in, it fails to convert Excel's datetime format from a float into a Carbon date object.

There is currently no fix, You can work around this by calling config before the call to load:

config(['excel.import.dates.columns' => [
        'deleted_at',
        'updated_at'
    ]]);

Excel::filter('chunk')->load($file)->chunk(100 function($rows) { ... });

If you're not using the chunk filter, then see http://www.maatwebsite.nl/laravel-excel/docs/import#dates on how to explicty set formats on cells (setDateColumns()), but those should be converting automatically unless you change the defaults.

Upvotes: 2

Nicolas Scordamaglia
Nicolas Scordamaglia

Reputation: 401

This only happend when use chunk. This issue could be solved by:

$UNIX_DATE = ($row->DOB - 25569) * 86400;
$date_column = gmdate("d-m-Y H:i:s", $UNIX_DATE);

Upvotes: 8

Prashant Prajapati
Prashant Prajapati

Reputation: 1005

Change the format your import file to .csv and format the date column to your required date format (dd-mm-yyyy)

Upvotes: 0

Related Questions