| Ver tema anterior :: Ver siguiente tema | | Autor | Mensaje |
|---|
polly
Registrado: 19 Jul 2007 Mensajes: 602
| Publicado: 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
| Publicado: 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
| Publicado: 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 :
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
| Publicado: 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 :
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
| Publicado: 05/12/2009 8:33 am | | | Título: |
| Gracias tio ! _________________ @enrmarc |
| | Volver arriba | |  | Pantalàimon_
Registrado: 17 Jul 2007 Mensajes: 961
| Publicado: 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
| Publicado: 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
| Publicado: 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
| Publicado: 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
| Publicado: 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
| Publicado: 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
| Publicado: 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
| | | Volver arriba | |  | eduar2083
Registrado: 10 Ago 2008 Mensajes: 216 Ubicación: Lima - Perú
| Publicado: 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
| Publicado: 06/04/2011 8:42 am | | | Título: |
| | esta excelente...saludos desde vzla |
| | Volver arriba | |  | | |
| No puede crear mensajes No puede responder temas No puede editar sus mensajes No puede borrar sus mensajes No puede votar en encuestas
|
|
| |