简体   繁体   中英

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?

是的,标准库C Time Library包含您想要的结构和功能。您可以使用struct tm来存储日期和difftime以获得差异。

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).

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);

}

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 .

/*  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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM