jueves, 3 de marzo de 2022

LAMBDA: conversor fechas universal

Una problemática habitual al trabajar con datos descargados de documentos wen, pdf, txt, etc... es el formato en que vienen las fechas... de formas muy dispares: DMA, DAM, MDA, MAD, ADM o AMD.
Esto obviamente genera un conflicto al trabajar dentro de Excel, ya que las fechas se intentan 'acoplar' al formato preestablecido en nuestro sistema.
Veamos la imagen siguiente donde comprobamos un caso problemático:
LAMBDA: conversor fechas universal

Comprobamos como las fechas originales en formato mm/dd/aaaa:
11/10/2021, 11/13/2021, 12/31/2021, 02/01/2022, 06/01/2022, 01/13/2022
han 'colapsado' y Excel ha tratado de leerlas como fechas cuando ha sido posible y adecuarlas a la configuración regional de Windows de nuestro equipo.. en mi caso: dd/mm/aaaa...
Y como hemos comprobado en la imagen algunas de ellas las ha leído como dd/mm en vez de mm/dd.. mientras que otras directamente las considera como texto... Irritante :(

Soluciones hay varias, pero he optado por comprobar la efictividad de LAMBDA para crear un conversor de fechas.
Así pues el objetivo es pasar de las fechas leídas por Excel a su antojo, previa indicación manual del formato original (esto es, como debemos entender la fecha original), para que nuestra fórmula la convierta a una fecha real pero de acuerdo a nuestra configuración.
LAMBDA: conversor fechas universal
Notemos en la imagem como nuestra fórmula trata correctamente tanto las fechas almacendas como texto como las incorrectamente leídas!!.

Nuestra fórmula en D2 (imaginarás que no es precisamente corta) es:
=LAMBDA(fecha;formatoActual;
LET(fechaTransf;SI(ESNUMERO(fecha);TEXTO(fecha;"dd/mm/aaaa hh:mm");fecha&" 00:00");
fechaLimpia;IZQUIERDA(fechaTransf;ENCONTRAR(" ";fechaTransf)-1);
Pos;K.ESIMO.MAYOR((EXTRAE(fechaLimpia;SECUENCIA(LARGO(fechaLimpia));1)="/")*(SECUENCIA(LARGO(fechaLimpia)));{1;2});
primer;EXTRAE(fechaLimpia;1;MIN(Pos)-1);segundo;EXTRAE(fechaLimpia;MIN(Pos)+1;MAX(Pos)-MIN(Pos)-1);tercer;EXTRAE(fechaLimpia;MAX(Pos)+1;LARGO(fechaLimpia));
PosFA;K.ESIMO.MAYOR((EXTRAE(formatoActual;SECUENCIA(LARGO(formatoActual));1)="/")*(SECUENCIA(LARGO(formatoActual)));{1;2});
primerFA;EXTRAE(formatoActual;1;1);segundoFA;EXTRAE(formatoActual;MIN(PosFA)+1;1);tercerFA;EXTRAE(formatoActual;MAX(PosFA)+1;1);
vDMA;ELEGIR({1\4;2\5;3\6};primerFA;segundoFA;tercerFA;primer;segundo;tercer);
FECHA(BUSCARV("a";vDMA;2;0);BUSCARV("m";vDMA;2;0);BUSCARV("d";vDMA;2;0))))(B2;$B$1)
LAMBDA: conversor fechas universal


Nuestra función LAMBDA (que he optado por no cargarla en el Administrador de nombres definidos) requiere dos argumentos: la fecha original y el formato de partida, y devuelve una fecha ajustada a nuestra configuración.

Me he apoyado en la función LET (ideal para estos casos) que facilita la definición de variables y/o pasos intermedios...

Los dos primeros pasos:
fechaTransf;SI(ESNUMERO(fecha);TEXTO(fecha;"dd/mm/aaaa hh:mm");fecha&" 00:00");
fechaLimpia;IZQUIERDA(fechaTransf;ENCONTRAR(" ";fechaTransf)-1);
Se encargan de homogeniezar la fecha de partida/original y tratarla en todo caso como una cadena de texto con la información que requerimos.

En los siguientes pasos:
Pos;K.ESIMO.MAYOR((EXTRAE(fechaLimpia;SECUENCIA(LARGO(fechaLimpia));1)="/")*(SECUENCIA(LARGO(fechaLimpia)));{1;2});
primer;EXTRAE(fechaLimpia;1;MIN(Pos)-1);segundo;EXTRAE(fechaLimpia;MIN(Pos)+1;MAX(Pos)-MIN(Pos)-1);tercer;EXTRAE(fechaLimpia;MAX(Pos)+1;LARGO(fechaLimpia));
Obtenemos un vector con las posiciones de los separadores de fecha '/' de la cadena de texto anterior (i.e. de la fecha tratada).
Y con ese vector de posiciones somos capaces con funciones básicas de texto de recuperar los caracteres numéricos que representarán el día, el mes y el año de acuerdo al argumento formato original que hayamos indicadao...

De forma similar a lo anterior conseguimos extraer la secuencia DD, MM, AAAA del formato original:
PosFA;K.ESIMO.MAYOR((EXTRAE(formatoActual;SECUENCIA(LARGO(formatoActual));1)="/")*(SECUENCIA(LARGO(formatoActual)));{1;2});
primerFA;EXTRAE(formatoActual;1;1);segundoFA;EXTRAE(formatoActual;MIN(PosFA)+1;1);tercerFA;EXTRAE(formatoActual;MAX(PosFA)+1;1);

Obviamente el vector o secuencia cambiará según nuestro argumento...

Con los vectores generados creamos una matriz 'virtual' que mostrará las equivalencias entre ambos vectores, el de los tres valores numéricos recuperados y lo que significan (día, mes o año):
vDMA;ELEGIR({1\4;2\5;3\6};primerFA;segundoFA;tercerFA;primer;segundo;tercer);

En el último paso aprovechamos la función FECHA para informar correctamente cuál es el año, cuál es el mes y cuál el día:
FECHA(BUSCARV("a";vDMA;2;0);BUSCARV("m";vDMA;2;0);BUSCARV("d";vDMA;2;0))))
lo que nos retornará una fecha (quizá sin formato) a la que podremos aplicar cualquiera de los formatos de fechas existentes o personalizados que deseemos... con la seguridad, con independencia del aspecto, que estaremos trabajando con la fecha adecuada.

En la imagen siguiente vemos algunos ejemplos de la conversión.. donde se muestra la matriz de equivalencias que se genera en el proceso de manera interna:
LAMBDA: conversor fechas universal

Comprueba que parece funcionar correctamente para todas las opciones/combinaciones de tipo de fechas existentes...

No sé si existirá alguna forma más rápida (yo no la pude encontrar)... pero efectiva es ;-)

No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.