C Programa para encontrar el día de la semana dada la fecha

7 minutos de lectura

avatar de usuario
elReverseFlick

¿Hay alguna manera de averiguar el día de la semana en una sola línea de código C?

Por ejemplo

Dado 19-05-2011(dd-mm-yyyy) me da jueves

  • Ver congruencia de Zeller para una fórmula explícita para calcular el día de la semana. Y no conozco ningún límite en la longitud de las líneas en C, por lo que puede reformatear cualquier programa para que quepa en una sola línea…

    – André Holzner

    19 de mayo de 2011 a las 12:08

  • Creo que siempre necesita algún ancla, es decir, una fecha para la que sepa el día de la semana, por ejemplo, “1 de enero de 1900 fue lunes” en la respuesta de @maerics. Supongo que otros algoritmos sugeridos tienen un ancla incorporada

    – davka

    19 de mayo de 2011 a las 12:48

  • Consulta este enlace. También contiene una explicación de cómo se realiza el cálculo. Espero eso ayude. cprogramming.language-tutorial.com/2012/01/…

    usuario1236102

    4 de marzo de 2012 a las 20:38

avatar de usuario
Eso es todo.

Según lo informado también por Wikipediaen 1990, Michael Keith y Tom Craver publicaron una expresión para minimizar la cantidad de pulsaciones de teclas necesarias para ingresar una función independiente para convertir una fecha gregoriana en un día numérico de la semana.

La expresión no conserva ni y ni dy devuelve un índice de base cero que representa el día, comenzando por el domingo, es decir, si el día es lunes, la expresión devuelve 1.

A continuación se muestra un ejemplo de código que utiliza la expresión:

int d    = 15   ; //Day     1-31
int m    = 5    ; //Month   1-12`
int y    = 2013 ; //Year    2013` 

int weekday  = (d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7;  

La expresión utiliza el operador de comacomo se discutió en esta respuesta.

¡Disfrutar! 😉

avatar de usuario
maéricos

Una sola línea es poco probable, pero el función de tiempo de ejecución se puede utilizar para analizar su formato de fecha y el struct tm El argumento puede ser consultado por su tm_wday miembro en sistemas que modifican esos campos automáticamente (por ejemplo, algunas implementaciones de glibc).

int get_weekday(char * str) {
  struct tm tm;
  memset((void *) &tm, 0, sizeof(tm));
  if (strptime(str, "%d-%m-%Y", &tm) != NULL) {
    time_t t = mktime(&tm);
    if (t >= 0) {
      return localtime(&t)->tm_wday; // Sunday=0, Monday=1, etc.
    }
  }
  return -1;
}

O podría codificar estas reglas para hacer algo de aritmética en una sola línea realmente larga:

  • El 1 de enero de 1900 fue un lunes.
  • Treinta días tiene septiembre, abril, junio y noviembre; todos los demás tienen treinta y uno, excepto febrero, que tiene veintiocho, llueva o truene, y en los años bisiestos, veintinueve.
  • Un año bisiesto ocurre en cualquier año divisible por 4, pero no en un siglo a menos que sea divisible por 400.

EDITAR: tenga en cuenta que esta solución solo funciona para fechas posteriores a la época de UNIX (1970-01-01T00:00:00Z).

avatar de usuario
pmg

Aquí hay una versión C99 basada en artículo de wikipedia sobre Julian Day

#include <stdio.h>

const char *wd(int year, int month, int day) {
  /* using C99 compound literals in a single line: notice the splicing */
  return ((const char *[])                                         \
          {"Monday", "Tuesday", "Wednesday",                       \
           "Thursday", "Friday", "Saturday", "Sunday"})[           \
      (                                                            \
          day                                                      \
        + ((153 * (month + 12 * ((14 - month) / 12) - 3) + 2) / 5) \
        + (365 * (year + 4800 - ((14 - month) / 12)))              \
        + ((year + 4800 - ((14 - month) / 12)) / 4)                \
        - ((year + 4800 - ((14 - month) / 12)) / 100)              \
        + ((year + 4800 - ((14 - month) / 12)) / 400)              \
        - 32045                                                    \
      ) % 7];
}

int main(void) {
  printf("%d-%02d-%02d: %s\n", 2011, 5, 19, wd(2011, 5, 19));
  printf("%d-%02d-%02d: %s\n", 2038, 1, 19, wd(2038, 1, 19));
  return 0;
}

Al eliminar el empalme y los espacios del return línea en la función wd(), se puede compactar en una sola línea de 286 caracteres 🙂

  • frio. Supongo que la fórmula JND utiliza algún conocimiento incorporado del día de la semana de cualquier otra fecha, como el 1 de enero de 4713 a. C. No creo que puedas hacerlo sin un ancla.

    – davka

    19 mayo 2011 a las 12:45

  • Sí, por supuesto. Lo principal es poder generar un valor secuencial para fechas sucesivas. Una vez que obtenga eso, “ajustará” el valor a una fecha conocida ajustando el -32045 parte del cálculo. Puede usar la misma fórmula con un valor de ajuste diferente y crear el “número de día davka” 🙂

    – pmg

    19 mayo 2011 a las 14:21

  • ¿Por qué diablos hay todas las barras invertidas al final de las líneas en el código? Ninguno de ellos es necesario; esto no es una macro, y no es una constante de cadena.

    –Jonathan Leffler

    25 de junio de 2014 a las 23:04

  • @JonathanLeffler: el operador quería “solo una línea de código C”

    – pmg

    7 julio 2014 a las 14:52

  • @DavidPetersonHarvey: tienes razón. No hay ninguna ventaja en la segunda versión. Eliminado (está en el historial de ediciones)

    – pmg

    4 de diciembre de 2018 a las 12:32

Esta es mi implementación. Es muy breve e incluye comprobación de errores. Si desea fechas anteriores al 01-01-1900, puede cambiar fácilmente el ancla a la fecha de inicio del calendario gregoriano.

#include <stdio.h>

int main(int argv, char** arv) {
    int month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    char* day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};   
    int d, m, y, i; 

    printf("Fill in a date after 01-01-1900 as dd-mm-yyyy: ");
    scanf("%d-%d-%d",  &d, &m, &y);

    // correction for leap year
    if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
        month[1] = 29;

    if (y < 1900 || m < 1 || m > 12 || d < 1 || d > month[m - 1]) {
        printf("This is an invalid date.\n");
        return 1;
    }

    for (i = 1900; i < y; i++)
        if (i % 4 == 0 && (i % 100 != 0 || i % 400 == 0))
            d += 366;
        else
            d += 365;

    for (i = 0; i < m - 1; i++) 
        d += month[i];

    printf("This is a %s.\n", day[d % 7]);
    return 0;
}

La respuesta que se me ocurrió:

const int16_t TM_MON_DAYS_ACCU[12] = {
    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};

int tm_is_leap_year(unsigned year) {
    return ((year & 3) == 0) && ((year % 400 == 0) || (year % 100 != 0));
}

// The "Doomsday" the the day of the week of March 0th,
// i.e the last day of February.
// In common years January 3rd has the same day of the week,
// and on leap years it's January 4th.
int tm_doomsday(int year) {
    int result;
    result  = TM_WDAY_TUE;
    result += year;       // I optimized the calculation a bit:
    result += year >>= 2; // result += year / 4
    result -= year /= 25; // result += year / 100
    result += year >>= 2; // result += year / 400
    return result;
}

void tm_get_wyday(int year, int mon, int mday, int *wday, int *yday) {
    int is_leap_year = tm_is_leap_year(year);
    // How many days passed since Jan 1st?
    *yday = TM_MON_DAYS_ACCU[mon] + mday + (mon <= TM_MON_FEB ? 0 : is_leap_year) - 1;
    // Which day of the week was Jan 1st of the given year?
    int jan1 = tm_doomsday(year) - 2 - is_leap_year;
    // Now just add these two values.
    *wday = (jan1 + *yday) % 7;
}

con estas definiciones (coincidencia struct tm de time.h):

#define TM_WDAY_SUN 0
#define TM_WDAY_MON 1
#define TM_WDAY_TUE 2
#define TM_WDAY_WED 3
#define TM_WDAY_THU 4
#define TM_WDAY_FRI 5
#define TM_WDAY_SAT 6

#define TM_MON_JAN  0
#define TM_MON_FEB  1
#define TM_MON_MAR  2
#define TM_MON_APR  3
#define TM_MON_MAY  4
#define TM_MON_JUN  5
#define TM_MON_JUL  6
#define TM_MON_AUG  7
#define TM_MON_SEP  8
#define TM_MON_OCT  9
#define TM_MON_NOV 10
#define TM_MON_DEC 11

avatar de usuario
AÑIL

#include<stdio.h>
#include<math.h>
#include<conio.h>
int fm(int date, int month, int year) {
int fmonth, leap;
if ((year % 100 == 0) && (year % 400 != 0))
leap = 0;
   else if (year % 4 == 0)
  leap = 1;
else
  leap = 0;

  fmonth = 3 + (2 - leap) * ((month + 2) / (2 * month))+ (5 * month + month / 9) / 2;

 fmonth = fmonth % 7;

  return fmonth;
}
int day_of_week(int date, int month, int year) {

   int dayOfWeek;
   int YY = year % 100;
   int century = year / 100;

   printf("\nDate: %d/%d/%d \n", date, month, year);

   dayOfWeek = 1.25 * YY + fm(date, month, year) + date - 2 * (century % 4);

   //remainder on division by 7
   dayOfWeek = dayOfWeek % 7;

   switch (dayOfWeek) {
      case 0:
         printf("weekday = Saturday");
         break;
      case 1:
         printf("weekday = Sunday");
         break;
      case 2:
         printf("weekday = Monday");
         break;
      case 3:
         printf("weekday = Tuesday");
         break;
      case 4:
         printf("weekday = Wednesday");
         break;
      case 5:
         printf("weekday = Thursday");
         break;
      case 6:
         printf("weekday = Friday");
         break;
      default:
         printf("Incorrect data");
   }
   return 0;
}
int main() {
   int date, month, year;

   printf("\nEnter the year ");
   scanf("%d", &year);

   printf("\nEnter the month ");
   scanf("%d", &month);

   printf("\nEnter the date ");
   scanf("%d", &date);

   day_of_week(date, month, year);

   return 0;
}

SALIDA: Introduzca el año 2012

Introduzca el mes 02

Introduce la fecha 29

Fecha: 29/2/2012

día de la semana = miércoles

avatar de usuario
Federico

Creo que puedes encontrar eso en glib:
http://developer.gnome.org/glib/unstable/glib-Date-and-Time-Functions.html#g-date-get-day

Saludos

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad