/
Inicio :: Foros

 F.A.Q.F.A.Q.                  Conéctese para revisar sus mensajesConéctese para revisar sus mensajes   

Duda sobre algoritmo de fechas

 
      Índice del Foro elrincondelc.com -> Algoritmos
Ver tema anterior :: Ver siguiente tema  
AutorMensaje
polly



Registrado: 19 Jul 2007
Mensajes: 602

MensajePublicado: 04/12/2009 3:55 pm
Título: Duda sobre algoritmo de fechas

Buenas, buscando por la red algoritmos que aceptando como entrada una fecha (dia-mes-año) devuelva el dia de la semana en que cayo, encontre el siguiente:

Código:


int day_of_week(int style, int year, int month, int day)
{
    int a = (14 - month) / 12;
    int y = year - a;
    int m = month + 12*a - 2;
    return style == JULIAN
             ? (5 + day + y + y/4 + (31*m)/12) % 7
             : (day + y + y/4 - y/100 + y/400 + (31*m)/12) % 7;
}


Acepta como entradas el dia , mes y año (ademas del estilo: calendario juliano o gregoriano) y devuelve un numero entre 0 y 6 (0 = Domingo, 1 =Lunes, ....)

La web es : http://www.tondering.dk/claus/cal/calendar29.txt

La cuestion es que no logro entender el algoritmo, nose porque hace 14-month, o suma 5 por ahi , etc, etc

(solo entiendo algunos fragmentos como y/4 + y/100 + y/400 por lo de los años bisiestos, y los % 7 para devolver numeros en el rango [0-6])

Alguien sabe de que va ?

Gracias
_________________
@enrmarc
Volver arriba
rir3760



Registrado: 01 Oct 2004
Mensajes: 6586
Ubicación: Mexico

MensajePublicado: 04/12/2009 6:08 pm
Título:

Lo primero: disculpa si esto no responde satisfactoriamente a tu pregunta pero me temo en este momento estoy experimentando algunas dificultades tecnicas (mas bien una alto nivel de "octanaje" en la sangre pero una descripcion mas a fondo quedaria muy fea ademas de deprimente, ...., en fin).

Uno de los algoritmos mas conocidos (al menos en USENET) fue publicado en comp.lang.c cortesia de Tomohiko Sakamoto. Un programa de ejemplo es (C estandar):
Código:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define A_MIN 1970
#define A_MAX 2037

int es_fecha_valida(int a, int m, int d);
int dia_be(int a, int m, int d);
int dia_ts(int a, int m, int d);

int main(void)
{
   char *dia[] = {
      "Domingo",
      "Lunes",
      "Martes",
      "Miercoles",
      "Jueves",
      "Viernes",
      "Sabado"
   };
   int a, m, d;
   
   printf("Introduce la fecha (aaaa/mm/dd): ");
   fflush(stdout);
   if (scanf("%d/%d/%d", &a, &m, &d) == 3 && es_fecha_valida(a, m, d)){
      putchar('\n');
     
      printf("%d/%d/%d ==> %s\n", a, m, d, dia[dia_be(a, m, d)]);
      printf("%d/%d/%d ==> %s\n", a, m, d, dia[dia_ts(a, m, d)]);
   }
   
   return EXIT_SUCCESS;
}

/* Verifica si la fecha dada este dentro del rango valido */
int es_fecha_valida(int a, int m, int d)
{
   int mes[2][13] = {
      {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
      {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
   };
   int es_bisiesto;
   int r;
   
   if (a < A_MIN || a > A_MAX)
      r = 0;
   else {
      es_bisiesto = (a%4 == 0 && a%100 != 0) || a%400 == 0;
      r = m >= 1 && m <= 12 && d >= 1 && d <= mes[es_bisiesto][m];
   }
   
   return r;
}

/* Calculo del dia de la semana -- mktime */
int dia_be(int a, int m, int d)
{
   struct tm temp = {0};
   
   temp.tm_year = a - 1900;
   temp.tm_mon  = m - 1;
   temp.tm_mday = d;
   
   if (mktime(&temp) == -1)
      exit(EXIT_FAILURE);
   
   return temp.tm_wday;
}

/* Calculo del dia de la semana -- Tomohiko Sakamoto */
int dia_ts(int a, int m, int d)
{
   static int t[] = {
      0, 3, 2, 5,
      0, 3, 5, 1,
      4, 6, 2, 4
   };
   
   a -= m < 3;
   
   return (a + a/4 - a/100 + a/400 + t[m-1] + d) % 7;
}


Dos pagina relacionadas con este (espero, si no es asi me excuso en base al primer parrafo ) son:

How to determine the day of the week, given the month, day and year
Day of the week algorithm

Un saludo
_________________
Memory never recaptures reality. Memory reconstructs. All reconstructions change the original, becoming external frames of reference that inevitably fall short.
--
Mentat Handbook
Volver arriba
polly



Registrado: 19 Jul 2007
Mensajes: 602

MensajePublicado: 05/12/2009 2:59 am
Título:

Gracias por tu respuesta rir.

Lo que pasa es que tengo que implementar el algoritmo en ensamblador (no de intel) y ademas tengo que saber que es lo que hace.

Asi que el metodo mktime() descartado.
El metodo de Tomohiko Sakamoto esta bastante bien, quiza el uso de una tabla me dificulte mas la implementacion (no soy muy bueno en ensamblador), pero lo he probado y "sirve" para fechas del calendario gregoriano mas no para las del calendario juliano.

De todas formas, muchas gracias.

PD:

en el algortimo del Sakamoto , a que se refiere con esto :

Código:

a -= m < 3;


Es desplazamiento de bits ?, se podria poner en otra forma mas "tradicional" ?

S2
_________________
@enrmarc
Volver arriba
rir3760



Registrado: 01 Oct 2004
Mensajes: 6586
Ubicación: Mexico

MensajePublicado: 05/12/2009 7:40 am
Título:

polly escribió:
Asi que el metodo mktime() descartado.

Es una lastima ya que esa funcion es muy util, por ejemplo puedes tomar la fecha actual (como un objeto de tipo "struct tm"), restarle, no se, 500 dias y que esa funcion se encarge de los detalles feos.

polly escribió:
en el algortimo del Sakamoto , a que se refiere con esto :
Código:
a -= m < 3;


Es desplazamiento de bits ?

No.

polly escribió:
se podria poner en otra forma mas "tradicional" ?

Por supuesto que si. Solo tienes que recordar que en C los operadores de igualdad, diferencia y relacionales:

==
!=
>
<
>=
<=

Son expresiones y su resultado es uno si se cumple la condicion y cero en caso contrario, el fragmento que mencionas solo es una forma ligeramente mas compacta y enredada que la usual y mejor (por simple):
Código:
if (m < 3)
   a = a - 1;


Un saludo
_________________
Memory never recaptures reality. Memory reconstructs. All reconstructions change the original, becoming external frames of reference that inevitably fall short.
--
Mentat Handbook
Volver arriba
polly



Registrado: 19 Jul 2007
Mensajes: 602

MensajePublicado: 05/12/2009 8:33 am
Título:

Gracias tio !
_________________
@enrmarc
Volver arriba
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 961

MensajePublicado: 08/12/2009 5:14 pm
Título:

Refiriendome al post inicial el calculo de month no lo he logrado entender.

No sé si te puede ayudar pero te informo de que el calendario juliano cada 28 años los dias de la semana vuelven a ser idénticos y que en gregoriano esto ocurre en ciclos de 400 años.

Un saludo!
Volver arriba
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 961

MensajePublicado: 08/12/2009 5:57 pm
Título:

No he podido dejar de pensar en lo de month y m.

a vale 1 vara enero y febrero, y 0 para los demás.

m será para los meses de enero a diciembre 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 , respectivamente.

Y, sorprendentemente, ((31*m)/12)%7 da el dia de la semana en que inicia cada mes en el caso de que 1 de enero iniciara en 0 (Lunes)

Un saludo!
Volver arriba
polly



Registrado: 19 Jul 2007
Mensajes: 602

MensajePublicado: 09/12/2009 5:44 am
Título:

Cita:
Y, sorprendentemente, ((31*m)/12)%7 da el dia de la semana en que inicia cada mes en el caso de que 1 de enero iniciara en 0 (Lunes)


En 1900 el 1 de enero cae Lunes ...
Creo haber visto algun otro algoritmo tomando como referencia ese año.

Gracias !! seguire investigando ...
_________________
@enrmarc
Volver arriba
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 961

MensajePublicado: 09/12/2009 3:14 pm
Título:

A ver, yo ya lo veo claro lo del algoritmo:

a es de tal manera que vale 1 para enero y febrero y, 0 para los demás meses.

Se define y como year - a. Es decir de marzo a diciembre y sigue significando el año, para enero y febrero significa un año menos de lo que debería ser( ya veremos por qué).

Una vez ahí vamos a ver que significa y + y/4( en calendario juliano). Si todos los años fueran de 365 dias, cada año tendría 52 semanas y 1 dia. Es decir que si 2001 empieza en lunes, 2002 empezaría en martes, 2003 en miercoles, etc... Un dia más cada año , de ahí viene y. Pero además en calendario juliano cada 4 años hay un año bisiesto, que tiene 1 dia más de lo normal cada 4 años . De ahí viene +y/4

Con una misma lógica se podría entender el gregoriano, pero ahora sabiendo que cada 4 años hay un dia mas pero no cuando es multiplo de 100 (-y/100) pero si es múltiplo de 400 si que es bisiesto, por tanto +y/400

Luego, y es un año menos cuando es enero o febrero para no contabilizar el dia de más que tiene el año bisiesto, pues hasta pasado el 29 de febrero no hay un dia más.

El 5 o el 0 deben ser el dia de la semana en que inició el uno de enero del hipotetico año 0.

Un saludo!
Volver arriba
polly



Registrado: 19 Jul 2007
Mensajes: 602

MensajePublicado: 10/12/2009 11:00 am
Título:

Muchisimas gracias Pantalàimon_ !!!

Ahora podre usarlo (y explicarlo).

Código:
El 5 o el 0 deben ser el dia de la semana en que inició el uno de enero del hipotetico año 0.


el 1 de enero del año 1 fue sabado (5). Segun la aplicacion 'cal' de *unix.

S2
_________________
@enrmarc
Volver arriba
Pantalàimon_



Registrado: 17 Jul 2007
Mensajes: 961

MensajePublicado: 10/12/2009 5:15 pm
Título:

Por cierto, no sé nada de ensamblador pero creo que un operador condicional costará menos que una multiplicación o división. Así que dejo un código que haria lo mismo pero usando alguna operación menos costosa.

Código:
int day_of_week(int style, int year, int month, int day)
{   
    int a = month < 3;
    int y = year - a;
    int m += month + (a ? 10 : -2);
    return style == JULIAN
             ? (5 + day + y + y/4 + (31*m)/12) % 7
             : (day + y + y/4 - y/100 + y/400 + (31*m)/12) % 7;
}
Volver arriba
manuel_venezuela



Registrado: 02 Mar 2011
Mensajes: 32
Ubicación: venezuela

MensajePublicado: 27/03/2011 10:46 am
Título: Re: Duda sobre algoritmo de fechas

Código:

#include<stdio.h>
int main(void){

   int ano;
   int mes;
   int fecha;
   int dia;
   int modulo_mes;

   printf("año \n");
   scanf("%d",&ano);
   printf("mes:\n");
   scanf("%d",&mes);
   printf("dia:\n");
   scanf("%d",&fecha);

      if((ano%4==0) && (ano%100!=0) || (ano%400==0))
      {
            printf("bisiesto\n");

         if(mes==1)
            modulo_mes=0;
         if(mes==2)
            modulo_mes=3;
         if(mes==3)
            modulo_mes=4;
         if(mes==4)
            modulo_mes=0;
         if(mes==5)
            modulo_mes=2;
         if(mes==6)
            modulo_mes=5;
         if(mes==7)
            modulo_mes=0;
         if(mes==8)
            modulo_mes=3;
         if(mes==9)
            modulo_mes=6;
         if(mes==10)
            modulo_mes=1;
         if(mes==11)
            modulo_mes=4;
         if(mes==12)
            modulo_mes=6;
         
         

      
      }
      else
      {
         if(mes==1)
            modulo_mes=0;
         if(mes==2)
            modulo_mes=3;
         if(mes==3)
            modulo_mes=3;
         if(mes==4)
            modulo_mes=6;
         if(mes==5)
            modulo_mes=1;
         if(mes==6)
            modulo_mes=4;
         if(mes==7)
            modulo_mes=6;
         if(mes==8)
            modulo_mes=2;
         if(mes==9)
            modulo_mes=5;
         if(mes==10)
            modulo_mes=0;
         if(mes==11)
            modulo_mes=3;
         if(mes==12)
            modulo_mes=5;
         
         
      
      }


      
      dia=  ((ano-1)%7+ ((ano-1)/4 -(3*((ano-1)/100+1)/4))%7+modulo_mes+fecha%7)%7;
      
      
      printf("el dia de la semana es:\n");
      printf("dia:%d\n",dia);      
      printf("0-domingo,1-lunes,2-martes,3-miercoles\n");
      printf("4-jueves,5-viernes,6-sabado\n");

}
Volver arriba
manuel_venezuela



Registrado: 02 Mar 2011
Mensajes: 32
Ubicación: venezuela

MensajePublicado: 27/03/2011 10:51 am
Título: Re: Duda sobre algoritmo de fechas

hola desde vzla...el codigo anterior es para ver el dia de la semana en que cayo una fecha determinada, lo extraje de esta fuente..

http://es.wikipedia.org/wiki/Algoritmo_para_calcular_el_d%C3%ADa_de_la_semana

cualquier cosa
Volver arriba
eduar2083



Registrado: 10 Ago 2008
Mensajes: 216
Ubicación: Lima - Perú

MensajePublicado: 05/04/2011 6:52 pm
Título:

Buenas tardes, hace algún tiempo escribí un programa que determina el día de la semana de una fecha dada. Para ello hago uso del algoritmo Doomsday. Espero sirva de algo.
Saludos.
Código:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>


#define esBisiesto( a ) ( (a) % 4 == 0 && (a) % 100 != 0 || (a) % 400 == 0 )


/* Prototipos */
int validaFecha( int, int, int );
char* diaDeSemana( int, int, int );


/* La función main comienza la ejecución del programa */
int main()
{
    char cadFecha[11];
    int dia, mes, anyo;
    int iError;
    int continuar = 's';

    /* Ciclo de control del programa */
    while ( continuar != 'n' ) {
        system( "cls" );
        printf( "Este programa determina el dia de la semana de una fecha dada\n\n" );

        iError = 1;
        while ( iError ) {
            printf( "Ingrese fecha[dd/mm/aaaa]: " );
            fflush( stdin );
            scanf( "%10s", cadFecha );

            if ( sscanf( cadFecha, "%d/%d/%d", &dia, &mes, &anyo ) == 3 ) {
                iError = validaFecha( dia, mes, anyo );

                if ( iError )
                    printf( "\nLa fecha no es consistente, intente otra vez\n\n" );

                else
                    printf( "\n%02d/%02d/%4d Fue/Es/Sera -> %s\n", dia, mes, anyo, diaDeSemana( dia, mes, anyo ) );
            }
            else
                printf( "\nEntrada no valida\n\n" );
        }

        printf( "\n\n\n\t\tDesea continuar? (s/n): " );
        fflush( stdin );
        continuar = tolower( getchar() );
    }

    return 0;   /* indicar terminación exitosa */

}   /* Fin de main */


/* Implementación de funciones */


/*  Rutina validaFecha.
   Verifica que una fecha determinada sea correcta
   Esta rutina devuelve:
   0 si la fecha es correcta
   1 si la fecha no es consistente
*/
int validaFecha( int dia, int mes, int anyo )
{
    static char dayTab[2][13] =
    {
        { 0, 31, 28, 31, 30, 31, 30, 31,31, 30, 31, 30, 31 },
        { 0, 31, 29, 31, 30, 31, 30, 31,31, 30, 31, 30, 31 },
    };

    if ( mes > 0 && mes <= 12 ) {
        if ( dia > 0 && dia <= dayTab[0][mes] )
           return 0;

        /* Si dia es 29 y año bisiesto, la fecha es correcta */
        if ( dia == 29 && esBisiesto( anyo ) )
           return 0;
    }

    return 1;
}

char* diaDeSemana( int dia, int mes, int anyo )
{
    static char* dias[] = { "Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado" };

    static char modTab[2][12] =
    {
        { 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 },
        { 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 },
    };

    int caso = esBisiesto( anyo );
    int mod = modTab[caso][mes-1];
    int val = anyo - 1;

    int d = ( val % 7 + ( val / 4 - 3 * ( ( val / 100 + 1 ) / 4 ) ) % 7 + mod + dia % 7 ) % 7;

    return dias[d];
}
Volver arriba
manuel_venezuela



Registrado: 02 Mar 2011
Mensajes: 32
Ubicación: venezuela

MensajePublicado: 06/04/2011 8:42 am
Título:

esta excelente...saludos desde vzla
Volver arriba
      Índice del Foro elrincondelc.com -> Algoritmos
Página 1 de 1Todas las horas están en GMT - 8 Horas

 
No puede crear mensajes
No puede responder temas
No puede editar sus mensajes
No puede borrar sus mensajes
No puede votar en encuestas

(c) ElRincondelC.com

Un proyecto de UrlanHeat.com