繁体   English   中英

如何在C ++中比较2个日期

[英]how to compare 2 dates in c++

我有一个包含yyyy/mm/dd格式的日期的字符串变量。 如何在C ++中将其转换为time_t类型? 例如: string date_details = "2012/09/12"

另外,如何比较两个包含日期的变量以决定哪个最早出现在C ++中? 例如: string curr_date = "2012/09/13" string user_date = "2012/09/12"

谢谢。

要比较年月日格式的两个日期, strcmp就足够了:

assert(strcmp("2012/09/13", "2012/09/12") > 0);
assert(strcmp("2012/10/13", "2013/01/12") < 0);

如果需要,可以使用strptime解析任何格式的日期,然后使用mktimetm结构转换为可以比较的time_t值。

对于自示例日期以来的价值, string curr_date = "2012/09/13"string curr_date = "2012/09/13"似乎采用ISO8601格式(除了使用'/'作为分隔符之外)。 ISO8601的乐趣在于字典顺序与时间顺序相同...即对字符串进行排序,并且您还按时间进行排序。

这很吸引人,因为它提供了一种处理许多日期的好方法(而不是2个)

#include <algorithm>
#include <vector>
#include <string>

using namespace std;

int main()
{

   vector<string> v = getDates(); //Made up function returning a vector of ISO dates
   sort(v, v.begin(), v.end()); //Done
   //Do whatever you have to
   return 0;
}

我的建议是使用函子。 这样做可以让您确定要如何比较这些日期,并且还可以稍后定义另一个函子,该函子以不同的方式比较日期。

例如,您可以这样定义函子:

struct DateLessThan
{
    BOOL operator()(const std::string& lhs, const std::string& rhs)
    {
        // the following is pseudocode
        split lhs and rhs into arrays of strings based on the delimiter "/"

        convert the string arrays into integers and store them in vars (possibly lhs_day, lhs_month, etc.)

        if (lhs_year < rhs_year)
            return true;
        else if (lhs_year == rhs_year)
        {
            if (lhs_month < rhs_month)
                return true;
            else if (lhs_month == rhs_month)
            {
                if (lhs_day < rhs_day)
                    return true;
            }
        }

        return false;
    }
};

strptime()是您要寻找的。 不幸的是,要在Windows上运行它并不容易。

尽管经过大量的搜索,我终于找到了与ffmpeg.org链接的实现,该实现可以完成这项工作。 可以在plibc.sourceforge.net(适用于Windows的POSIX兼容libc)上 找到实现

如果要使用此正则表达式00([0-9])([0-9])([0-9])从doxygen复制行号,则必须删除行号。 在行115 enum locale_status { not, loc, raw };也有错误enum locale_status { not, loc, raw }; 必须更改为enum locale_status { nott, loc, raw };

或者,如果您对所有这些都不满意,请使用我使用的版本:

/* Convert a string representation of time to a time value.
    Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.

    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.

    The GNU C Library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with the GNU C Library; see the file COPYING.LIB.  If not,
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */

 void get_locale_strings(void);

 /* XXX This version of the implementation is not really complete.
    Some of the fields cannot add information alone.  But if seeing
    some of them in the same format (such as year, week and weekday)
    this is enough information for determining the date.  */

 #include <ctype.h>
 #include <limits.h>
 #include <string.h>
 #include <time.h>

 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL

 #ifndef Macintosh
 #if defined __GNUC__ && __GNUC__ >= 2
 # define match_string(cs1, s2) \
   ({ size_t len = strlen (cs1);                                               \
      int result = strncasecmp ((cs1), (s2), len) == 0;                        \
      if (result) (s2) += len;                                                 \
      result; })
 #else
 /* Oh come on.  Get a reasonable compiler.  */
 # define match_string(cs1, s2) \
   (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
 #endif
 #else
 # define match_string(cs1, s2) \
   (strncmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
 #endif /* mac */

 /* We intentionally do not use isdigit() for testing because this will
    lead to problems with the wide character version.  */
 #define get_number(from, to, n) \
   do {                                                                        \
     int __n = n;                                                              \
     val = 0;                                                                  \
     while (*rp == ' ')                                                        \
       ++rp;                                                                   \
     if (*rp < '0' || *rp > '9')                                               \
       return NULL;                                                            \
     do {                                                                      \
       val *= 10;                                                              \
       val += *rp++ - '0';                                                     \
     } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9');        \
     if (val < from || val > to)                                               \
       return NULL;                                                            \
   } while (0)
 # define get_alt_number(from, to, n) \
   /* We don't have the alternate representation.  */                          \
   get_number(from, to, n)
 #define recursive(new_fmt) \
   (*(new_fmt) != '\0'                                                         \
    && (rp = strptime_internal (rp, (new_fmt), tm, decided)) != NULL)

 /* This version: may overwrite these with versions for the locale */
 static char weekday_name[][20] =
 {
     "Sunday", "Monday", "Tuesday", "Wednesday",
     "Thursday", "Friday", "Saturday"
 };
 static char ab_weekday_name[][10] =
 {
     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 };
 static char month_name[][20] =
 {
     "January", "February", "March", "April", "May", "June",
     "July", "August", "September", "October", "November", "December"
 };
 static char ab_month_name[][10] =
 {
     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 };

 static char am_pm[][4] = {"AM", "PM"};


 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
 # define HERE_D_FMT "%y/%m/%d"
 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
 # define HERE_T_FMT "%H:%M:%S"

 static const unsigned short int __mon_yday[2][13] =
 {
     /* Normal years.  */
     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
     /* Leap years.  */
     { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
 };


 /* Status of lookup: do we use the locale data or the raw data?  */
 enum locale_status { nott, loc, raw };

 # define __isleap(year) \
   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))

 /* Compute the day of the week.  */
 void
 day_of_the_week (struct tm *tm)
 {
     /* We know that January 1st 1970 was a Thursday (= 4).  Compute the
        the difference between this data in the one on TM and so determine
        the weekday.  */
     int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
     int wday = (-473
                 + (365 * (tm->tm_year - 70))
                 + (corr_year / 4)
                 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
                 + (((corr_year / 4) / 25) / 4)
                 + __mon_yday[0][tm->tm_mon]
                 + tm->tm_mday - 1);
     tm->tm_wday = ((wday % 7) + 7) % 7;
 }

 /* Compute the day of the year.  */
 void
 day_of_the_year (struct tm *tm)
 {
     tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
                    + (tm->tm_mday - 1));
 }

 char *
 strptime_internal (const char *rp, const char *fmt, struct tm *tm,
                    enum locale_status *decided)
 {
     const char *rp_backup;
     int cnt;
     size_t val;
     int have_I, is_pm;
     int century, want_century;
     int have_wday, want_xday;
     int have_yday;
     int have_mon, have_mday;

     have_I = is_pm = 0;
     century = -1;
     want_century = 0;
     have_wday = want_xday = have_yday = have_mon = have_mday = 0;

     while (*fmt != '\0')
     {
         /* A white space in the format string matches 0 more or white
            space in the input string.  */
         if (isspace (*fmt))
         {
             while (isspace (*rp))
                 ++rp;
             ++fmt;
             continue;
         }

         /* Any character but `%' must be matched by the same character
            in the iput string.  */
         if (*fmt != '%')
         {
             match_char (*fmt++, *rp++);
             continue;
         }

         ++fmt;

         /* We need this for handling the `E' modifier.  */
     start_over:

         /* Make back up of current processing pointer.  */
         rp_backup = rp;

         switch (*fmt++)
         {
         case '%':
             /* Match the `%' character itself.  */
             match_char ('%', *rp++);
             break;
         case 'a':
         case 'A':
             /* Match day of week.  */
             for (cnt = 0; cnt < 7; ++cnt)
             {
                 if (*decided != loc
                     && (match_string (weekday_name[cnt], rp)
                         || match_string (ab_weekday_name[cnt], rp)))
                 {
                     *decided = raw;
                     break;
                 }
             }
             if (cnt == 7)
                 /* Does not match a weekday name.  */
                 return NULL;
             tm->tm_wday = cnt;
             have_wday = 1;
             break;
         case 'b':
         case 'B':
         case 'h':
             /* Match month name.  */
             for (cnt = 0; cnt < 12; ++cnt)
             {
                 if (match_string (month_name[cnt], rp)
                     || match_string (ab_month_name[cnt], rp))
                 {
                     *decided = raw;
                     break;
                 }
             }
             if (cnt == 12)
                 /* Does not match a month name.  */
                 return NULL;
             tm->tm_mon = cnt;
             want_xday = 1;
             break;
         case 'c':
             /* Match locale's date and time format.  */
             if (!recursive (HERE_T_FMT_AMPM))
                 return NULL;
             break;
         case 'C':
           /* Match century number.  */
           get_number (0, 99, 2);
           century = val;
           want_xday = 1;
           break;
         case 'd':
         case 'e':
           /* Match day of month.  */
           get_number (1, 31, 2);
           tm->tm_mday = val;
           have_mday = 1;
           want_xday = 1;
           break;
         case 'F':
           if (!recursive ("%Y-%m-%d"))
             return NULL;
           want_xday = 1;
           break;
         case 'x':
           /* Fall through.  */
         case 'D':
           /* Match standard day format.  */
           if (!recursive (HERE_D_FMT))
             return NULL;
           want_xday = 1;
           break;
         case 'k':
         case 'H':
           /* Match hour in 24-hour clock.  */
           get_number (0, 23, 2);
           tm->tm_hour = val;
           have_I = 0;
           break;
         case 'I':
           /* Match hour in 12-hour clock.  */
           get_number (1, 12, 2);
           tm->tm_hour = val % 12;
           have_I = 1;
           break;
         case 'j':
           /* Match day number of year.  */
           get_number (1, 366, 3);
           tm->tm_yday = val - 1;
           have_yday = 1;
           break;
         case 'm':
           /* Match number of month.  */
           get_number (1, 12, 2);
           tm->tm_mon = val - 1;
           have_mon = 1;
           want_xday = 1;
           break;
         case 'M':
           /* Match minute.  */
           get_number (0, 59, 2);
           tm->tm_min = val;
           break;
         case 'n':
         case 't':
           /* Match any white space.  */
           while (isspace (*rp))
             ++rp;
           break;
         case 'p':
           /* Match locale's equivalent of AM/PM.  */
           if (!match_string (am_pm[0], rp))
             if (match_string (am_pm[1], rp))
               is_pm = 1;
             else
               return NULL;
           break;
         case 'r':
           if (!recursive (HERE_T_FMT_AMPM))
             return NULL;
           break;
         case 'R':
             if (!recursive ("%H:%M"))
                 return NULL;
             break;
         case 's':
         {
             /* The number of seconds may be very high so we cannot use
                the `get_number' macro.  Instead read the number
                character for character and construct the result while
                doing this.  */
             time_t secs = 0;
             if (*rp < '0' || *rp > '9')
                 /* We need at least one digit.  */
                 return NULL;

             do
             {
                 secs *= 10;
                 secs += *rp++ - '0';
             }
             while (*rp >= '0' && *rp <= '9');

             if ((tm = localtime (&secs)) == NULL)
                 /* Error in function.  */
                 return NULL;
         }
         break;
         case 'S':
             get_number (0, 61, 2);
             tm->tm_sec = val;
             break;
         case 'X':
             /* Fall through.  */
         case 'T':
             if (!recursive (HERE_T_FMT))
                 return NULL;
             break;
         case 'u':
             get_number (1, 7, 1);
             tm->tm_wday = val % 7;
             have_wday = 1;
             break;
         case 'g':
             get_number (0, 99, 2);
             /* XXX This cannot determine any field in TM.  */
             break;
         case 'G':
             if (*rp < '0' || *rp > '9')
                 return NULL;
             /* XXX Ignore the number since we would need some more
                information to compute a real date.  */
             do
                 ++rp;
             while (*rp >= '0' && *rp <= '9');
             break;
         case 'U':
         case 'V':
         case 'W':
             get_number (0, 53, 2);
             /* XXX This cannot determine any field in TM without some
                information.  */
             break;
         case 'w':
             /* Match number of weekday.  */
             get_number (0, 6, 1);
             tm->tm_wday = val;
             have_wday = 1;
             break;
         case 'y':
             /* Match year within century.  */
             get_number (0, 99, 2);
             /* The "Year 2000: The Millennium Rollover" paper suggests that
                values in the range 69-99 refer to the twentieth century.  */
             tm->tm_year = val >= 69 ? val : val + 100;
             /* Indicate that we want to use the century, if specified.  */
             want_century = 1;
             want_xday = 1;
             break;
         case 'Y':
             /* Match year including century number.  */
             get_number (0, 9999, 4);
             tm->tm_year = val - 1900;
             want_century = 0;
             want_xday = 1;
             break;
         case 'Z':
             /* XXX How to handle this?  */
             break;
         case 'E':
             /* We have no information about the era format.  Just use
                the normal format.  */
             if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
                 && *fmt != 'x' && *fmt != 'X')
                 /* This is an invalid format.  */
                 return NULL;

             goto start_over;
         case 'O':
             switch (*fmt++)
             {
             case 'd':
             case 'e':
                 /* Match day of month using alternate numeric symbols.  */
                 get_alt_number (1, 31, 2);
                 tm->tm_mday = val;
                 have_mday = 1;
                 want_xday = 1;
                 break;
             case 'H':
                 /* Match hour in 24-hour clock using alternate numeric
                    symbols.  */
                 get_alt_number (0, 23, 2);
                 tm->tm_hour = val;
                 have_I = 0;
                 break;
             case 'I':
                 /* Match hour in 12-hour clock using alternate numeric
                    symbols.  */
                 get_alt_number (1, 12, 2);
                 tm->tm_hour = val - 1;
                 have_I = 1;
                 break;
             case 'm':
                 /* Match month using alternate numeric symbols.  */
                 get_alt_number (1, 12, 2);
                 tm->tm_mon = val - 1;
                 have_mon = 1;
                 want_xday = 1;
                 break;
             case 'M':
                 /* Match minutes using alternate numeric symbols.  */
                 get_alt_number (0, 59, 2);
                 tm->tm_min = val;
                 break;
             case 'S':
                 /* Match seconds using alternate numeric symbols.  */
                 get_alt_number (0, 61, 2);
                 tm->tm_sec = val;
                 break;
             case 'U':
             case 'V':
             case 'W':
                 get_alt_number (0, 53, 2);
                 /* XXX This cannot determine any field in TM without
                    further information.  */
                 break;
             case 'w':
                 /* Match number of weekday using alternate numeric symbols.  */
                 get_alt_number (0, 6, 1);
                 tm->tm_wday = val;
                 have_wday = 1;
                 break;
             case 'y':
                 /* Match year within century using alternate numeric symbols.  */
                 get_alt_number (0, 99, 2);
                 tm->tm_year = val >= 69 ? val : val + 100;
                 want_xday = 1;
                 break;
             default:
                 return NULL;
             }
             break;
         default:
             return NULL;
         }
     }

     if (have_I && is_pm)
         tm->tm_hour += 12;

     if (century != -1)
     {
         if (want_century)
             tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
         else
             /* Only the century, but not the year.  Strange, but so be it.  */
             tm->tm_year = (century - 19) * 100;
     }

     if (want_xday && !have_wday) {
         if ( !(have_mon && have_mday) && have_yday)  {
             /* we don't have tm_mon and/or tm_mday, compute them */
             int t_mon = 0;
             while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
                 t_mon++;
             if (!have_mon)
                 tm->tm_mon = t_mon - 1;
             if (!have_mday)
                 tm->tm_mday = tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1;
         }
         day_of_the_week (tm);
     }
     if (want_xday && !have_yday)
         day_of_the_year (tm);

     return (char *) rp;
 }

 char *
 strptime (const char *buf, const char *format, struct tm *tm)
 {
     enum locale_status decided;
 #ifdef HAVE_LOCALE_H
     if(!have_used_strptime) {
         get_locale_strings();
         /* have_used_strptime = 1; might change locale during session */
     }
 #endif
     decided = raw;
     return strptime_internal (buf, format, tm, &decided);
 }

 #ifdef HAVE_LOCALE_H
 void get_locale_strings(void)
 {
     int i;
     struct tm tm;
     char buff[4];

     tm.tm_sec = tm.tm_min = tm.tm_hour = tm.tm_mday = tm.tm_mon
         = tm.tm_isdst = 0;
     tm.tm_year = 30;
     for(i = 0; i < 12; i++) {
         tm.tm_mon = i;
         strftime(ab_month_name[i], 10, "%b", &tm);
         strftime(month_name[i], 20, "%B", &tm);
     }
     tm.tm_mon = 0;
     for(i = 0; i < 7; i++) {
         tm.tm_mday = tm.tm_yday = i+1; /* 2000-1-2 was a Sunday */
         tm.tm_wday = i;
         strftime(ab_weekday_name[i], 10, "%a", &tm);
         strftime(weekday_name[i], 20, "%A", &tm);
     }
     tm.tm_hour = 1;
     /* in locales where these are unused, they may be empty: better
        not to reset them then */
     strftime(buff, 4, "%p", &tm);
     if(strlen(buff)) strcpy(am_pm[0], buff);
     tm.tm_hour = 13;
     strftime(buff, 4, "%p", &tm);
     if(strlen(buff)) strcpy(am_pm[1], buff);
 }
 #endif

这是一个工作示例:

#include <iostream> 
#include <string>
#include <cstdlib>
#include <cstring>
#include <time.h>
#include <stdio.h>          
#include "strptime.h"

using namespace std;

int main()
{
    struct tm tm1, tm2;
    time_t t1, t2;

    memset(&tm1, 0, sizeof(struct tm));
    memset(&tm2, 0, sizeof(struct tm));

    strptime("12 February 2010", "%d %b %Y", &tm1);         
    strptime("11 February 2010", "%d %b %Y", &tm2);

    t1 = mktime(&tm1);
    t2 = mktime(&tm2);

    cout << t1 << endl;
    cout << t2 << endl;

    if (t1 > t2)
    {
        cout << "t1 > t2" << endl;
    }
    else if (t1 == t2)
    {
        cout << "t1 == t2" << endl;
    }
    else if (t1 < t2)
    {
        cout << "t1 < t2" << endl;
    }

    cout << (t1 - t2) << endl;

    return 0;
}

输出:

1265925600
1265839200
t1 > t2
86400

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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