calculate a date given day of year and year - c

I am trying to write a program in C given these two data sets from a user. Year:[Range 1901-2099] and Day in year: [range 1-366] I need a formula to calculate the date in MM/DD/YYYY format. One more thing. No IF/ELSE statements. No AND/OR or GREATER THAN or LESS THAN are allowed.

You can use nested switch case to avoid using if-else.
Find out whether it is a leap year or not.
Create four buckets of months (1-99), (100-199).. etc. Bucket numbers will be used as case numbers.
Now check the left most bit of the day, and write a switch case for assigning it into the right bucket.
Each bucket could be divided into 4 more buckets too (the leap year information will be used).
Repeat step 3 for the middle bit and based on the result (case) switch to appropriate bucket.
Briefly, logic could be as follows:
isLeapYear = year % 4
Switch(isLeapYear)
Case 0: {
first_bucket = days/4
Switch(first_bucket)
{
Case 0: {
days_left = days % 100
second_bucket = days / 50;
// ...
// ...
}
Case 1, 2, 3: {
// Similar logic for non-leap year
// ...
}

You can do it without any kind of flow control statements (if, switch) and without doing leap year calculation yourself. Get the timestamp corresponding to January 1st of the desired year. Then, you can use a single addition on the timestamp to get to the correct day, and convert the timestamp to whatever format you want.
I would provide code, specific function names and explain what you need to add to the timestamp, but since this is obviously a homework question, I won't. If anyone reminds me in two weeks (i.e. when the deadline for the assignment is most likely over) I'll happily post example code.

In case library functions were allowed to be used (which I doubt) I'd do it this (lazy lego) way:
#define _XOPEN_SOURCE /* glibc2 needs this for strptime */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
int to_date(
char * date,
const size_t size,
const char * fmt,
const short unsigned int day_of_year,
const short unsigned int year)
{
char buffer[16] = "";
sprintf(buffer, "%hu %hu", day_of_year, year);
{
struct tm t = {0};
char * presult = strptime(buffer, "%j %Y", &t);
if ((NULL == presult) || ('\0' != *presult))
{
errno = EINVAL;
return -1;
}
strftime(date, size, fmt, &t);
}
return 0;
}
int main(int argc, char ** argv)
{
if (2 > argc)
{
fprintf(stderr, "Missing arguments. Usage: %s day-of-year year\n", argv[0]);
return EXIT_FAILURE;
}
short unsigned int day_of_year = atoi(argv[1]);
short unsigned int year = atoi(argv[2]);
char date[16] = "";
if (-1 == to_date(date, sizeof(date), "%m/%d/%Y", day_of_year, year))
{
perror("to_date() failed");
return EXIT_FAILURE;
}
printf("Result: day %d of year %d is '%s'.\n", day_of_year, year, date);
return EXIT_SUCCESS;
}
Call it like this
$ ./main 2 2000
to get
Result: day 2 of year 2000 is '01/02/2000'.

For years 1901 to 2099, can easily be done using time functions.
void Makedate(int year, int day, struct tm *dest) {
struct tm tm1 = { 0 };
// Leap year every 4 years, lets do calc referencing 2000-2003
tm1.tm_year = 2000 - 1900 + year % 4;
tm1.tm_mday = day; // Make the Jan 1st to Jan 366th. OK to be out of range.
// Avoid day changes due to DST by using Noon. BTW I doubt this is needed (CYA)
tm1.tm_hour = 12;
// mktime adjusts our fields for us, setting the month, mday, dow, etc.
mktime(&tm1);
tm1.tm_year = year - 1900; // set to selected year
*dest = tm1;
}
int main() {
struct tm tm0;
Makedate(2013, 1, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
Makedate(2013, 365, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
Makedate(2020, 1, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
Makedate(2020, 366, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
return 0;
}
y:2013 m: 1 d: 1
y:2013 m:12 d:31
y:2020 m: 1 d: 1
y:2020 m:12 d:31

Related

C - How to get dates in a week from only weeknumber and year?

I would like the function to return an array of strings where each date is reprsented as "13/11" or any other format from where i can pull both the date and month.
Maybe it would look something like this:
char** get_dates_from_year_and_week(int year, int week) {
//Magic happens
return arr
}
get_dates_from_year_and_week(2021, 45);
//Would return ["08/11", "09/11", 10/11", "11/11", "12/11", "13/11", "14/11"];
How could this possible be obtained using c? Any library is welcome.
To covert the year/week/(day-of-the-week) to a year/month/day, find the date of the first Monday of the year as ISO 8601 week-of-the-year begins on a Monday. Then add week*7 days to that. Use mktime() to determine day-of the-week (since Sunday) and to bring an out-of-range date into its primary range.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
int year, month, day;
} ymd;
typedef struct {
int year, week, dow; // ISO week-date: year, week 1-52,53, day-of-the-week 1-7
} ISO_week_date;
int ISO_week_date_to_ymd(ymd *y, const ISO_week_date *x) {
// Set to noon, Jan 4 of the year.
// Jan 4 is always in the 1st week of the year
struct tm tm = {.tm_year = x->year - 1900, .tm_mon = 0, .tm_mday = 4,
.tm_hour = 12};
// Use mktime() to find the day-of-the week
if (mktime(&tm) == -1) {
return -1;
}
// Sunday to Jan 4
int DaysSinceSunday = tm.tm_wday;
// Monday to Jan 4
int DaysSinceMonday = (DaysSinceSunday + (7 - 1)) % 7;
tm.tm_mday += (x->dow - 1) + (x->week - 1) * 7 - DaysSinceMonday;
if (mktime(&tm) == -1) {
return -1;
}
y->year = tm.tm_year + 1900;
y->month = tm.tm_mon + 1;
y->day = tm.tm_mday;
return 0;
}
"array of strings" --> leave that part for OP to do.

Calculate number of days elapsed from epoch - formula based

I am trying to calculate number of days elapsed from a given GMT time.
Well, I am able to make it work with iterative approach of calculation (finding number of normal years
and leap years)
The function get_number_of_leap_years_from_base_year is iterating over all the years from 1970 till the given date and checking every year whether its a leap or not and finally add all days.
Is there any other way (formula) based to calculating number normal & leap years elapsed.
/* so-prg-2: Calculating number normal & leap years passed */
#include <stdio.h>
#include <string.h>
#include <time.h>
#define BASE_YEAR 1970
void print_time_readable_format(struct tm tm);
int convert_gmt_date_time_to_tm_format(char* gmt_time_fmt);
int get_number_of_leap_years_from_base_year(int start_year, int end_year);
int calculate_days_elapsed_from_epoch(struct tm tm);
int main()
{
int days = 0;
char gmt_time_fmt[] = "Dec 28 18:40:01 2020 GMT";
//char gmt_time_fmt[] = "Jan 20 19:00:01 2019 GMT";
//char gmt_time_fmt[] = "Dec 27 14:52:30 2020 GMT";
//char gmt_time_fmt[] = "Jan 01 00:00:01 1970 GMT";
days = convert_gmt_date_time_to_tm_format(gmt_time_fmt);
printf("GMT = %s and days are %d\n", gmt_time_fmt, days);
return 0;
}
int convert_gmt_date_time_to_tm_format(char* gmt_time_fmt)
{
struct tm tm;
char tm_time_fmt[255];
//set tm struture to 0
memset(&tm, 0, sizeof(struct tm));
// convert gmt_time_fmt to format required by 'tm' structure
strptime(gmt_time_fmt, "%B %d %H:%M:%S %Y GMT", &tm);
strftime(tm_time_fmt, sizeof(tm_time_fmt), "%s", &tm);
printf("tm_time_fmt = %s\n", tm_time_fmt);
print_time_readable_format(tm);
return calculate_days_elapsed_from_epoch(tm);
}
int calculate_days_elapsed_from_epoch(struct tm tm)
{
int days_by_month [2][12] = {
/* normal years */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
/* leap years */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
};
int current_year = tm.tm_year+1900;
int total_years_passed = current_year - BASE_YEAR;
/* -1, to skip the current year */
int nleap_years_passed = get_number_of_leap_years_from_base_year(BASE_YEAR, current_year-1);
int normal_years = total_years_passed - nleap_years_passed;
int total_days_passed = (normal_years*365 + nleap_years_passed*366 );
printf(" **Years total_days_passed =%d\n", total_days_passed);
total_days_passed += days_by_month[(current_year%4 == 0) - (current_year%100 == 0) + (current_year%400 == 0)][tm.tm_mon];
total_days_passed += tm.tm_mday - 1; /* to skip the current day */
printf(" **total_days_passed =%d\n", total_days_passed);
return total_days_passed;
}
int get_number_of_leap_years_from_base_year(int start_year, int end_year)
{
int leap_year_count = 0;
int year = start_year;
while( year <= end_year)
{
if( (year%4 == 0) - (year%100 == 0) + (year%400 == 0) )
leap_year_count++;
year++;
}
printf("leap_year_count = %d\n", leap_year_count);
return leap_year_count;
}
void print_time_readable_format(struct tm tm)
{
printf("tm.tm_year = %d ", tm.tm_year);
printf("tm.tm_mon = %d ", tm.tm_mon);
printf("tm.tm_mday = %d ",tm.tm_mday);
printf("tm.tm_hour = %d ", tm.tm_hour);
printf("tm.tm_min = %d ", tm.tm_min );
printf("tm.tm_sec = %d\n", tm.tm_sec );
}
Use mktime()
Since your code is allowed to use both Standard C strftime() and POSIX strptime(), there's no reason not to use Standard C mktime() either.
It gives you a time_t value which is the number of seconds since The Epoch.
int calculate_days_elapsed_from_epoch(struct tm tm)
{
time_t t = mktime(&tm);
return t / 86400; // 24 * 60 * 60 = 86400
}
But if the goal is to calculate the seconds since The Epoch, you have the answer immediately from mktime().
Note that mktime() is passed a struct tm pointer, and it accepts values that are 'out of range' and normalizes the result. See also the example code in the section 'Demonstrating mktime()'.
Calculating leap days
I have a function jl_dmy_conversion() lurking in my library which converts a combination of year, month, day to a number of days since 1899-12-31 (so in this system, day 1 was 1900-01-01). But it includes a calculation for number of leap days. This code is internal to a package where the parameters are already validated as valid within the date range 0001-01-01 .. 9999-12-31, so it does not do much to protect itself from invalid data. There is another function that invokes this that does the data validation. Some of the information shown here comes from a header, most from the source file containing the implementation.
typedef int Date;
enum { DATE_NULL = -2147483648 }; /* Informix NULL DATE */
#define LEAPYEAR(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#define PRId_Date "d"
/*
** In 400 years, there are 97 leap years (because the three years
** divisible by 100 but not by 400 are not leap years). This also
** happens to be exactly 20871 weeks.
*/
#define DAYS_IN_400_YEARS (400*365+97)
#define DAYS_IN_2000_YEARS (5*DAYS_IN_400_YEARS)
enum
{
DAYS_IN_JANUARY = 31,
DAYS_IN_FEBRUARY = 28,
DAYS_IN_MARCH = 31,
DAYS_IN_APRIL = 30,
DAYS_IN_MAY = 31,
DAYS_IN_JUNE = 30,
DAYS_IN_JULY = 31,
DAYS_IN_AUGUST = 31,
DAYS_IN_SEPTEMBER = 30,
DAYS_IN_OCTOBER = 31,
DAYS_IN_NOVEMBER = 30,
DAYS_IN_DECEMBER = 31
};
static const int days_in_month[][2] =
{
{ 0, 0 },
{ DAYS_IN_JANUARY, DAYS_IN_JANUARY },
{ DAYS_IN_FEBRUARY, DAYS_IN_FEBRUARY+1 },
{ DAYS_IN_MARCH, DAYS_IN_MARCH },
{ DAYS_IN_APRIL, DAYS_IN_APRIL },
{ DAYS_IN_MAY, DAYS_IN_MAY },
{ DAYS_IN_JUNE, DAYS_IN_JUNE },
{ DAYS_IN_JULY, DAYS_IN_JULY },
{ DAYS_IN_AUGUST, DAYS_IN_AUGUST },
{ DAYS_IN_SEPTEMBER, DAYS_IN_SEPTEMBER },
{ DAYS_IN_OCTOBER, DAYS_IN_OCTOBER },
{ DAYS_IN_NOVEMBER, DAYS_IN_NOVEMBER },
{ DAYS_IN_DECEMBER, DAYS_IN_DECEMBER }
};
/* Return date as number of days since 31st December 1899 - no range check */
static Date jl_dmy_conversion(int d, int m, int y)
{
int leap;
int i;
Date daynum;
/* No need to assert here - calling functions have checked basics */
DB_TRACE(1, "[[-- jl_dmy_conversion (d = %2d, m = %2d, y = %4d) ", d, m, y);
leap = LEAPYEAR(y);
if (d > days_in_month[m][leap])
{
DB_TRACE(1, "<<-- NULL (invalid day of month)\n");
return(DATE_NULL);
}
/* Number of days so far this month */
daynum = d;
/* Days so far this year prior to this month */
for (i = 1; i < m; i++)
daynum += days_in_month[i][leap];
DB_TRACE(4, "YDAY = %3ld ", daynum);
/*
** Now compute number of days to 1st of January of this year. Add
** 2000 years (5 periods of 400 years) to ensure that numbers
** resulting from subtraction are positive, even when dates back to
** 0001-01-01 are allowed, and then remove the number of days found
** in 2000 years. This assumes int is 32-bit or longer.
**
** NB: Things begin to go haywire when (y - 1901) yields -4, which
** is when y == 1897. Things get worse before 1601. The result is
** usually, but not always, off by one. Adding 2000 years and then
** subtracting the appropriate number of days sidesteps the
** problems.
*/
y += 2000;
daynum += 365 * (y - 1900); /* Ignoring leap years */
DB_TRACE(4, "INC1 = %7d ", 365 * (y - 1900));
daynum += (y - 1901) / 4; /* Allowing for leap years */
DB_TRACE(4, "INC2 = %4d ", (y - 1901) / 4);
daynum -= (y - 1901) / 100; /* Allowing for non-leap years */
DB_TRACE(4, "INC3 = %3d ", -(y - 1901) / 100);
daynum += (y - 1601) / 400; /* Allowing for leap years */
DB_TRACE(4, "INC4 = %2d ", (y - 1601) / 400);
daynum -= DAYS_IN_2000_YEARS;
DB_TRACE(1, " (r = %7" PRId_Date ") --]]\n", daynum);
return(daynum);
}
The DB_TRACE macro is derived from the code shown in #define a macro for debug printing in C?. The DB_TRACE macro is available in my SOQ (Stack Overflow Questions) repository on GitHub as files debug.c and debug.h in the src/libsoq sub-directory.
The formatting gives a single line showing the calculation steps.
The code above compiles with the debug.h header and <stdio.h> included, and a minimal main(), plus linking with the code from debug.c:
int main(void)
{
int dd = 28;
int mm = 12;
int yyyy = 2020;
Date dt = jl_dmy_conversion(dd, mm, yyyy);
printf("%.4d-%.2d-%.2d = %d\n", yyyy, mm, dd, dt);
return 0;
}
Demonstrating mktime()
As mentioned above, mktime() is passed a struct tm pointer, and it is documented that it accepts values that are 'out of range' and normalizes the result — modifying the structure it is passed. It also sets the tm_wday and tm_yday fields — it ignores them as inputs.
If you have a struct tm value for 2020-12-28 08:20:26 and you want to know the time_t value for 6 days, 18 hours, 43 minutes, 32 seconds later, you can use code like this:
#include <stdio.h>
#include <time.h>
static void print_time(time_t t, const struct tm *tm)
{
char buffer[32];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %A", tm);
printf("%lld: %s (%d)\n", (long long)t, buffer, tm->tm_yday);
}
int main(void)
{
struct tm tm = { .tm_year = 2020 - 1900, .tm_mon = 12 - 1, .tm_mday = 28,
.tm_hour = 8, .tm_min = 20, .tm_sec = 26 };
time_t t0 = mktime(&tm);
print_time(t0, &tm);
tm.tm_mday += 6;
tm.tm_hour += 18;
tm.tm_min += 43;
tm.tm_sec += 32;
time_t t1 = mktime(&tm);
print_time(t1, &tm);
return 0;
}
When run (in US/Mountain standard time zone — UTC-7), it produces:
1609168826: 2020-12-28 08:20:26 Monday (362)
1609754638: 2021-01-04 03:03:58 Monday (3)
The conditions for leap year are summarized as:
leap year if perfectly visible by 400
not a leap year if visible by 100 but not divisible by 400
leap year if not divisible by 100 but divisible by 4
all other years are not leap year
So the logic could be expressed as:
if (((year%4 == 0) && (year%100 != 0)) || (year%400 == 0))
{
leap_year_count++;
}
year++;
But not sure if re-factoring your existing logic will add any speed advantage.

If inside a for loop (day difference for common and leap year) not working

I'm new to C-programming and I'm trying to make a code to count the day difference between a date and a birthday.
int year, birth_year;
int year_common;
int year_leap;
for(int i = year; i <= birth_year; i--){
year = i;
if (year % 400 != 0 || (year % 100 == 0 && year % 400 != 0)){
year_common++;
}
if(year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)){
year_leap++;
}
}
int date_pass = (year_common * 365) + (year_leap * 366);
I wanted the loop to decrement the 'i', add 1 into the year_common integer when it's a common year, and add 1 into the year_leap integer when it's a leap year until it is the same as the birth_year.
For now, I'm still trying to check out the years, but no matter how many year difference I made, they always give out 5856 days.
e.g. :
birth date : 05/11/2005
checked date : 05/11/ 2007
give out '5856 days'
And I don't know where that number comes from.
I tried initializing it with 0, but it gave out 0 days instead.
I tried this code:
int year_pass = year - birth_year;
int year_leap = 0;
for(int i = year; i <= birth_year; i--){
if(i % 400 == 0 || (i % 100 != 0 && i % 4 == 0)){
year_leap++;
}
}
int date_pass = (year_pass * 365) + (year_leap * 1);
And it missed 1 day for the leap year.
Is there something wrong with the loop?
My prof wants the code to be as standard as possible with loops and conditions.
You have declared the year common and year leap as in variables but haven't assigned any value. Since youre adding one unit by ++;, you need to pre define year_leap and year_common =0
int year, birth_year;
int year_common=0;
int year_leap=0;
Dates are hard to handle, with all UTC leap seconds and local timezones - leap years are only the tip of the iceberg. Don't reinvent the wheel. Whenever you want to do something with dates, first thing to do is to convert everything to seconds since epoch. Then you do what you want.
#include <time.h>
#include <stdio.h>
#include <stdint.h>
int main() {
// 05/11/2005
struct tm birthday = {
.tm_year = 2005 - 1900,
.tm_mon = 11,
.tm_mday = 5,
.tm_hour = 12,
};
// 05/11/2007
struct tm end = {
.tm_year = 2007 - 1900,
.tm_mon = 11,
.tm_mday = 5,
.tm_hour = 12,
};
time_t birth_s = mktime(&birthday);
time_t end_s = mktime(&end);
time_t diff_s = end_s - birth_s;
time_t diff_day = diff_s / 3600 / 24;
printf("%ju\n", (uintmax_t)diff_day);
}

How do you return a formatted string in C?

So basically I have a function that calculates three integer values: day, month, year
I want it to return a string in format "day/month/year"
This is the function:
char* generateDate(int day, int month, int year){
day++;
int dayCount = 31;
if (month == 4 || month == 6 || month == 9 || month == 11) {
dayCount = 30;
}
else if (month == 2) {
dayCount = 28;
if (year % 4 == 0) {
dayCount = 29;
if (year % 100 == 0) {
dayCount = 28;
if (year % 400 == 0) {
dayCount = 29;
}
}
}
}
if (day > dayCount) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
char* date = malloc(10);
char* s_day;
sprintf(s_day, "%f", day);
date[0] = day;
return date;
}
Near the bottom of the function, I create a pointer to a char array, and try to convert day (which is an int) to a string and add it to the array but that doesn't work yet. I get the following error:
RUN FAILED (exit value -1,073,741,819, total time: 1s)
I realize that converting int to string doesn't work as easily as I think, especially to then only add it to to an array.
I basically want to take: int day, int month, int year and return:
"day/month/year" (does not need to be a pointer, unless necessary. It can be passed by value to calling code)
Sorry if it's a silly error, I'm very used to Java and C# where working with strings is so easy
If you just need to return an allocated string with the full date, your task is quite trivial. You just need to build the string with a function like sprintf:
#include <stdio.h>
char* generateDate(int day, int month, int year)
{
/* here you should place parameters check */
char retString = malloc( 11 );
sprintf (retString, "%02d/%02d/%04d", day, month, year);
return retString;
}
Please note how format %02d prints a 2 digits integer with a leading 0 in case the corresponding integer is only one digit long.
We allocate 11 chars because:
2 are for the day
2 are for the month
4 are for the year
2 are for the separators '/'
1 is required for the string terminator
Of course the function can be improved by inserting parameters check at the beginning of the function, and returning NULL if they are wrong.
Make sure that year is lower than 9999 (for sanity)
Make sure that month is between 1 and 12
With a switch-case conditional, set a variable dayMax to the maximum number of days of every month, and check day so that it is icluded between 1 and dayMax
If I understood your code correctly it looks like you want to calculate the date of the next day.
One way to do that without having to calculate all that you are doing is to use the built-in runtime functions in C
struct tm myDate = {0, 0, 0,day,month-1,year - 1900,0,0,-1};
time_t seconds = mktime(&myDate); // strictly speaking it is clock ticks but secs normally
seconds += 3600*24; // add a day of seconds
localtime_s(&myDate, &seconds);
now you have year, month and day for next day and don't have think about leap year etc.
to return this string to caller either pass a buffer to the function or allocate some memory
char* s_day = malloc( 4 + 1 + 2 + 1 + 2 + 1 ); // 0000/00/00 + \0
sprintf_s( s_day, "%d/%d/%d", myDate.tm_mday, myDate.tm_mon + 1, myDate.tm_year + 1900);
return s_day;
EDIT: If you prefer to have the format with leading zeros use the format string
"%02d/%02d/%d" instead

Difference between two dates in C

I'm a beginner in C.
Is there any datatype for dates?
In C we have for working with time, is there one for dates too?
How can I calculate difference between two dates?
Yes,the standard library C Time Library contains structures and functions you want.You can use struct tm to store date and difftime to get the difference.
Is there any datatype for save dates?
No, although for dates in the range "now plus or minus a few decades" you could use time_t or struct tm containing the datetime at (for example) midnight on the relevant day. Alternatively you could look into a thing called the "Julian day": compute that and store it in whatever integer type you like.
Is there any library for C too?
The standard functions all relate to date/times rather than just dates: mktime, localtime, gmtime.
How can I calculate different between two date
Once you have it in a time_t you can subtract the two and divide by 86400. Watch out, though, since "midnight local time" on two different days might not be an exact multiple of 24 hours apart due to daylight savings changes.
If you need a calendar that extends beyond the range of time_t on your implementation then you're basically on your own. If time_t is 64 bits then that's more than the age of the universe, but if time_t is 32 bits it's no good for history. Or pension planning, even. Historical applications have their own demands on calendars anyway (Julian calendar, calendars completely unrelated to Gregorian).
The standard C library options for dates and times are pretty poor and loaded with caveats and limitations. If at all possible, use a library such as Gnome Lib which provides GDate and numerous useful date and time functions. This includes g_date_days_between() for getting the number of days between two dates.
The rest of this answer will restrict itself to the standard C library, but if you don't have to limit yourself to the standard, don't torture yourself. Dates are surprisingly hard.
Is there any datatype for dates?
struct tm will serve. Just leave the hour, minutes, and seconds at 0.
Simplest way to ensure all the fields of struct tm are properly populated is to use strptime.
struct tm date;
strptime( "2017-03-21", "%F", &date );
puts( asctime(&date) ); // Mon Mar 21 00:00:00 2017
But that's not a great way to store dates. It turns out it's better to use Julian Days (see below).
In C we have for working with time, is there one for dates too?
If you're referring to time_t, that is also for date-times. It's the number of seconds since "the epoch" which is 1970-01-01 00:00:00 UTC on POSIX systems, but not necessarily others. Unfortunately its safe range is only 1970 to 2037, though any recent version of an operating system will have greatly expanded that range.
How can I calculate difference between two dates?
Depends on what you want. If you want the number of seconds, you could convert the struct tm to time_t using mktime and then use difftime, but that's limited to the 1970-2037 safe range of time_t.
int main() {
struct tm date1, date2;
strptime( "2017-03-21", "%F", &date1 );
strptime( "2018-01-20", "%F", &date2 );
printf("%.0lf\n", difftime(mktime(&date1), mktime(&date2)));
}
If you want the number of days, you'd convert the dates into Julian days, the number of days since November 24, 4714 BC, and subtract. While that might seem ridiculous, this relatively simple formula takes advantage of calendar cycles and only uses integer math.
// The formulas for a and m can be distilled down to these tables.
int Julian_A[12] = { 1, 1, 0 };
int Julian_M[12] = { 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int julian_day( struct tm *date ) {
int a = Julian_A[date->tm_mon];
int m = Julian_M[date->tm_mon];
int y = date->tm_year + 1900 + 4800 - a;
return date->tm_mday + ((153*m + 2) / 5) + 365*y + y/4 - y/100 + y/400 - 32045;
}
int main() {
struct tm date1, date2;
strptime( "2017-03-21", "%F", &date1 );
strptime( "2018-01-20", "%F", &date2 );
// 305 days
printf("%d days\n", julian_day(&date2) - julian_day(&date1));
}
There are other simple formulas for converting between Julian Dates and calendar dates.
Getting diffs in years, months, and days is difficult because of the number of days in a month varies by month and year, and because it has to be normalized. For example, you wouldn't say 2 years, -1 months, 2 days. You'd say 1 year, 11 months, 29 days (or maybe 28, depends on the month). For this reason, do date math in Julian Days whenever possible.
To get an idea of what's involved, PHP implements this as date_diff. Have a look at the amount of C code required.
Is there any datatype for dates?
No, inbuilt datatype in C , you have to defined user-defined data type.
How can I calculate difference between two dates?
You may try this:
struct dt
{
int dd;
int mm;
int yy;
};
typedef dt date;
In main() you need to declare three variables for type data.
In following example today difference,
for example you wants to take difference between current date (c_date) and date of birth (dob)
date dob,c_date,today;
if(c_date.dd>=dob.dd)
today.dd = c_date.dd-dob.dd;
else
{
c_date.dd+=30;
c_date.mm-=1;
today.dd = c_date.dd-dob.dd;
}
if(c_date.mm>=dob.mm)
today.mm = c_date.mm-dob.mm;
else
{
c_date.mm+=12;
c_date.yy-=1;
today.mm = c_date.dd-dob.mm;
}
today.yy = c_date.yy-dob.yy;
In today you have difference between two dates.
There is one more way: double difftime (time_t end, time_t beginning);
Read this answers:
1. How to compare two time stamp in format “Month Date hh:mm:ss"
2. How do you find the difference between two dates in hours, in C?
You can create a struct named date having following fields
typedef struct
{
int day;
int month;
int year;
}date;
It's just a blueprint what you want , now make and object of date and work accordingly.
To find the difference ,write a function to take a difference between day month and year of the both stucts respectively.
You have to define a date struct:
typedef struct date {
int day;
int month;
int year;
} Date;
And then define a simple date_compare() method:
int date_compare(Date *date1, Date *date2) {
if (date1->year != date2->year)
return (date1->year - date2->year);
if (date1->month != date2->month)
return (date1->month - date2->month);
return (date1->day - date2->day);
}
/* Version 3 (better)
Date Difference between the two dates in days
like VBA function DateDiff("d", date1, date2)
in case of Gregorian. Same basic principle you
can translate in lot of other languages. This
is complete C code with date validity control.
*/
#include<stdio.h>
void main(){
long d1,m1,y1,d2,m2,y2;
printf("Enter first date day, month, year\n");
scanf("%d%d%d",&d1,&m1,&y1);
printf("Enter second date day, month, year\n");
scanf("%d%d%d",&d2,&m2,&y2);
if((IsValid(d1,m1,y1)==0)||(IsValid(d2,m2,y2)==0)){
printf("Invalid date detected\n");
}else{
d1=DatDif(d1,m1,y1,d2,m2,y2);
printf("\n\n Date difference is %d days\n",d1);
}
}// end main
long DatDif(d1,m1,y1,d2,m2,y2)
{ long suma;
suma=rbdug(d2,m2,y2) - rbdug(d1,m1,y1);
if(y1 != y2){
if(y1 < y2){
suma+=Godn(y1,y2);
}else{
suma-=Godn(y2,y1);
}
}
return(suma);
}// end DatDif
long Godn(yy1,yy2)
{ long jj,bb;
bb=0;
for(jj=yy1;jj<yy2;jj++){
bb+=365;
if(((((jj%400)==0)||((jj%100)!=0))
&&((jj%4)==0))) bb+=1;
}
return(bb);
}// end Godn
//Day of the Year
long rbdug(d,m,y)
{ long a,r[13];
r[1] = 0; r[2] = 31; r[3] = 59;
r[4] = 90; r[5] = 120; r[6] = 151;
r[7] = 181; r[8] = 212; r[9] = 243;
r[10]= 273; r[11]= 304; r[12]= 334;
a=r[m]+d;
if(((((y%400)==0)||((y%100)!=0))
&&((y%4)==0))&&(m>2)) a+=1;
return(a);
}//end rbdug
//date validity
long IsValid(dd,mm,yy)
{ long v[13];
if((0 < mm) && (mm < 13)){
v[1] = 32; v[2] = 29; v[3] = 32;
v[4] = 31; v[5] = 32; v[6] = 31;
v[7] = 32; v[8] = 32; v[9] = 31;
v[10]= 32; v[11]= 31; v[12]= 32;
if(((((yy%400)==0)||((yy%100)!=0))
&&((yy%4)==0))) v[2]+=1;
if((0 < dd) && (dd < v[mm])){
return(1);
}else{
return(0);
}
}else{
return(0);
}
}//end IsValid
/* Version 4 ( 100 % correct):
Proleptic Gregorian date difference in days.
Date Difference between the two dates in days
like VBA function DateDiff("d", date1, date2)
and better (without limitations of DateDiff)
in case of Gregorian. Same basic principle you
can translate in lot of other languages. This
is complete C code with date validity control.
*/
#include<stdio.h>
void main(){
long d1,m1,y1,d2,m2,y2;
printf("Enter first date day, month, year\n");
scanf("%d%d%d",&d1,&m1,&y1);
printf("Enter second date day, month, year\n");
scanf("%d%d%d",&d2,&m2,&y2);
if((IsValid(d1,m1,y1)==0)||(IsValid(d2,m2,y2)==0)){
printf("Invalid date detected\n");
}else{
d1=DatDif(d1,m1,y1,d2,m2,y2);
printf("\n\n Date difference is %d days\n",d1);
}
}// end main
long DatDif(d1,m1,y1,d2,m2,y2)
{ long suma;
suma=rbdug(d2,m2,y2) - rbdug(d1,m1,y1);
if(y1 != y2){
if(y1 < y2){
suma+=Godn(y1,y2);
}else{
suma-=Godn(y2,y1);
}
}
return(suma);
}// end DatDif
long Godn(yy1,yy2)
{ long jj,bb;
bb=0;
for(jj=yy1;jj<yy2;jj++){
bb+=365;
if(IsLeapG(jj)==1) bb+=1;
}
return(bb);
}// end Godn
//Day of the Year
long rbdug(d,m,y)
{ long a,r[13];
r[1] = 0; r[2] = 31; r[3] = 59; r[4] = 90;
r[5] = 120; r[6] = 151; r[7] = 181; r[8] = 212;
r[9] = 243; r[10]= 273; r[11]= 304; r[12]= 334;
a=r[m]+d;
if((IsLeapG(y)==1)&&(m>2)) a+=1;
return(a);
}//end rbdug
//date validity
long IsValid(dd,mm,yy)
{ long v[13];
if((0 < mm) && (mm < 13)){
v[1] = 32; v[2] = 29; v[3] = 32; v[4] = 31;
v[5] = 32; v[6] = 31; v[7] = 32; v[8] = 32;
v[9] = 31; v[10]= 32; v[11]= 31; v[12]= 32;
if ((mm==2)&&(IsLeapG(yy)==1)) v[2]=30;
if((0 < dd) && (dd < v[mm])){
return(1);
}else{
return(0);
}
}else{
return(0);
}
}//end IsValid
//is leap year in Gregorian
long IsLeapG(yr){
if(((((yr%400)==0)||((yr%100)!=0))&&((yr%4)==0))){
return(1);
}else{
return(0);
}
}//end IsLeapG

Resources