En el desarrollo de aplicaciones para empresas es bastante común tener que trabajar con Excel (Ya sea importando planillas a bases de datos o bien lo inverso).
En general, la libería PHPSpreadSheet funciona muy bien para estos casos (Algo más de información aquí), sin embargo, el tratamiento de las fechas no es tan sencillo como esperamos.
Cómo Excel maneja las fechas
El problema radica en que el valor almacenado en la celda no es en realidad una fecha… si no la cantidad de días transcurridos desde el primero de Enero de 1900 (Si tenés curiosidad abrí el Excel y probá la fórmula «=DATEVALUE(‘1900-01-01’)»).
Esto provoca que, al hacer algo como:
$value = $worksheet->getCell('A1')->getValue();
Obtengamos un número entero (Generalmente grande) en lugar de una fecha
Cómo leer datos de tipo fecha con PhpSpreadsheet
Para resolver este pequeño inconveniente PhpSpreadsheet dispone de un método especial:
$date = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
Este método retorna un objeto de tipo DateTime.
A partir de este objeto podemos usar todas las operaciones que queramos.
Cómo escribir datos de tipo fecha con PhpSpreadsheet
Y ¿qué pasa si tenemos que generar valores fecha para exportar a Excel? (Básicamente lo inverso de lo anterior).
Para eso también tenemos un método especial:
\PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel( $date )
Este método tomará un objeto DateTime de php y lo convertirá a su correspondiente valor numérico para ser guardado sin problemas en una planilla de cálculo Excel.
Cuidado: que lo guarde bien no quiere decir que se vea bien al abrir el Excel.
Si lo dejas así verás algo como:
Que si bien técnicamente es correcto, muy probablemente no sea lo que esperarías.
No te preocupes, la solución es bien simple. Todo lo que tienes que hacer es establecer un formato para la celda que contiene la fecha.
Sería algo así como:
$worksheet->getStyle('A1') ->getNumberFormat() ->setFormatCode( \PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_DATE_YYYYMMDDSLASH );
Con esto tendrás una salida bien formateada y no tendrás problemas de incompatibilidad con configuraciones regionales.
- Cómo agregar una página de error 500 en un proyecto PHP - 31/10/2024
- ¿Cuántos contenedoresnecesita tu php? - 28/10/2024
- Cuál es el mejor framework PHP para hacer APIs REST - 25/10/2024
Buenas tardes, estoy tratando de formatear una hora que tengo en una celda en excel, como podría resolver esto para que cuando lea el excel en php me traiga la hora y no numeros como por ejemplo (0.33333333333333).
Gracias de antemano.
Puedes probar algo como:
$date = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
Y luego usar $date->format(‘H:i:s’) para obtener un string con la hora, minutos y segundos.
Buenos días.
Me podrías decir si existe un comando que me retorne cuántos años, meses y días completos hay en un rango de fecha.
Por ejemplo
entrada 1: 10/05/2022
entrada 2: 25/07/2042
salida: «La duración es 10 años, 2 meses y 15 días»
De antemano, te agradezco mucho.
Quedo atenta a tu respuesta
Hola Jessica:
Gracias por tu pregunta. Se pueden usar diferentes librerías, una muy utilizada es Carbon. Personalmente prefiero las propias de PHP que son sumamente funcionales.
Algo que puedes probar:
<?php
$entrada1 = DateTimeImmutable::createFromFormat("d/m/Y", "10/05/2022");
$entrada2 = DateTimeImmutable::createFromFormat("d/m/Y", "25/07/2042");
$diff = $entrada2->diff($entrada1);
echo $diff->format("La duración es %Y años, %m meses y %d días");
Exitos!
La duda es la siguiente, tengo que leer secuencialmente los renglones de un archivo de Excel e insertarlos en una base de datos. Donde la fecha no esta necesariamente en una columna en particular y puede cambiar de columna, al momento de leer una fecha, en efecto me devuelve su valor como un entero, pero requiero guardarla como fecha, la conversión para de entero regresarla a fecha me queda clara, pero… ¿existe alguna manera de identificar que el tipo de dato almacenado en una celda es de tipo fecha? y así poderle aplicar la conversión, pues no todo valor numerico que vaya leyendo en mi proceso, se trata necesariamente de una fecha, gracias de antemano.
Hola Sergio!
Gracias por tu pregunta :). Es un poco raro el método pero sí, es posible.
Las celdas pueden identificarse por su tipo usando el método
getDataType()
, sin embargo, éste método no distingue fechas de otros números.Lo que debes hacer es utilizar el método estático
\PhpOffice\PhpSpreadsheet\Shared\Date::isDateTime()
pasando como parámetro la celda en cuestión.Aquí te dejo un ejemplo que te dirá cuáles de las celdas de un archivo son fechas:
<?php
require_once 'vendor/autoload.php';
$reader = PhpOffice\PhpSpreadsheet\IOFactory::createReaderForFile($argv[1]);
$s = $reader->load($argv[1]);
$ri = $s->getActiveSheet()->getRowIterator();
foreach ($ri as $row) {
$ci = $row->getCellIterator();
}