Inicio

Novedades de pgsql en la 7.0

Entrevista con Bruce Momjian

Manejo de Estilos de Fechas en PostgreSQL

Introducción a los Triggers en C para PostgreSQL

Ligas interesantes

Interpretación de Fechas

Finalmente, vamos a analizar la manera en que Postgres interpreta la entrada de diversas fechas. De acuerdo con el Appendix UG1. Date/Time Support, de la versión 7.0.2:

3. Si el token es un número o un campo numérico.

a. Si hay más de 4 dígitos y si no ha sido leído previamente otros campos de fecha, entonces se interpreta como una "fecha concatenada" (es decir 19990118). 8 y 6 dígitos se interpretan como año, mes y día, mientras que 7 y 5 dígitos se interpretan como año, día del año, respectivamente.

b. Si el token es de tres dígitos y el año ya ha sido decodificado, entonces se interpreta como día del año.

c. Si hay cuatro o más dígitos, se interpreta como un año.

d. Si se trata de un modo de fecha europeo (European), y el campo del día no ha sido léido, y si el valor es menor o igual a 31, entonces se interpreta como el día.

e. Si el campo del mes no ha sido leído, y si el valor es menor o igual a 12, entonces se interpreta como un mes.

f. Si el campo del día no ha sido leído, y si el valor es menor o igual a 31, entonces se interpreta como día.

g. Si hay dos dígitos o cuatro o más dígitos, se interpreta como año.

h. De otra manera, devuelve un error.

En nuestra prueba trataremos de introducir cuatro fechas: '2000-12-31','2000-31-12','31-12-2000'y '12-31-2000'. Las cuatro pretenden ser el 31 de diciembre de 2000, aunque escritas de diferentes maneras. Usaremos el formato de salida Postgres y los dos formatos de entrada que ofrece nuestra base de datos: NonEuropean y European, por medio del siguiente script con Perl:
 

#!/usr/bin/perl -w
# Manejo de fechas ambiguas.
# DBI: La neta para acceso a bases de datos con perl.
use DBI;

# Base de datos de prueba
$dbname = 'pruebas';

# Conexión a la base de datos
# Evitamos que DBI imprima el error en STDOUT
$dbh = DBI -> connect("dbi:Pg(PrintError=>0):dbname=$dbname");

defined ($dbh) or die "No pude conectar a la base de datos.\n";

# Fijamos el estilo de salida a 'Postgres'
$dbh->do("SET DATESTYLE TO 'Postgres'");
@estilos = qw(NonEuropean European);

# Arreglo de fechas de prueba
@fechas = ("2000-12-31","2000-31-12","31-12-2000","12-31-2000");

foreach $estilo (@estilos) {
	$dbh->do("SET DATESTYLE TO '$estilo'");
	print "\n                             $estilo\n\n";
	foreach $fecha(@fechas) {
		$sql = "UPDATE persona set fecha_actualizacion = ? WHERE id_persona = 1;";
		$sth=$dbh->prepare($sql);
		# Nuestra sentencia SQL modifica fecha de contratación de una persona
		$sth->execute($fecha);
		$rc = $sth->err;
		# Primera parte del mensaje: La entrada ...
		unless ($rc) {$msg="Entrada: $fecha, "} else {$msg = "Error>>> $fecha, "};
		# Consultamos el registro para observar como se modificó 
		$sql= "SELECT fecha_actualizacion FROM persona WHERE id_persona = 1;";
		$sth=$dbh->prepare($sql);
		$sth->execute;
		while ( @row = $sth->fetchrow_array ) {
			#... y la salida.
			print " $msg  Salida: $row[0]\n";
		}
	}
}

El cual genera la siguiente salida al ejecutarse:

 
                             
							 NonEuropean

 Entrada: 2000-12-31,   Salida: Sun Dec 31 00:00:00 2000 CST
 Entrada: 2000-31-12,   Salida: Sun Dec 31 00:00:00 2000 CST
 Entrada: 31-12-2000,   Salida: Sun Dec 31 00:00:00 2000 CST
 Entrada: 12-31-2000,   Salida: Sun Dec 31 00:00:00 2000 CST

                             European

 Entrada: 2000-12-31,   Salida: Sun 31 Dec 00:00:00 2000 CST
 Entrada: 2000-31-12,   Salida: Sun 31 Dec 00:00:00 2000 CST
 Entrada: 31-12-2000,   Salida: Sun 31 Dec 00:00:00 2000 CST
 Error>>> 12-31-2000,   Salida: Sun 31 Dec 00:00:00 2000 CST

Podemos observar comportamientos diferentes en función del formato de entrada. Con el estilo NonEuropean no existe ningún problema: las fechas son bien interpretadas en los cuatro casos, como se puede ver en la salida. Sin embargo, usando el formato European la fecha '12-31-2000' no puede ser interpretada y se considera un error. La causa del error se puede encontrar en las reglas anotadas más arriba: La regla 3.d menciona que si el modo es European y el campo del día no ha sido leído y el valor es menor o igual a 31, o sea nuestro caso, entonces ese valor se interpreta como ¡el día!, así que Postgres nos regresa un error al detectar que no hay un mes '31'.

Podemos concluir que Postgres hará todo cuanto sea posible por interpretar de la mejor manera la entrada de la fecha, pero las reglas que tiene no son infalibles. así que no debemos descuidarnos en ese flanco tomando, al menos, estas precauciones:

  • Indique de manera explícita el formato con el que espera que se capturen las fechas; ya sea como parte de la etiqueta que acompaña al campo de captura, o en las salida que genere el parámetro de ayuda, algo como:
    
>mi_script --ayuda
    
    Esta es la ayuda de mi_script:
    
    mi_script espera como parámetro una fecha con el formato 'dd/mm/aaaa', por ejemplo: '21/12/2001'.
  • Valide la entrada de la fecha. Puede hacerlo analizando sintacticamente cada uno de loe elementos de la fecha o uando algún módulo de Perl, por ejemplo Date-Calc.
  • Planee cuidadosamente los formatos de entrada y salida que definirá con la sentencia SET DateStyle TO 'estilo_deseado'.

Para termina solamente me resta comentarle que las siglas CST y CDT que acompañan a algunos estilos, son producto de las zonas temporales, es decir de manera relativa al Greenwich Mean Time (GMT). Puede ver los obscuros detalles en la documentación de PostgreSQL: http://www.postgresql.org/docs/postgres/datetime-appendix.htm#AEN28108.

Roberto Andrade Fonseca

[email protected]