Truco SAS: Convertir fechas datetime de Unix a SAS

Como sabemos, los formatos de fechas en SAS y en otros sistemas operativos o bases de datos se interpretan y se almacenan como números que representan el número de días (o de segundos, en el caso de los datetime) transcurridos desde una fecha de origen. Las fechas anteriores a ella se almacenan como números negativos.

Lo que puede cambiar entre estos distintos sistemas es esa fecha origen a partir de la que se empieza a contar, de forma que una misma cifra puede representar fechas distintas dependiendo de qué sistema haya generado esa fecha. Esto da lugar a algunos problemas que debemos resolver cuando se realizan migraciones de datos de un sistema a otro. En nuestro caso, como programadores en SAS, debemos tener cuidado al importar fechas generadas con el timestamp de Unix y tener en cuenta que Unix no comienza a contar las fechas desde la misma fecha origen que SAS. Mientras SAS comienza a contar en ’01jan1960′; Unix comienza a contar en ’01jan1970′. Esos 10 años de diferencias hay que tenerlos en cuenta.

Por ello, si tenemos un datetime generado en Unix será necesario aplicar la siguiente corrección para que al convertir el número en fecha SAS éstas sean equivalentes:

fecha_SAS = fecha_Unix + 315619200;

Esa cantidad que sumamos es el número de segundos que representan esos 10 años. Existe otra forma de hacerlo, quizás un poco más elegante, que es utilizando la función dhms():

fecha_SAS = dhms('01jan1970'd, 0, 0, fecha_Unix);

La función dhms() construye un datetime a partir de una fecha y un número de horas, minutos y segundos. Con la instrucción anterior, se generará un datetime sumando el número de segundos expresados en la fecha_Unix a la fecha origen de Unix, que es el ’01jan1970′. Es una forma más elegante y además resulta más fácil recordar la fecha de origen de Unix, que el número tan grande de segundos que representan esa diferencia.
Si las fechas de Unix están representadas en milisegundos solo debemos utilizar una pequeña variante sobre lo anterior:

fecha_SAS = dhms('01jan1970'd, 0, 0, fecha_Unix/1000);

SAS: Obtener el listado de los últimos ficheros por fecha en Unix

¿Cómo podemos obtener y cargar los últimos archivos de un cierto periodo? Seguro que podemos encontrarnos este problema en algunas de sus variantes y podemos resolver todas ellas basándonos de la siguiente forma. Voy a basar este artículo en el supuesto de una máquina SAS corriendo sobre un sistema operativo Unix, que creo que es lo más común, aunque tiene también la misma solución bajo Windows, con algunas diferencias.

Lo primero que vamos a hacer es obtener el listado de ficheros csv que nos interesa cargar, utilizando la línea de comandos del sistema operativo del servidor SAS, y vamos a incluir ese listado en un fichero lista_ficheros.txt. Utilizaremos el comando x de SAS que envía las instrucciones al sistema operativo para que este los interprete.

x"cd /[ruta_ficheros]";
x"ls *.csv > lista_ficheros.txt";

En el paso anterior el comando «cd» indica la ruta en la vamos a trabajar, que será la ruta en donde tenemos guardados esos ficheros. El comando «ls» lista los ficheros que cumplan con el patrón indicado y la salida la vuelca en un fichero nuevo llamado lista_ficheros.txt. Sin embargo, el paso anterior no discrimina los ficheros por fecha y para poder obtener, por ejemplo, los ficheros de los últimos 15 días utilizaremos lo siguiente:

x"cd /[ruta_ficheros]";
x"find *.csv -mtime +15 > lista_ficheros.txt";

El comando «find» busca todos aquellos ficheros en la ruta indicada que cumplan el patrón de nombre de fichero y que estén en el periodo temporal indicado en «-mtime» volcando todos los nombres de esos ficheros en un nuevo fichero llamado listado_ficheros.txt. Una vez llegado a este punto solo nos queda importar el fichero txt como una tabla SAS para poder procesar la información que contiene fácilmente:

data LISTA_FICHEROS;
    length fichero $ 50 ;
    format fichero $CHAR50. ;
    informat fichero $CHAR50. ;
    infile "[ruta_ficheros]/ficheros.txt"
        lrecl=50 encoding="LATIN9" missover;
    input fichero : $CHAR50. ;
run;

Ahora tenemos una tabla (LISTA_FICHEROS) que contiene una lista de nombres de ficheros csv que queremos importar. Como son varios, más de uno, debemos utilizar un bucle para recorrer la tabla de los nombres a la vez que importamos los csv y los vamos guardando como tablas SAS. Pero, ¿cómo se hace eso? ¿Cómo podemos recorrer una tabla a la vez que creamos otra? Utilizaremos para recorrer la primera tabla una especie de puntero que recorre LISTA_FICHEROS:

%let dsid = %sysfunc(open(LISTA_FICHEROS));
%macro importar_ficheros;
    %let num_reg = %sysfunc(attrn(&dsid,NOBS));
    %do x=1 %to &num_reg;
        %let rc = %sysfunc(fetch(&dsid));
        %let fichero = %sysfunc(getvarc(&dsid,%sysfunc(varnum(&dsid,F1))));

        data FICHERO_&x;
            length campo $ 20;
            format campo $CHAR20. ;
            informat campo $CHAR20. ;
            infile"&fichero"
                lrecl=20 encoding="UTF8" missover;
            input campo : $CHAR20. ;
        run;
%mend importar_ficheros;
%importar_ficheros;

Sobre como utilizar estos punteros de datos en SAS que hemos utilizado en este último paso podéis revisar este link: «Punteros de datos en SAS» donde se explican los distintos comandos que se utilizan para gestionar los punteros.

Por otro lado, el bucle anterior va recogiendo el nombre de cada fichero csv que está listado en la tabla LISTA_FICHEROS e importándolo a una tabla SAS. En este supuesto todos los ficheros son del mismo formato.