Reto PhP – Puede Pasarle a cualquier Programador


El Problema


Para este reto se usaron la herramienta de Php

  1. Date
  2. Mktime
  3. Substr

Narrare la historia de un Desarrollador de Software que lleva 5 meses trabajando en una pequeña empresa que desarrolla sistemas basados en Web. El sistema es un programa para universidades que se compone de 4 modulos, Central, Estudiante, Docente y Administrivo. No pretendo hablar de todo el sistema, pero doy una descripcion de donde trabajaba y de que tenia que realizar.

El Reto fue el siguiente: Realizar una planilla de Asistencia para un Docente :shock:, Se ve facil pero . . .

El problema que surgio fue que tenia la Fecha Inicio de Curso/Trimestre/Semestre, y Fecha Fin de Curso/Trimestre/Semestre. Existe una Oferta Academica que es un registro del curso que inscribio un alumno. el cual esta Relacionado con Oferta Academica Fecha con la idofertaacademica. Como todos saben se puede ver una materia 2 veces por semana a lo cual existirian dos OfertaAcademicaFecha con la misma idOfertaAcademica.

imagentabla1

Como pueden ver, en la tabla.. aunque falten registros (solo coloque los necesarios) no existe ningun campo en ofertaacademicafecha en donde se vea que fecha especifica empieza la clase, solo tenemos el dia que es representado por un numero y es cuando se ve la materia..
1 = lunes
2 = martes
3 = miercoles
4 = jueves
5 = viernes
6 = sabado
(PUEDE QUE ESTO SEA CONFUNSO)

Ejemplo:

  • Fecha Comienzo Clase = 05/01/2009 (Lunes = 1)
  • Fecha Fin Clase = 30/04/2009 (Jueves = 4)
  • Dia de la Materia (Matematica II) = 3, 4 y 5 ( Miercoles, Jueves y Viernes)

Ahora, ¿cómo sabemos que fecha cae el dia 3 por delante de la fecha comienzo clase?. Todos diran facil.. se suma los dias que faltan de Lunes a Miercoles a la Fecha Comienzo de Clase y se sabra que fecha cae (07/01/09) X_x. Pero no es asi de sencillo y hacerlo en php fue complicado. Codigo a Continuacion:

$ainicio = substr($sqlFechaCurso['fechainiciocurso'],0,4);
$minicio = substr($sqlFechaCurso['fechainiciocurso'],5,2);
$dinicio = substr($sqlFechaCurso['fechainiciocurso'],8,2);
// 		---------------------------------------------------------------------------->
$afin = substr($sqlFechaCurso['fechafincurso'],0,4);
$mfin = substr($sqlFechaCurso['fechafincurso'],5,2);
$dfin = substr($sqlFechaCurso['fechafincurso'],8,2);
// 		---------------------------------------------------------------------------->
// 		---------------------------------------------------------------------------->
$amedio = substr($sqlFechaCurso['fechainiciocurso'],0,4);
$mmedio = substr($sqlFechaCurso['fechainiciocurso'],5,2);
$dmedio = substr($sqlFechaCurso['fechainiciocurso'],8,2);
// 		---------------------------------------------------------------------------->
$listo = 0;
$contdia = 0;
$i = 1;
$sdia = 0;
$fechacomienzoclase = mktime(0,0,0,$minicio,$dinicio,$ainicio);
$fechamedioclase = mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio);
$fechafinclase = mktime(0,0,0,$mfin,$dfin,$afin);
while ($fechacomienzoclase < $fechafinclase){
	$sqlDiaExacto = $bd->query("SELECT dia  FROM ofertaacademicafecha as OAF
						WHERE ofertaacademica = '".$sice->input['opcionSeccion']."'
						GROUP BY dia
						ORDER BY dia ASC");
	while($r = $bd->fetch_row($sqlDiaExacto)){
		while($listo == 0){
			$dia = date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));
			if($r['dia'] == $dia){
				$diaespañol = $funciones->DiaEspanol(date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio)));
				$diamateria = date("d/m/Y",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));
				$listo = 1;
			}
			$contdia++;
		}
		$listo = 0;
		$contdia = 0;
	}
		$i++;
$sdia +=7;
$fechacomienzoclase = mktime(0,0,0,$minicio,$dinicio+$sdia,$ainicio);
$fechamedio = date("Y-m-d",mktime(0,0,0,$minicio,$dinicio+$sdia,$ainicio));
$amedio = substr($fechamedio,0,4);
$mmedio = substr($fechamedio,5,2);
$dmedio = substr($fechamedio,8,2);
}

Ejemplos de Funciones


SUBSTR

La funcion substr corta una cadena dandole el primer parametro “la cadena”, el segundo la posicion de la cadena y el tercer parametro cantidad de caracteres a cortar.
Ejemplo:

$cadena = "KernelError Postiando"
//"Kernel" tomara 6 caracteres desde la posición 0
$kernel = substr($cadena,0,6)
//"Postiando" tomara 9 caracteres desde la posición 12
$postiando = substr($cadena,12,9)

DATE

La función date, devuelve una cadena con formato de acuerdo a la cadena de formato dada.

Parametros Descripción
Formato Requerido. Especifica el formato de la Marca de Tiempo
TimeStamp (Marca de Tiempo) Opcional. Especifica la Marca de Tiempo, Predeterminado la marca de tiempo actual

Ejemplo:

echo date("Y/m/d"); //Imprime 2009/05/03
echo date("Y.m.d"); //Imprime 2009.05.03
echo date("Y-m-d"); //Imprime 2009-05-03
//04/05/2009
echo "Mañana ". date("d/m/Y",mktime(0,0,0,date("m"),date("d")+1,date(Y));
//04/06/2009
echo "Mes siguiente ". date("d/m/Y",mktime(0,0,0,date("m")+1,date("d"),date(Y));
//04/06/2010
echo "Año siguiente ". date("d/m/Y",mktime(0,0,0,date("m"),date("d"),date(Y)+1);
$hoy = date("F j, Y, g:i a");                 // May 3, 2009, 7:55 pm
$hoy = date('\i\t \i\s \t\h\e jS \d\a\y.');   // it is the 3rd day.
$hoy = date("D M j G:i:s T Y");               // Sat Mar 10 15:16:08 MST 2001
$hoy = date("H:i:s");                         // 17:16:17

MKTIME

La función mktime, devuelve la marca de tiempo Unix que corresponde a los argumentos dados. Esta marca de tiempo es un entero largo que contiene el número de segundos entre el Epoch Unix (Enero 1 1970 00:00:00 GMT) y la hora especificada.
Ejemplo:

/**
mktime(hora,min,seg,mes,dia,año)
*/
// 3 de Mayo del 2009 = 1236121200
echo mktime(0,0,0,3,4,2009)."<br />";
// 31 de Diciembre del 2009 = 1262214000
echo mktime(0,0,0,12,31,2009)."<br />";
// 1 de Enero del 2010 = 1262300400
echo mktime(0,0,0,1,1,2010);

Paso a Paso


Primero Necesitaba dividir la Fecha que traia de la base de datos que venia en formato ingles: 2009-01-01.

FechaInicioCurso = 2009-01-01

$ainicio = substr($sqlFechaCurso['fechainiciocurso'],0,4); //2009
$minicio = substr($sqlFechaCurso['fechainiciocurso'],5,2); //01
$dinicio = substr($sqlFechaCurso['fechainiciocurso'],8,2); //05

FechaFinCurso = 2009-04-30

$afin = substr($sqlFechaCurso['fechafincurso'],0,4); //2009
$mfin = substr($sqlFechaCurso['fechafincurso'],5,2); //04
$dfin = substr($sqlFechaCurso['fechafincurso'],8,2); //30

Esta fecha Medio se utiliza en el codigo para sacar la fecha exacta por cada semana de clase como limite la fecha fin curso

$amedio = substr($sqlFechaCurso['fechainiciocurso'],0,4); //2009
$mmedio = substr($sqlFechaCurso['fechainiciocurso'],5,2); //01
$dmedio = substr($sqlFechaCurso['fechainiciocurso'],8,2); //05

Se crean algunos contadores y una variable de validacion, tambien se le saca el valor timestamp de cada fecha con la funcion de php mktime

$listo = 0;
$contdia = 0;
$i = 1;
$sdia = 0;
$fechacomienzoclase = mktime(0,0,0,$minicio,$dinicio,$ainicio);
$fechamedioclase = mktime(0,0,0,$mmedio,$dmedio,$amedio);
$fechafinclase = mktime(0,0,0,$mfin,$dfin,$afin);

Se tiene que hacer un ciclo repetitivo que tenga como regla de validacion FechaInicioCurso < FechaFinCuros, si en algun momento del ciclo, FechaInicioCurso es mayor a la FechaFinCurso se saldra del ciclo.

while ($fechacomienzoclase < $fechafinclase)

Se hace una consulta de base de datos buscando los dias que se ven la materia (Este arroja 3,4,5)

    $sqlDiaExacto = $bd->query("SELECT dia  FROM ofertaacademicafecha as OAF
                        WHERE ofertaacademica = '".$sice->input['opcionSeccion']."'
                        GROUP BY dia
                        ORDER BY dia ASC");

Se realiza un while del fetch_row de la consulta que se acaba de hacer (fetch_row guarda los registros arrojados por la consulta en una variable en esta la $r), El saldra del while cuando ya no hayan registros (pasara 3 veces)

    while($r = $bd->fetch_row($sqlDiaExacto))

Se coloca un while que se repetira hasta que la condicion $listo sea diferente a 0

while($listo == 0)

Luego tenemos la variable $dia que usando las funciones date y mktime, obtendremos el numero del dia de la semana poniendo como dia, mes y año las variables de fechamedio, se le suma un contador a el $dmedio para que en cada vuelta del while pase de dia. Esta variable lo utilizaremos en la siguiente linea en una condicion IF.

$dia = date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));

Ahora se hace un IF (linea 7) con la condicion de que si el dia traido de la base de datos $r['dia'] es igual a la variable $dia que se saca con las funciones date y mktime.

$sqlDiaExacto = $bd->query("SELECT dia  FROM ofertaacademicafecha as OAF
						WHERE ofertaacademica = '".$sice->input['opcionSeccion']."'
						GROUP BY dia
						ORDER BY dia ASC");
	while($r = $bd->fetch_row($sqlDiaExacto)){
		while($listo == 0){
			$dia = date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));
			if($r['dia'] == $dia){
				$diaespañol = $funciones->DiaEspanol(date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio)));
				$diamateria = date("d/m/Y",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));
				$listo = 1;
			}
			$contdia++;
		}
  • Si es , se guarda en la variable $diaespañol el dia en letras con la $funcion->DiaEspañol, ya que la funcion date. trae los dias en ingles (Monday,Thusday). La función toma el numero de la semana que se saca con la combinacion de date y mktime, lo pasa a español colocando en la variable Lunes, Martes, Miercoles, etc. . .
    // Como el primer dia que se da la clase en la semana es el Numero 3
    // y fechainiciocurso es el numero 1
    // Luego de que el while de listo, pase 2 veces y se haga la logica de
    // $r['dia] == $dia, se guardara en la variable el Dia Miercoles
    $diaespañol = $funciones->DiaEspanol(date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio)));

    Tambien ya sumado los dias desde la FechaInicioCurso que funciona con el $contdia, guarda la fecha exacta con formato d/m/y en la variable $diamateria

    // Aqui ya sabiendo que el primer dia de clase es el Miercoles
    // necesitamos saber cual es su fecha exacta, La fechamedio
    // es el 05/01/2000  y como se a pasado 2 veces por el while
    // la variable $contdia tiene el valor 2 que se le suma a la variable
    // $dmedio = 05, dando el resultado de 7 entonces en la variable
    // $diamateria tiene la fecha de 07/01/2009
    $diamateria = date("d/m/Y",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));

    Luego cambia la variable $listo dandole el valor 1, con esto saldra del ciclo y se reiniciara la variable $contdia

    $listo = 1;
            while($listo == 0){
                $dia = date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));
                if($r['dia'] == $dia){
                       // Pasa
                       // Codigo
                }
                $contdia++;
            }
    
  • Si es No, solo pasa la condicion IF y se suma 1 al $contdia
            while($listo == 0){
                $dia = date("w",mktime(0,0,0,$mmedio,$dmedio+$contdia,$amedio));
                if($r['dia'] == $dia){
                       // No pasa
                       // Codigo
                }
                $contdia++;
            }
    

La ultima parte es la importante. Primero, se suma 7 dias a la variable $fechacomienzoclase la cual aumentara su timestamp hasta que deje de ser verdadera la condicion $fechacomienzoclase < $fechafinclase.

$sdia +=7;
$fechacomienzoclase = mktime(0,0,0,$minicio,$dinicio+$sdia,$ainicio);

Segundo, se guarda en $fechamedio la fecha en ingles, utilizando las variables $dmedio, $mmedio, $amedio. Sumando el mismo contador de 7 dias a la variable $dmedio. Luego esta misma variable se parte con la funcion substr para que las 3 variables de fechamedio tomen la fecha de la siguiente semana. y asi poder calcular los dia que toca la materia con su fecha exacta por cada semana con fecha limite la $fechafinclase

while ($fechacomienzoclase < $fechafinclase){
    // QUERY
    while($r = $bd->fetch_row($sqlDiaExacto)){
        while($listo == 0){
            if($r['dia'] == $dia){
                // CODIGO
            }
            // CONTADOR
        }
        // REINICIO DE VARIABLES
    }
$sdia +=7;
$fechacomienzoclase = mktime(0,0,0,$minicio,$dinicio+$sdia,$ainicio);
$fechamedio = date("Y-m-d",mktime(0,0,0,$minicio,$dinicio+$sdia,$ainicio));
$amedio = substr($fechamedio,0,4);
$mmedio = substr($fechamedio,5,2);
$dmedio = substr($fechamedio,8,2);
}

Resultado


Como ven en la planilla, muestra el dia en español y la fecha exacta por cada semana de clase hasta que culmine el semestre, no pueden ver cuantas paginas faltaban xD.. pero eran varias ;).



imagenreporte


Conclusión


El tema de la Programación no es soplar y hacer botella, pero por esto es que me encata la informatica. Ademas si no entienden algo no se preocupen en preguntar. Porque de vaina entiendo yo xD..

Saludos, Suerte con este Codigo Da Vinci

Att. FeCr_88
PD: CASPER TE AMO, BACHO TE AMO

    Posts Relacionados

    2 Comentarios en “Reto PhP – Puede Pasarle a cualquier Programador”

    1. avatar
      b@cHo 5 mayo 2009 at 7:36 pm #

      La sangre dejara de correr a consequencia tus acciones soy hombre de palabra, espero tu proxima entrada el prox mes, o sino-…

      Usando Unknown Unknown en Unknown Unknown
    2. avatar
      FeCr_88 5 mayo 2009 at 7:48 pm #

      Weno.. Bacho Gracias por la Espera X_X…

      Ahi esta el post

      Usando Unknown Unknown en Unknown Unknown

    Deja un comentario

    Tienes que estar logueado para escribir un comentario.