Converting Julian Date to Gregorian Date - C programming - c

I'm stuck on an assignment for C where I have to convert a Julian Date that is input by the user and convert it to Gregorian. When I run it and I enter a number for the Julian date all it prints out is 1, 0, -12 for the month, day and year. How to fix? I also don't completely understand pointers so maybe that is the problem?
#include <stdio.h>
#include <math.h>
void getDateFromJulian(double jd, int *month, int *day, int *year);
double getDoubleFromUser(char* msg);
int main() {
double jd = 0;
int month, day, year;
jd = getDoubleFromUser("Enter a valid Julian Day: ");
if (jd != -999.0) {
getDateFromJulian(jd, &month, &day, &year);
printf("Month, day, year is: %d, %d, %d \n", month, day, year);
}
return;
}
double getDoubleFromUser(char* msg){
int input;
int term;
//check for valid number
printf("Enter Julian Day: \n");
scanf_s("%1f%c");
if (scanf_s("%1f%c", &input, &term) != 2) {
if (term >= 0 * 41 && term <= 0 * (int)7) {
printf("That's not a valid number!\n");
return -999.0;
}
}
}
void getDateFromJulian(double jd, int *month, int *day, int *year) {
int A, B, C, D, E, alpha;
double Z, F;
int JD = 0;
F = modf(JD, &Z);
if (Z < 2299161) {
A = Z;
}
if (Z >= 2299161) {
alpha = (int)((Z - 1867216.25) / 36524.25);
A = Z + 1 + alpha - (int)(alpha / 4);
}
B = A + 1524;
C = (int)((B - 122.1) / 365.25);
D = (int)(365.25 * C);
E = (int)((B - D) / 30.6001);
day = B - D - (int)(30.6001 * E) + 0.5;
if (E < 14) {
month = E - 1;
}
if (E = 14 || 15) {
month = E - 13;
}
if (month > 2) {
year = C - 4716;
}
if (month = 1 || 2) {
year = C - 5715;
}
return;
}

When you assign to the day, month, or year you should do it as follows:
day[0] = B - D - (int)(30.6001 * E) + 0.5;
month[0] = E - 1;
and so on. Basically, you have to assign to the first element of the pointer (array) which is sometimes a little bit clearer than using an asterisk, which you left out.
The program effectively wasn't doing anything because the output values were essentially set to gibberish.

In addition to assigning integers to pointers (month = newVal; for example), some of your conditional tests are always true.
if (E = 14 || 15) {
month = newVal;
newVal = E - 13;
}
This assigns the value of 14 || 15 (which is 1) to E, and then tests that E is non-zero, which of course, it always is.
This test (and the other one like it) should be:
if (E == 14 || E == 15) {
*month = newVal;
newVal = E - 13;
}
Note that the newVal integer is assigned to the integer that is pointed to by month (by using *month), and not the actual pointer variable month. This remedy should be applied to assignments to the day and year pointers also.

Related

What is This Moon-Phase Calculation Function Doing?

I'm currently reading through the MEAP book Tiny C Projects by Dan Gookin. In the opening chapter he presents a small daily greeting program which also reports the phase of the moon. The calculations in the book for this look very strange - he also states outright that he doesn't know where he first got this code from or even what it's doing; it also doesn't have any comments or links to any other explanatory information. This is my cleaned-up rendition of it:
int moonphase_from_tm(struct tm* datetime)
{
int year = datetime->tm_year;
int month = datetime->tm_mon;
int day = datetime->tm_mday;
if (month == 2)
{
day += 31;
}
else if (month > 2)
{
day += 59 + (month - 3) * 30.6 + 0.5;
}
int g = year % 19;
int e = (11 * g + 29) % 30;
if (e == 25 || e == 24)
{
++e;
}
int phase = ((((e + day) * 6 + 5) % 177) / 22 & 7);
return phase;
}
It returns an int used to index a string out of a char* array describing the current moon phase.
Can anybody figure out what this is actually doing? I looked up moon phase calculations on Google and can't find anything that bears more than a passing resemblance to this. It also isn't entirely accurate with the entire thing being calculated with ints (it's out by a day or so, checking against some moon-phase tracking websites), which makes finding something similar a little more difficult.
Below is the original old-style version as reproduced in the book; when calling it, the author adds 1900 to the date, but then this is immediately subtracted again on line 13 when assigning to g, so I just didn't bother doing either:
int moonphase_book_verbatim(int year, int month, int day)
{
int d, g, e;
d = day;
if (month == 2)
{
d += 31;
}
else if (month > 2)
{
d += 59 + (month - 3) * 30.6 + 0.5;
}
g = (year - 1900) % 19;
e = (11 * g + 29) % 30;
if (e == 25 || e == 24)
{
++e;
}
return ((((e + d) * 6 + 5) % 177) / 22 & 7);
}

While return loop issue with function call in C

I´m Working on a program for a class and this is what I have so far. My buddy helped me with the function but when a wrong date is entered it should iterate until a correct date is asked. Not sure what to do we have been working on it for a few hours right now and since we are both new to C, we need some outside help.
#include <stdio.h> //for input output
#include <stdlib.h>
#include <string.h> // for string functions
#include <time.h> //for time functions
#include <stdbool.h> //bool functions for true/false
//used typedef for convenience, no need to type struct all the time
typedef struct
{
int m, d, y;
} Data_t;
int checkDate (int m, int d, int y); //declare function to check input
void modDate (Data_t * data); //declare function to modify date
int
main ()
{
int x = 0; //kill switch for while loop
//declare a struct variable and initialize it for the date
Data_t uDate = { 0, 0, 0 };
/* program has infinite loop bug when using the while loop with x */
while (x == 0){
printf ("x before input: %d\n", x); //debug printer
// Ask user for date input
printf ("Enter a date in mm/dd/yyyy format: ");
//Pass the input to the uDate struct with scanf
scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y);
// check data if valid and set x
x = checkDate (uDate.m, uDate.d, uDate.y);
printf ("x after check: %d\n", x); //debug printer
}
// end of while loop
// Display the entered date & modifier message
printf ("\nDate Entered: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
printf ("Adding 1 week to entered date...\n");
modDate (&uDate); //pass the address of uDate to the modDate function
/* since it was passed through a pointer (by reference),
the original uDate struct is now modified */
// Display the modified date
printf ("New Date is: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
return 0;
}
//Define the checkDate function
int
checkDate (int m, int d, int y)
{
// This is sloppy. Clean it up with multiple functions later
if (y <= 0)
{
printf ("Invalid Date, Please try again.\n");
return false;
}
if (m >= 1 && m <= 12)
{
//Then check the days against the months & leap years
if ((d >= 1 && d <= 31)
&& (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10
|| m == 12))
{
return true;
}
else if ((d >= 1 && d <= 30) && (m == 4 || m == 6 || m == 9 || m == 11))
{
return true;
}
else if ((d >= 1 && d <= 28) && (m == 2))
{
return true;
}
else if (d == 29 && m == 2
&& (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)))
{
return true;
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
//Define the modDate function to add 7 days
void
modDate (Data_t * data)
{
data->d = data->d + 7; // modify the day element in struct
// initialize the time_t structs from time.h and pass elements
struct tm t = {.tm_mon = data->m - 1,.tm_mday = data->d,
.tm_year = data->y - 1900
};
/* month+/-1 is because tm struct stores january as 0 and december as 11
year+/- 1900 is because year values are calculated starting from
the year 1900. So when calculating with mktime() you need to get
the integer value of the year by y-1900. And to properly display
the year value that is returned, you add 1900 as done below */
mktime (&t); // call mktime() to calculate the new date
// pass new values into struct and reformat month & year
data->m = t.tm_mon + 1;
data->d = t.tm_mday;
data->y = t.tm_year + 1900;
}
Your problem is that wrong input for scanf is not properly handled.
If you enter something like "A", scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y); won't be successful because it could not read any int that was expected.
Because your "A" is not properly processed it remains in your input buffer what will cause scanf to fail again and again.
So first you should check if all 3 expected values are read:
if (scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y) != 3)
// x remains 0
printf("Invalid input format!\n");
else
x = checkDate (uDate.m, uDate.d, uDate.y);
This alone would not be enough because the wrong input still remains in your input buffer. So you need to flush it before you are making the next try:
Edit
As #AndrewHenle pointed out you should avoid using fflush(stdin) (at least if you are not on a windows platform and want to keep your code portable).
So another solution is to read every input including newline character after user input with e.g. while((getchar()) != '\n');
if (scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y) != 3)
// x remains 0
printf("Invalid input format!\n");
else
x = checkDate (uDate.m, uDate.d, uDate.y);
// flush input buffer
while((getchar()) != '\n');
You have declared return type of int checkDate (int m, int d, int y); as int but return a bool. When correcting this to bool checkDate (int m, int d, int y); the code seems to work:
#include <stdio.h> //for input output
#include <stdlib.h>
#include <string.h> // for string functions
#include <time.h> //for time functions
#include <stdbool.h> //bool functions for true/false
//used typedef for convenience, no need to type struct all the time
typedef struct
{
int m, d, y;
} Data_t;
bool checkDate (int m, int d, int y); //declare function to check input
void modDate (Data_t * data); //declare function to modify date
int
main ()
{
bool x = false; //kill switch for while loop
//declare a struct variable and initialize it for the date
Data_t uDate = { 0, 0, 0 };
/* program has infinite loop bug when using the while loop with x */
while (x == false){
printf ("x before input: %d\n", x); //debug printer
// Ask user for date input
printf ("Enter a date in mm/dd/yyyy format: ");
//Pass the input to the uDate struct with scanf
scanf ("%d/%d/%d", &uDate.m, &uDate.d, &uDate.y);
// check data if valid and set x
x = checkDate (uDate.m, uDate.d, uDate.y);
printf ("x after check: %d\n", x); //debug printer
}
// end of while loop
// Display the entered date & modifier message
printf ("\nDate Entered: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
printf ("Adding 1 week to entered date...\n");
modDate (&uDate); //pass the address of uDate to the modDate function
/* since it was passed through a pointer (by reference),
the original uDate struct is now modified */
// Display the modified date
printf ("New Date is: %d/%d/%d\n", uDate.m, uDate.d, uDate.y);
return 0;
}
//Define the checkDate function
bool
checkDate (int m, int d, int y)
{
// This is sloppy. Clean it up with multiple functions later
if (y <= 0)
{
printf ("Invalid Date, Please try again.\n");
return false;
}
if (m >= 1 && m <= 12)
{
//Then check the days against the months & leap years
if ((d >= 1 && d <= 31)
&& (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10
|| m == 12))
{
return true;
}
else if ((d >= 1 && d <= 30) && (m == 4 || m == 6 || m == 9 || m == 11))
{
return true;
}
else if ((d >= 1 && d <= 28) && (m == 2))
{
return true;
}
else if (d == 29 && m == 2
&& (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)))
{
return true;
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
else
{
printf ("Invalid Date, Please try again.\n");
return false;
}
}
//Define the modDate function to add 7 days
void
modDate (Data_t * data)
{
data->d = data->d + 7; // modify the day element in struct
// initialize the time_t structs from time.h and pass elements
struct tm t = {.tm_mon = data->m - 1,.tm_mday = data->d,
.tm_year = data->y - 1900
};
/* month+/-1 is because tm struct stores january as 0 and december as 11
year+/- 1900 is because year values are calculated starting from
the year 1900. So when calculating with mktime() you need to get
the integer value of the year by y-1900. And to properly display
the year value that is returned, you add 1900 as done below */
mktime (&t); // call mktime() to calculate the new date
// pass new values into struct and reformat month & year
data->m = t.tm_mon + 1;
data->d = t.tm_mday;
data->y = t.tm_year + 1900;
}

Print a calendar by input character month and integer year

I've write the code to print the one month calendar by input of integer month and integer year. But I want to input the month by characters, first three letters of the month word like Jan for January and Feb For February.As Shown in the picture the month is entered by characters. Here is the Image. So please change the code, so I can input the month in character.Thanks
#include <stdio.h>
int isLeapYear(int y); /* True if leap year */
int leapYears(int y); /* The number of leap year */
int todayOf(int y, int m, int d); /* The number of days since the beginning
of the year */
long days(int y, int m, int d); /* Total number of days */
void calendar(int y, int m); /* display calendar at m y */
int main(void) {
int year, month;
printf("Enter the month and year: ");
scanf("%d %d", &month, &year);
calendar(year, month);
return 0;
}
int isLeapYear(int y) /* True if leap year */
{
return(y % 400 == 0) || ((y % 4 == 0) && (y % 100 != 0));
}
int leapYears(int y) /* The number of leap year */
{
return y / 4 - y / 100 + y / 400;
}
int todayOf(int y, int m, int d) /* The number of days since the beginning
of the year */
{
static int DayOfMonth[] =
{ -1/*dummy*/,0,31,59,90,120,151,181,212,243,273,304,334 };
return DayOfMonth[m] + d + ((m>2 && isLeapYear(y)) ? 1 : 0);
}
long days(int y, int m, int d) /* Total number of days */
{
int lastYear;
lastYear = y - 1;
return 365Q * lastYear + leapYears(lastYear) + todayOf(y, m, d);
}
void calendar(int y, int m) /* display calendar at m y */
{
const char *NameOfMonth[] = { NULL/*dummp*/,
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
char Week[] = "Su Mo Tu We Th Fr Sa";
int DayOfMonth[] =
{ -1/*dummy*/,31,28,31,30,31,30,31,31,30,31,30,31 };
int weekOfTopDay;
int i, day;
weekOfTopDay = days(y, m, 1) % 7;
if (isLeapYear(y))
DayOfMonth[2] = 29;
printf("\n %s %d\n%s\n", NameOfMonth[m], y, Week);
for (i = 0; i<weekOfTopDay; i++)
printf(" ");
for (i = weekOfTopDay, day = 1; day <= DayOfMonth[m]; i++, day++) {
printf("%2d ", day);
if (i % 7 == 6)
printf("\n");
}
printf("\n");
}
There are many way to do this. They usually involve taking the input string and looking up in some table.
An efficient way is to compute a hash based on the string input rather than do up to 12 string compares. Use the hash to look that month name and see if it matches. The hash below requires ASCII encoding for the month names. char may be signed or unsigned.
Of course if the month names change (another language?), the specific values and hash method below need adjustment.
// Assume month is any 3 ASCII characters (either case)
int month2int_chux(const char *month) {
if (month[0] && month[1] && month[2]) {
unsigned m0 = month[0] | 0x20;
unsigned m1 = month[1] | 0x20;
unsigned m2 = month[2] | 0x20;
unsigned m = (14 * m2) ^ (47 * m1); // magic computation does not use m0.
m %= 13;
const unsigned char hash[] = { 9, 11, 5, 12, 0, 7, 2, 1, 3, 4, 8, 10, 6 };
m = hash[m % 13u];
if (m && (NameOfMonth[m][0] | 0x20) == m0 &&
NameOfMonth[m][1] == m1 && NameOfMonth[m][2] == m2) {
return m;
}
}
return 0;
}

Why am I getting these random values?

Ok, so I have to write a function that uses pointers to convert days into years, weeks, and days. Here is the function.
int convertTime(int days, int *y, int *w, int *d){
if (days < 0 || y == NULL || w == NULL || d == NULL){
printf("An error has occured\n");
return 1;
}else{
*y = days / 365;
*w = (days % 365) / 7;
*d = ((days % 365) / 7) % 7)
return 0;
}
}
and here is the part in the main function where I am calling it.
// Tests convertTime
int days = 1000;
int y2 = 0, w2 = 0, d2 = 0;
int *y = NULL, *w = NULL, *d = NULL;
y = &y2, w = &w2, d = &d2;
convertTime(days, y, w, d);
printf("Expected output: 2 years, 38 weeks, 4 days\n");
printf("Actual output: %d years, %d, weeks, %d days\n");
and it prints out
Expected output: 2 years, 38 weeks, 4 days
Actual output: -127184896 years, -132560896, weeks, -135499072 days
You forgot to pass your variables to printf. Fix the last line like this:
printf("Actual output: %d years, %d, weeks, %d days\n", y2, w2, d2);
As stated in the other answer you need to pass in the values to the printf.
Also you need to check the return value for convertTime

C Program to find day of week given date

Is there a way to find out day of the week given date in just one line of C code?
For example
Given 19-05-2011(dd-mm-yyyy) gives me Thursday
As reported also by Wikipedia, in 1990 Michael Keith and Tom Craver published an expression to minimise the number of keystrokes needed to enter a self-contained function for converting a Gregorian date into a numerical day of the week.
The expression does preserve neither y nor d, and returns a zero-based index representing the day, starting with Sunday, i.e. if the day is Monday the expression returns 1.
A code example which uses the expression follows:
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;
The expression uses the comma operator, as discussed in this answer.
Enjoy! ;-)
A one-liner is unlikely, but the strptime function can be used to parse your date format and the struct tm argument can be queried for its tm_wday member on systems that modify those fields automatically (e.g. some glibc implementations).
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;
}
Or you could encode these rules to do some arithmetic in a really long single line:
1 Jan 1900 was a Monday.
Thirty days has September, April, June and November; all the rest have thirty-one, saving February alone, which has twenty-eight, rain or shine, and on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
EDIT: note that this solution only works for dates after the UNIX epoch (1970-01-01T00:00:00Z).
Here's a C99 version based on wikipedia's article about 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;
}
By removing the splicing and spaces from the return line in the wd() function, it can be compacted to a 286 character single line :)
This is my implementation. It's very short and includes error checking. If you want dates before 01-01-1900, you could easily change the anchor to the starting date of the Gregorian calendar.
#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;
}
The answer I came up with:
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;
}
with these defines (matching struct tm of 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
#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;
}
OUTPUT:
Enter the year 2012
Enter the month 02
Enter the date 29
Date: 29/2/2012
weekday = Wednesday
This is question 20.31 in the C FAQ list. It lists three answers, two of which are amenable to one-liners.
Modified Zeller's congruence: j = y/100; k = y%100; dow = (d + 26 * (m + 1) / 10 + k + k/4 + j/4 + 5*j) % 7;
Tomohiko Sakamoto's method: static int t[] = {0,3,2,5,0,3,5,1,4,6,2,4}; y -= m < 3; dow = (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
There's a further condensation of Sakamoto's method using an ASCII string instead of the t array: dow = (y + y/4 - y/100 + y/400 + "-bed=pen+mad."[m] + d) % 7;
The basic idea underlying all of these methods is the same: boil the date down to a monotonically-increasing sequence of day numbers (taking month lengths and leap years into account), then reduce that day number modulo 7.
I think you can find that in glib:
http://developer.gnome.org/glib/unstable/glib-Date-and-Time-Functions.html#g-date-get-day
Regards
#include<stdio.h>
static char day_tab[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 main()
{
int year,month;
scanf("%d%d%d",&year,&month,&day);
printf("%d\n",day_of_year(year,month,day));
return 0;
}
int day_of_year(int year ,int month,int day)
{
int i,leap;
leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
if(month < 1 || month >12)
return -1;
if (day <1 || day > day_tab[leap][month])
return -1;
for(i= 1;i<month ; i++)
{
day += day_tab[leap][year];
}
return day;
}
/*
Program to calculate the day on a given date by User
*/
#include<stdio.h>
#include<conio.h>
#include<process.h>
void main()
{
int dd=0,mm=0,i=0,yy=0,odd1=0,todd=0;//variable declaration for inputing the date
int remyr=0,remyr1=0,lyrs=0,oyrs=0,cyr=0,upyr=0,leap=0;//variable declaration for calculation of odd days
int montharr[12]={31,28,31,30,31,30,31,31,30,31,30,31};//array of month days
clrscr();
printf("Enter the date as DD-MM-YY for which you want to know the day\t:");
scanf("%d%d%d",&dd,&mm,&yy); //input the date
/*
check out correct date or not?
*/
if(yy%100==0)
{
if(yy%400==0)
{
//its the leap year
leap=1;
if(dd>29&&mm==2)
{
printf("You have entered wrong date");
getch();
exit(0);
}
}
else if(dd>28&&mm==2)
{
//not the leap year
printf("You have entered wrong date");
getch();
exit(0);
}
}
else if(yy%4==0)
{
//again leap year
leap=1;
if(dd>29&mm==2)
{
printf("You have entered wrong date");
getch();
exit(0);
}
}
else if(dd>28&&mm==2)
{
//not the leap year
printf("You have entered wrong date");
getch();
exit(0);
}
//if the leap year feb month contains 29 days
if(leap==1)
{
montharr[1]=29;
}
//check date,month,year should not be beyond the limits
if((mm>12)||(dd>31)|| (yy>5000))
{
printf("Your date is wrong");
getch();
exit(0);
}
//odd months should not contain more than 31 days
if((dd>31 && (mm == 1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12)))
{
printf("Your date is wrong");
getch();
exit(0);
}
//even months should not contains more than 30 days
if((dd>30 && (mm == 4||mm==6||mm==9||mm==11)))
{
printf("Your date is wrong");
getch();
exit(0);
}
//logic to calculate odd days.....
printf("\nYou have entered date: %d-%d-%d ",dd,mm,yy);
remyr1=yy-1;
remyr=remyr1%400;
cyr=remyr/100;
if(remyr==0)
{
oyrs=0;
}
else if(cyr==0 && remyr>0)
{
oyrs=0;
}
else if(cyr==1)
{
oyrs=5;
}
else if(cyr==2)
{
oyrs=3;
}
else if(cyr==3)
{
oyrs=1;
}
upyr=remyr%100;
lyrs=upyr/4;
odd1=lyrs+upyr;
odd1=odd1%7;
odd1=odd1+oyrs;
for(i=0;i<mm-1;i++)
{
odd1=odd1+montharr[i];
}
todd=odd1+dd;
if(todd>7)
todd=todd%7; //total odd days gives the re quired day....
printf("\n\nThe day on %d-%d-%d :",dd,mm,yy);
if(todd==0)
printf("Sunday");
if(todd==1)
printf("Monday");
if(todd==2)
printf("Tuesday");
if(todd==3)
printf("Wednesday");
if(todd==4)
printf("Thrusday");
if(todd==5)
printf("Friday");
if(todd==6)
printf("Saturday");
getch();
}
For Day of Week, years 2000 - 2099.
uint8_t rtc_DayOfWeek(uint8_t year, uint8_t month, uint8_t day)
{
//static const uint8_t month_offset_table[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; // Typical table.
// Added 1 to Jan, Feb. Subtracted 1 from each instead of adding 6 in calc below.
static const uint8_t month_offset_table[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
// Year is 0 - 99, representing years 2000 - 2099
// Month starts at 0.
// Day starts at 1.
// Subtract 1 in calc for Jan, Feb, only in leap years.
// Subtracting 1 from year has the effect of subtracting 2 in leap years, subtracting 1 otherwise.
// Adding 1 for Jan, Feb in Month Table so calc ends up subtracting 1 for Jan, Feb, only in leap years.
// All of this complication to avoid the check if it is a leap year.
if (month < 2) {
year--;
}
// Century constant is 6. Subtract 1 from Month Table, so difference is 7.
// Sunday (0), Monday (1) ...
return (day + month_offset_table[month] + year + (year >> 2)) % 7;
} /* end rtc_DayOfWeek() */
This one works: I took January 2006 as a reference. (It is a Sunday)
int isLeapYear(int year) {
if(((year%4==0)&&(year%100!=0))||((year%400==0)))
return 1;
else
return 0;
}
int isDateValid(int dd,int mm,int yyyy) {
int isValid=-1;
if(mm<0||mm>12) {
isValid=-1;
}
else {
if((mm==1)||(mm==3)||(mm==5)||(mm==7)||(mm==8)||(mm==10)||(mm==12)) {
if((dd>0)&&(dd<=31))
isValid=1;
} else if((mm==4)||(mm==6)||(mm==9)||(mm==11)) {
if((dd>0)&&(dd<=30))
isValid=1;
} else {
if(isLeapYear(yyyy)){
if((dd>0)&&dd<30)
isValid=1;
} else {
if((dd>0)&&dd<29)
isValid=1;
}
}
}
return isValid;
}
int calculateDayOfWeek(int dd,int mm,int yyyy) {
if(isDateValid(dd,mm,yyyy)==-1) {
return -1;
}
int days=0;
int i;
for(i=yyyy-1;i>=2006;i--) {
days+=(365+isLeapYear(i));
}
printf("days after years is %d\n",days);
for(i=mm-1;i>0;i--) {
if((i==1)||(i==3)||(i==5)||(i==7)||(i==8)||(i==10)) {
days+=31;
}
else if((i==4)||(i==6)||(i==9)||(i==11)) {
days+=30;
} else {
days+= (28+isLeapYear(i));
}
}
printf("days after months is %d\n",days);
days+=dd;
printf("days after days is %d\n",days);
return ((days-1)%7);
}
Here is a simple code that I created in c that should fix your problem :
#include <conio.h>
int main()
{
int y,n,oy,ly,td,a,month,mon_,d,days,down,up; // oy==ordinary year, td=total days, d=date
printf("Enter the year,month,date: ");
scanf("%d%d%d",&y,&month,&d);
n= y-1; //here we subtracted one year because we have to find on a particular day of that year, so we will not count whole year.
oy= n%4;
if(oy==0) // for leap year
{
mon_= month-1;
down= mon_/2; //down means months containing 30 days.
up= mon_-down; // up means months containing 31 days.
if(mon_>=2)
{
days=(up*31)+((down-1)*30)+29+d; // here in down case one month will be of feb so we subtracted 1 and after that seperately
td= (oy*365)+(ly*366)+days; // added 29 days as it is the if block of leap year case.
}
if(mon_==1)
{
days=(up*31)+d;
td= (oy*365)+(ly*366)+days;
}
if(mon_==0)
{
days= d;
td= (oy*365)+(ly*366)+days;
}
}
else
{
mon_= month-1;
down= mon_/2;
up= mon_-down;
if(mon_>=2)
{
days=(up*31)+((down-1)*30)+28+d;
td= (oy*365)+(ly*366)+days;
}
if(mon_==1)
{
days=(up*31)+d;
td= (oy*365)+(ly*366)+days;
}
if(mon_==0)
{
days= d;
td= (oy*365)+(ly*366)+days;
}
}
ly= n/4;
a= td%7;
if(a==0)
printf("\nSunday");
if(a==1)
printf("\nMonday");
if(a==2)
printf("\nTuesday");
if(a==3)
printf("\nWednesday");
if(a==4)
printf("\nThursday");
if(a==5)
printf("\nFriday");
if(a==6)
printf("\nSaturday");
return 0;
}
I wrote a small function to do this in C inspired by Conway's doomsday algorithm.
It was written with 8-bit microcontrollers in mind and the "year" argument is a year from 0 to 99 only (representing 2000 to 2099). I wrote it to compile down nice and small on avr-gcc. It uses no lookup table (I got the code smaller without).
// day of week, Thomas Rutter
// y should be a year 0 to 99 (meaning 2000 to 2099)
// m and d are 1-based (1-12, 1-31)
// returns 0 = sunday, ..., 6 = saturday
uint8_t dayofweek(uint8_t y, uint8_t m, uint8_t d)
{
uint8_t x = y + 24 - (m < 3);
x = x + (x >> 2) + d - m;
if (m & 1)
x += (m & 8) ? 4 : 3;
if (m < 3)
x += 3;
return x % 7;
}
In my own version, the mod operator at the bottom was replaced with my own optimised code as the platform I was using has no MUL or DIV and I wanted it 1 to 7 instead of 0 to 6.
This could be adapted to work with other centuries or specify the year in full - I just didn't need to do so for my own use.
See strftime and %u or %w qualifiers
#include<stdio.h>
int main(void) {
int n,y;
int ly=0;
int mon;
printf("enter the date\n");
scanf("%d",&n);
printf("enter the month in integer\n");
scanf("%d",&mon);
mon=mon-1;
printf("enter year\n");
scanf("%d",&y);
int dayT;
dayT=n%7;
if((y%4==0&&y%100!=0)|(y%4==0&&y%100==0&&y%400==0))
{
ly=y;
printf("the given year is a leap year\n");
}
char a[12]={6,2,2,5,0,3,5,1,4,6,2,4};
if(ly!=0)
{
a[0]=5;
a[1]=1;
}
int m,p;
m=a[mon];
int i,j=0,t=1;
for(i=1600;i<=3000;i++)
{
i=i+99;
if(i<y)
{
if(t==1)
{
p=5;t++;
}
else if(t==2)
{
p=3;
t++;
}
else if(t==3)
{
p=1;
t++;
}
else
{
p=0;
t=1;
}
}}
int q,r,s;
q=y%100;
r=q%7;
s=q/4;
int yTerm;
yTerm=p+r+s;
int w=dayT+m+yTerm;
w=w%7;
if(w==0)
printf("SUNDAY");
else if(w==1)
printf("MONDAY");
else if(w==2)
printf("TUESDAY");
else if(w==3)
printf("WEDNESDAY");
else if(w==4)
printf("THURSDAY");
else if(w==5)
printf("FRIDAY");
else
printf("SATURDAY");
return 0;
}

Resources