Convertir de número a fecha cuando hay ceros

En algunas ocasiones nos encontramos que en una tabla los campos de fecha aparecen en numérico y llevan los valores no informados rellenados con un 0. O sea, hay un 0 en vez de un nulo. En este artículo quiero ofreceros algunas opciones para convertir rápidamente estos números en un formato fecha de SAS tradicional, de forma que podamos operar normalmente con ellos. Veremos ejemplos cuando el campo de origen es de texto, o es numérico.

En primer lugar, una tabla para los ejemplos que van abajo:

data EJEMPLO;
fecha_inicio = 20220101;
fecha_fin = 20220331;
output;
fecha_inicio = 20220101;
fecha_fin = 0;
run;

Formato número YYYYMMDD a fecha


data FECHAS1;
    set EJEMPLO;
    format fc_inicio ddmmyyn8.;
    if fecha_inicio = 0 then fc_inicio = .;
    else fc_inicio = mdy(mod(floor(fecha_inicio/100),100),mod(fecha_inicio,100),floor(fecha_inicio/10000));
run;

Formato número DDMMYYYY a fecha


data FECHAS2;
    set EJEMPLO;
    format fc_fin ddmmyys10.;
    if fecha_fin = 0 then fc_fin = .;
    else fc_fin = mdy(mod(floor(fecha_fin/10000),100),floor(fecha_fin/1000000),mod(fecha_fin,10000));
run;

Convertir mes YYYYMM a fecha

A veces tienes un dato de fecha expresado como mes. El problema para crear una fecha a partir de él es que no conocemos el día, así que hay que asumir que nos valdría o el primer o el último día del mes. La forma de convertirlo es así:


data FECHAS3;
    mes = 202208;
    format fc_mes_1 fc_mes_2 ddmmyys10.;
    /* primer día del mes */
    fc_mes_1 = mdy(mod(mes,100),1,floor(mes/100));
    /* último día del mes */
    fc_mes_2 = intnx('month',mdy(mod(mes,100),1,floor(mes/100)),0,'e');
run;

Para saber algo más de los tipos de formato de fecha que puedes utilizar visita este link.

SAS: Convertir de texto a fecha

Convertir de un texto a una fecha es una pregunta habitual para nuevos programadores en SAS, hay varios enfoques válidos para hacerlo:
La mejor solución al problema es aplicar la función input() sobre la cadena de entrada para cambiarle el informat al nuevo campo (fecha) e inmediatamente después aplicar el formato con put(). Incluyo dos ejemplos distintos de formato de entrada y de salida:

data SALIDA2;
    cadena1 = "2021/07/15";
    fecha2 = put(input(cadena,yymmdd10.),date9.);
    cadena2 = "20220115";
    fecha2 = input(put(cadena,z8.),yymmdd8.);
run;

Otra solución es tratar la cadena de texto obteniendo cada uno de los tres componentes de la fecha: día, mes, año y pasándolos como parámetro a una función mdy() para formar la fecha.

data SALIDA;
    cadena = "2021/07/15";
    dia = input(put(substr(cadena,9,2),$2.),8.);
    mes = input(put(substr(cadena,6,2),$2.),8.);
    anyo = input(put(substr(cadena,1,4),$4.),8.);
    fecha = put(mdy(mes,dia,anyo),date9.);
run;

Este enfoque es engorroso y largo pero da total libertad al programador: Por ejemplo, en caso de que la entrada no sea exactamente una fecha, sino un dato como «202107» pero sin embargo quisiéramos conseguir una salida que fuera el primer día del mes.

data SALIDA;
    cadena = "202107";
    mes = input(put(substr(cadena,5,2),$2.),8.);
    anyo = input(put(substr(cadena,1,4),$4.),8.);
    fecha = put(mdy(mes,1,anyo),date9.);
run;

Trucos SAS: Añadir ceros por la izquierda

Estos son unos pequeños trucos para conseguir añadir tantos ceros por la izquierda como necesitemos para conseguir un tamaño dado para una cadena. Vamos a imaginar, para los ejemplos que vamos a poner, que necesitamos conseguir que nuestro valor tenga siempre 10 caracteres y que en caso de necesitarlo le añadiremos tantos ceros por la izquierda como sea necesario.
Lo primero, no es lo mismo si partimos de un número o de una cadena de texto. Disponemos de un método para cada uno de esos casos. En todo caso, la salida del proceso tiene que ser siempre una cadena de texto.

Añadir ceros por la izquierda a un número

Creamos una tabla NUMEROS con unos cuantos números de ejemplo de distintas longitudes. Deseamos crear una cadena de texto que tenga 10 posiciones y que, en caso de necesitarlo, se complete con tantos ceros por la izquierda como haga falta.

data NUMEROS;
    format num best12.;
    informat num best12.;
    input num;
    datalines;
    646543589
    9684634311
    654634
    6354
    1
run;

data NUM_FORMAT;
    set NUMEROS;
    format cadena $10.;
    cadena = put(num,z10.);
run;

Lo que hemos hecho para resolverlo es un casting del campo original. Con put() le hemos aplicado un formato z10., que es el que se encarga de añadirle ceros por la izquierda. La salida de esto es una cadena de texto, ya que si almacenamos un número, los ceros por la izquierda se perderán.

Añadir ceros por la izquierda a una cadena de texto

En caso de que partamos de una cadena de texto hay varias soluciones posibles, si bien, alguna de ellos no es válida si tenemos caracteres alfanuméricos en la cadena origen. Incluyo algunas en el siguiente código incluyéndolas como distintos campo de la tabla de salida:

data CADENAS;
    format char $10.;
    informat char $10.;
    input char;
    datalines;
    615546241
    A165432113
    135485
    A
run;

data CHAR_FORMAT;
    set CADENAS;
    format cadena1 cadena2 $10.;
    cadena1 = compress(repeat('0',9 - length(char))||char);
    cadena2 = put(input(char,best12.),z10.);
run;

La primera solución utiliza la función repeat() que incluye tantos caracteres, ‘0’ en este caso, como se le indique. Aquí se da una particularidad que no es común en SAS: si se indica 2 se añadirán 3 ceros, por lo que hay que restar 1 a la cantidad de caracteres que queremos añadir. Por ello, el segundo parámetro de repeat() está calculado como 9 (en vez de 10) menos la longitud original de la cadena. Concatenando la salida del repeat() a la cadena original tendremos lo que estamos buscando.
Otra opción es una solución menos general porque solo es válida si la cadena de entrada está formada solo por números. Esto es porque lo que haremos será reformatear la cadena de texto primero como número (formato best12.) para luego convertirla de nuevo en texto con el formato z10. que es el que vimos que se encarga de añadir ceros por la izquierda a números. Tenemos que usar una combinación de put() e input() ya que cada uno de ellos acepta números o cadenas de texto respectivamente.

Salida del código anterior

Formatos de fecha en SAS

Existen infinidad de formatos de fecha o fecha-hora en SAS, literalmente cientos, en todos los idiomas y en todos los tipos de calendarios. Creo que conocer lo que SAS nos puede ofrecer en cuanto a estos formatos nos puede ayudar mucho. Y además, si esto no es suficiente para ti, aún te puedes crear un formato personalizado.

Vamos a hacer un repaso de los formatos de fecha que me parecen más interesantes. No creo que nadie utilice todos, pero desde luego aquí hay para todas las preferencias. Os los ofrezco clasificados por el uso más natural que me parece que tiene cada formato. Incluyo también algunos formatos de fecha en español.

Formato Resultado Uso
Partes de la fecha
DAY. 19 Día del mes.
WEEKDAY. 1 Día de la semana (1=domingo).
DOWNAME. Sunday Nombre del día de la semana en inglés.
ESPDFDWN. domingo Nombre del día de la semana en español.
MONTH. 4 Número del mes.
MONNAME. April Nombre del mes en inglés.
ESPDFMN. abril Nombre del mes en español.
QTR. 2 Número del trimestre.
YEAR. 2020 Año
Fechas solo con números.
DDMMYY10. 19/04/2020 Compatible con Excel.
DDMMYYB10. 19 04 2020
DDMMYYC10. 19:04:2020
DDMMYYD10. 19-04-2020 Compatible con Excel.
DDMMYYP10. 19.04.2020
YYMMDDS10. 2020/04/19
YYMMDDB10. 2020 04 19
YYMMDDC10. 2020:04:19
YYMMDDD10. 2020-04-19 Compatible con Excel.
YYMMDDP10. 2020.04.19
Fechas con el nombre del mes.
DATE. 19apr20
DATE9. 19apr2020 Formato habitual de trabajo.
ESPDFDE. 20abr2020 Igual al anterior, en español.
Para fechar nombres de fichero o tabla
DDMMYYN10. 19042020 Para fechar (orden invertido).
YYMMDDN10. 20200419 Para fechar ficheros.
YYMMN6. 202004 Para fechar ficheros mensuales.
Fechas para informes
YYWEEKW7. 2020W04 Informes semanales.
YYMMN6. 202004 Informes mensuales.
YYMMS. 2020/04 Informes mensuales.
MMYYS. 04/2020 Informes mensuales.
YYMON. 2020APR Informes mensuales.
MONYY. APR20 Informes mensuales.
YYQ6. 2020Q2 Informes trimestrales
YYS6. 2020S1 Informes semestrales.
Fechas para texto o documentos.
WORDDATE. April 19, 2020 Fecha en texto en inglés.
WORDDATX. 19 April 2020
ESPDFWDX. 30 de enero de 2011 Como los anteriores pero en formato español.
WEEKDATE. Sunday, April 19, 2020 Fecha en texto con día de la semana en inglés.
ESPDFWKX. domingo, 30 de enero de 2011 Como el anterior pero en formato español.

Hay muchísimos más formatos de fecha que se pueden encontrar en la documentación de SAS.