Ejercicios resueltos laboratorio 11 - Procedimientos y funciones (fechas)

Asignatura: Fundamentos de Informática
Especialidad: Electrónica - UPV/EHU
Curso académico: 2013-2014
Profesor: Ismael Etxeberria Agiriano

En este laboratorio vamos a utilizar un conjunto de funciones asociadas con las horas y las fechas.

Los detalles de codificación de la mayoría de estas funciones van más allá del alcance de este curso, por lo que deberían ser vistas como cajas negras, es decir, comprender su modo de utilización pero desentenderse del cómo lo hace.

Para la utilización correcta de estas funciones deberían incluirse en una biblioteca y linkarlas como se hace con otras funciones (printf, scanf, ...). Las complicaciones técnicas hacen más práctico desde el punto de vista didáctico su inclusión en cada fichero fuente, duplicando el código.

Al final de este documento se proporciona el código completo de las funciones propuestas.

11.1. Ejercicio resuelto: DiaSis

Se proporciona una función que obtendrá la fecha del sistema con la siguiente cabecera:


Figura 11.1. Cabecera de la función DiaSis.

El prototipo correspondiente puede ser:

void DiaSis (int *dia, int *mes, int *ano);

La función no devuelve nada, lo cual se ha representado mediante un recuadro a puntos rosa vacío. En el prototipo de la función se indica que la función devuelve void.

No tiene parámetros de entrada y podríamos haberlo representado mediante una recuadro a puntos pero no lo hemos hecho para simplificar la figura.

La función obtendrá el día, el mes y el año de la fecha del sistema, que se actualiza a partir de un reloj interno. Para poder recuperar esta fecha tendremos que enviar la dirección de las variables correspondientes (&dia, &mes y &ano) para que se actualicen.

Nótese que la función podrá ver el contenido previo de las direcciones dia, mes y ano pero en la representación de la Figura 11.1 estamos queriendo expresar que esa información no se utiliza. Este detalle no se puede deducir del prototipo.

Se proporciona un ejemplo de utilización de esta función DiaSis.

Al final de este documento se proporciona el código completo de las funciones propuestas. En este ejemplo 11-r01-DiaSis.c habrá que añadir los prototipos y el código proporcionado de la función DiaSis.


/* 11-r01-DiaSis.c */
#include <stdio.h>
#include <stdlib.h>
#include "fechas.h"

int main (void)
{
  int dia, mes, ano;
  DiaSis (&dia, &mes, &ano);
  printf ("Fecha del sistema: %02d/%02d/%d\n", dia, mes, ano);

  system ("pause");
  return 0;
}

Ejemplo de ejecución:


Fecha del sistema: 11/12/2009

11.2. Ejercicio resuelto: HorSis

Se proporciona una función que obtendrá la hora del sistema con la siguiente cabecera:


Figura 11.2. Cabecera de la función HorSis.

El prototipo correspondiente puede ser:

void HorSis (int *hor, int *min, int *seg);

Se observará que el ejemplo es similar al anterior por lo que no vamos a detallar la descripción.

Se proporciona un ejemplo de utilización. Al final de este documento se podrá encontrar el código completo de las funciones propuestas.


/* 11-r02-HorSis.c */
#include <stdio.h>
#include <stdlib.h>
#include "fechas.h"

int main (void)
{
  int hor, min, seg;
  HorSis (&hor, &min, &seg);
  printf ("Hora del sistema: %02d:%02d:%02d\n", hor, min, seg);

  system ("pause");
  return 0;
}

Ejemplo de ejecución:


Hora del sistema: 14:09:05

11.3. Ejercicio resuelto: DiaJul

Se proporciona una función que obtendrá la fecha del calendario juliano o fecha numérica a partir de la correspondiente fecha del calendario gregoriano.


Figura 11.3. Cabecera de la función DiaJul.

El prototipo correspondiente puede ser:

long DiaJul (int dia, int mes, int ano);

Para el 9 de diciembre de 2009 la fecha juliana es el 2.455.175, de lo que se puede deducir que no va a caber en un entero corto. Por ello nos aseguramos de que la función devuelve un entero largo (long) en el que sabemos que sí cabrá.

Las ventajas de utilizar fechas en formato numérico son múltiples. Una única variable contiene la fecha. Podemos sumar y restar días directamente y la obtención del día de la semana es el resto de dividirlo por 7 aunque eso es transparente si se utiliza la función DiaSem.

Se proporciona un ejemplo de utilización de esta nueva función en combinación con la que nos proporciona la fecha del sistema.

Para poder probar este programa habrá que añadir el código de las dos funciones propuestas, DiaSis y DiaJul. Al final de este documento se proporciona el código completo de las funciones propuestas.


/* 11-r03-DiaJul.c */
#include <stdio.h>
#include <stdlib.h>
#include "fechas.h"

int main (void)
{
  int dia, mes, ano;
  long jul;

  DiaSis (&dia, &mes, &ano);
  jul = DiaJul (dia, mes, ano);
  printf ("Fecha juliana: %ld\n", jul);

  system ("pause");
  return 0;
}

Ejemplo de ejecución (para el 9 de diciembre de 2009):


Fecha juliana: 2455175

11.4. Ejercicio resuelto: DiaSem, TxtDsm y TxtMes

La función DiaSem devuelve el ordinal del día de la semana numerado del 0 al 6. Este ordinal puede utilizarse como parámetro a la función TxtDsm, que nos devuelve el texto correspondiente al día de la semana (lunes, martes, ...).

TxtMes es similar a TxtDsm ya que nos da el texto del mes pero contando de 1 a 12.

El respectivos prototipos son:

int   DiaSem (long jul);
char *TxtDsm (int dsm);
char *TxtMes (int mes);

Se proporciona un ejemplo de utilización de estas nuevas funciones en combinación con las anteriores.

Para poder probar este programa habrá que añadir el código de las funciones necesarias. Al final de este documento se proporciona el código completo de las funciones propuestas.


/* 11-r04-DiaSem.c */
#include <stdio.h>
#include <stdlib.h>
#include "fechas.h"

int main (void)
{
  int dia, mes, ano;
  long hoy;
  int dsm;

  DiaSis (&dia, &mes, &ano);
  hoy = DiaJul (dia, mes, ano);
  dsm = DiaSem (hoy);
  printf ("%s, %d de %s de %d\n", TxtDsm(dsm), dia, TxtMes(mes), ano);

  system ("pause");
  return 0;
}

Ejemplo de ejecución:


miércoles, 9 de diciembre de 2009

11.5. Ejercicio resuelto: DiaGrg

La función inversa a DiaJul es DiaGrg. DiaGrg obtendrá la fecha del calendario gregoriano a partir de la correspondiente fecha del calendario juliano.


Figura 11.4. Cabecera de la función DiaGrg.

El prototipo correspondiente puede ser:

void  DiaGrg (long jul, int *dd, int *mm, int *aa);

Se proporciona un ejemplo de utilización de esta nueva función en combinación con las anteriores.

Para poder probar este programa habrá que añadir el código de las funciones necesarias. Al final de este documento se proporciona el código completo de las funciones propuestas.


/* 11-r05-DiaGrg.c */
#include <stdio.h>
#include <stdlib.h>
#include "fechas.h"

int main (void)
{
  int dia, mes, ano;
  int hor, min, seg;
  long jul;

  DiaSis (&dia, &mes, &ano);      /* Fecha del sistema en gregoriano */
  jul = DiaJul (dia, mes, ano);   /* Fecha en juliano */
  jul--;                          /* Ayer en juliano */
  DiaGrg (jul, &dia, &mes, &ano); /* Ayer en gregoriano */
  printf ("Ayer %s: %02d/%02d/%d\n", TxtDsm (DiaSem (jul)), dia, mes, ano);

  DiaGrg (1, &dia, &mes, &ano); /* Primer día del calendario juliano */
  printf ("Primera fecha juliana: %02d/%02d/%d\n", dia, mes, ano);

  jul = DiaJul (1, 1, 1);         /* Primer día de la historia en juliano */
  jul--;                          /* Día anterior en juliano */
  DiaGrg (jul, &dia, &mes, &ano); /* Último día de la prehistoria gregoriano */
  printf ("Ultimo dia prehistoria: %02d/%02d/%d\n", dia, mes, ano);

  system ("pause");
  return 0;
}

Ejemplo de ejecución:


Ayer martes: 08/12/2009
Primera fecha juliana: 02/01/-4713
Ultimo dia prehistoria: 31/12/-1

11.6. Resumen: código de las funciones proporcionadas

En esta sección se proporciona el código completo de las funciones propuestas. En primer lugar tendremos los prototipos (se pueden poner siempre todos o especificar selectivamente aquéllos que se utilizan):


/* fechas.h */
void  HorSis           (int *hh, int *mm, int *ss); /* Hora  del sistema */
void  DiaSis           (int *dd, int *mm, int *aa); /* Fecha del sistema */
long  DiaJul           (int  dd, int  mm, int  aa); /* De Grg a Jul */
void  DiaGrg (long jul, int *dd, int *mm, int *aa); /* De Jul a Grg */
int   DiaSem (long jul);                            /* Ordinal día de semana */
char *TxtDsm (int  dsm);                            /* Nombre día de semana */
char *TxtMes (int  mes);                            /* Nombre del mes */

Estos prototipos pueden ir en un fichero de cabeceras, por ejemplo, fechas.h. Se proporcionan ejemplos completos de cómo se puede realizar eso con wx-devcpp. Si se desea probarlos con una versión anterior (por ejemplo, DevC++) es recomendable rehacer el proyecto porque pueden encontrarse problemas de compatibilidad. Asimismo se recomienda evitar el uso de carpetas con espacios ya que genera problemas a la hora de compilar los programas.

La definición de las funciones, aunque no es relevante en estos momentos, se proporciona a continuación:


/* fechas.c */
#include <time.h>

void DiaSis (int *dd, int *mm, int *aa)
{
  time_t timer;
  struct tm *stm;

  timer = time (NULL);
  stm = localtime (&timer);

  *dd = stm->tm_mday;
  *mm = stm->tm_mon + 1;
  *aa = stm->tm_year + 1900;
}

void HorSis (int *hh, int *mm, int *ss)
{
  time_t timer;
  struct tm *stm;

  timer = time (NULL);
  stm = localtime (&timer);

  *hh = stm->tm_hour;
  *mm = stm->tm_min;
  *ss = stm->tm_sec;
}

long DiaJul (int dd, int mm, int aa)
{
  long jul;
  int  ja,
       jy,
       jm;

  jy = aa;

  if (jy == 0)
    return -1; /* No hay año 0 */

  if (jy < 0)
    ++jy;

  if (mm > 2) {
    jm = mm + 1;
  }
  else {
    --jy;
    jm = mm + 13;
  }

  jul =  (long) (365.25  * jy) +
         (long) (30.6001 * jm) +
                dd +
           1720995L;

  if (dd + 31L * (mm + 12L * aa) >= (15 + 31L * (10 + 12L * 1582))) {
    ja = (int) (0.01 * jy);
    jul += 2 - ja + (int) (0.25 * ja);
  }

  return jul;
}

void DiaGrg (long jul, int *dd, int *mm, int *aa)
{
  long ja, jal, jb, jc, jd, je;

  if (jul >= 2299161L) {
   jal = ((float) (jul - 1867216L) - 0.25) / 36524.25;
    ja = jul + 1 + jal - (long) (0.25 * jal);
  }
  else if (jul < 0)
   ja = jul + 36525L *( 1 - jul / 36525L);
  else
    ja = jul;
  jb = ja + 1524;
  jc = (long) (6680.0 + ((float) (jb - 2439870L) - 122.1) / 365.25);
  jd = (long) (365 * jc + (0.25 * jc));
  je = (long) ((jb - jd) / 30.6001);
  *dd = (int)(jb - jd - (long) (30.6001 * je));
  *mm = (int)(je - 1);

  if (*mm > 12)
    *mm -= 12;
  *aa = (int)(jc - 4715);
  if (*mm > 2) --(*aa);
  if (*aa <= 0) --(*aa);
  if (jul < 0)
   *aa -= (int)(100 * (1 - jul / 36525L));
}

int DiaSem (long jul)
{
  return (int)(jul % 7);
}

static char *vTxtDsm [] = {
  "lunes",
  "martes",
  "miércoles",
  "jueves",
  "viernes",
  "sábado",
  "domingo"
};

char *TxtDsm (int dsm)
{
  return vTxtDsm [dsm];
}

static char *vTxtMes [] = {
  "error",
  "enero",
  "febrero",
  "marzo",
  "abril",
  "mayo",
  "junio",
  "julio",
  "agosto",
  "septiembre",
  "octubre",
  "noviembre",
  "diciembre"
};

char *TxtMes (int mes)
{
  return vTxtMes [mes];
}