En utilisant Maatwebsite/Laravel-Excel version 3.1 pour importer une feuille Excel, j'ai été confronté à un problème : la colonne date-heure de la feuille Excel renvoie un nombre inconnu. Comment résoudre ce problème ? Exemple : Considérons la valeur de la cellule "29/07/1989" qui renvoie "32178" lors de l'importation.
Réponses
Trop de publicités?Les chiffres proviennent d'Excel lui-même, les dates sont stockées dans Excel sous forme numérique. numériques. http://www.cpearson.com/excel/datetime.htm
Pour le framework Laravel 5.6 et le package maatwebsite/excel version 3.1, pour convertir la date des chiffres excel au format normal de date, cette fonction
PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateFromExcel)
peut être utilisé. Il accepte un entier (excel date) et retourne un objet DateTime objet.Vous trouverez de plus amples informations ici https://github.com/Maatwebsite/Laravel-Excel/issues/1832
De cette réponse : https://stackoverflow.com/a/55139981/9133724
Ce "nombre inconnu" est un timestamp excel, de cette façon il stocke les données de date et d'heure en interne.
par exemple :
123213.0: it's just a date
213233.1233: is a date and time
0.1233: it's one hour
Si vous pouvez mapper la cellule et que vous savez quelle colonne aura toujours une date / heure / date-heure, vous pouvez utiliser des cellules mappées ou les convertir manuellement, voir : https://stackoverflow.com/a/59049044
Sinon, si votre besoin implique la résolution dynamique des champs de type datetime, j'ai écrit une méthode qui se charge de détecter automatiquement si la valeur est une datetime de manière dynamique (que vous sachiez ou non s'il y aura une datetime dans cette colonne) ou j'ai essayé différents types de données et cela fonctionne bien.
/**
* @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;
}
}
Sur la base de Skyrem Brilliant
Grâce à la réponse brillante de @skyrem, j'ai résolu le problème de cette façon :
<?php
//...
class YourExcelImport implements OnEachRow, WithValidation, WithHeadingRow
{
// ...
/**
* Tweak the data slightly before sending it to the validator
* @param $data
* @param $index
* @return mixed
*/
public function prepareForValidation($data, $index)
{
//Fix that Excel's numeric date (counting in days since 1900-01-01)
$data['your_date_column'] = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($data['your_date_column'])->format('Y-m-d');
//...
}
/**
* List the validation rules
* @return array
*/
public function rules(): array
{
return [
'your_date_column'=>'required|date_format:Y-m-d',
//..
];
}
}
?>
Cela a fait l'affaire et la validation passe.