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

后端 未结 4 1920
陌清茗
陌清茗 2021-01-20 17:09

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 : Conside

相关标签:
4条回答
  • 2021-01-20 17:43

    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;
        }
        
    }
    
    0 讨论(0)
  • 2021-01-20 17:59

    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.

    0 讨论(0)
  • 2021-01-20 18:05

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

    0 讨论(0)
  • 2021-01-20 18:08

    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);
    
    0 讨论(0)
提交回复
热议问题