在C++中比较两个日期

6

我想知道C++中是否有相对简单和短的日期比较函数。我的日期类型是char*,格式如下:DD\MM\YYYY

谢谢。


1
相关链接:https://dev59.com/LnI-5IYBdhLWcg3w1sTi。我编写了自己的日期类来进行这些操作。你也可以轻松地实现它。 - AgA
1
还要注意一下C++11的新chrono头文件,它支持一些日期和时间实用工具。 - Felix Glas
1
反斜杠,不是正斜杠? - Potatoswatter
1
格式是必需的吗?ISO标准日期,YYYY-MM-DD,可以与普通字符串比较。 - Bo Persson
是的,这是日期格式,给定为DD\MM\YYYY。 - David Faizulaev
5个回答

7
解析通常在流上进行,而不是字符串上进行,但您可以使用stringstream。
std::istringstream date_s( "04\\10\\1984" );
struct tm date_c;
date_s >> std::get_time( &date_c, "%d\\%m\\%Y" );
std::time_t seconds = std::mktime( & date_c );

现在,您可以使用<来比较秒数,以确定哪个更早。
请注意,std::get_time是C++11中的新功能。它是基于strptime定义的,该函数来自于POSIX但不是C99标准的一部分。如果没有可用的C++11库,可以使用strptime。如果您勇敢的话,也可以使用std::time_get facet…虽然看起来很丑陋。
如果您只想知道日期中哪个更早,而不想了解其它任何信息,可以使用std::lexicographical_compare。这将成为一个一行代码,但函数名太长了。
// return true if the date string at lhs is earlier than rhs
bool date_less_ddmmyyyy( char const *lhs, char const *rhs ) {
    // compare year
    if ( std::lexicographical_compare( lhs + 6, lhs + 10, rhs + 6, rhs + 10 ) )
        return true;
    if ( ! std::equal( lhs + 6, lhs + 10, rhs + 6 ) )
        return false;
    // if years equal, compare month
    if ( std::lexicographical_compare( lhs + 3, lhs + 5, rhs + 3, rhs + 5 ) )
        return true;
    if ( ! std::equal( lhs + 3, lhs + 5, rhs + 3 ) )
        return false;
    // if months equal, compare days
    return std::lexicographical_compare( lhs, lhs + 2, rhs, rhs+2 );
}

另请参阅如何在C语言中将日期时间转换为Unix时间戳?


1
对于 std::get_time 的示例,在 Visual Studio 2013 中,我需要首先将 tm 结构的值设置为零,以便让 mktime 正常工作。例如:memset(&date_c, 0, sizeof(date_c)); - bossbarber

2
如果这确实是一个固定格式,您可以使用简单的C字符串比较来完成。
int date_cmp(const char *d1, const char *d2)
{
    int rc;
    // compare years
    rc = strncmp(d1 + 6, d2 + 6, 4);
    if (rc != 0)
        return rc;

    // compare months
    rc = strncmp(d1 + 3, d2 + 3, 2);
    if (rc != 0)
        return rc;

    // compare days
    return strncmp(d1, d2, 2);
}

这与 strncmp 的工作方式类似。如果 d1 早于 d2,则返回小于0的值;如果两者日期相同,则返回0;如果 d1 晚于 d2,则返回大于0的值。另一种方法是使用 strptimemktime 将其转换为 time_t,并使用 difftime 进行比较。
struct tm tm;
time_t t1, t2;
strptime(d1, "%d\\%m\\%Y", &tm);
t1 = mktime(&tm);
// do the same with d2
double diff = difftime(t1, t2);

1

你觉得使用高效的解决方案如何?如果忽略斜杠,你的固定大小日期只需要8个字符。因此,通过一些移位和字节交换,你可以将它们作为64位整数进行比较。这比将它们作为字符串进行比较更快。

using std::cout;
using std::endl;
typedef unsigned __int16 U2;
typedef unsigned __int32 U4;
typedef unsigned __int64 U8;
#define bswap2 _byteswap_ushort
#define bswap4 _byteswap_ulong
#define bswap8 _byteswap_uint64

const int YYYYMMDD = 0;
const int YYYY_MM_DD = 1;
const int DDMMYYYY = 2;
const int DD_MM_YYYY = 3;

// compiler will optimize the if's out.
template <int FMT>
U8 DateToInt(char* sz) {
    if (FMT == YYYYMMDD) {
        return bswap8(*(U8*)sz);
    }
    if (FMT == YYYY_MM_DD) {
        U4 y = *(U4*)sz, m = *(U2*)(sz + 5), d = *(U2*)(sz + 8);
        return ((U8)bswap4(y) << 32) | (bswap2(m) << 16) | bswap2(d);
    }
    if (FMT == DD_MM_YYYY) {
        U4 y = *(U4*)(sz + 6), m = *(U2*)(sz + 3), d = *(U2*)sz;
        return ((U8)bswap4(y) << 32) | (bswap2(m) << 16) | bswap2(d);
    }
}

template<int FMT1, int FMT2 = FMT1>
__int64 CompareDate(char* sz1, char* sz2) {
    return DateToInt<FMT1>(sz1) - DateToInt<FMT2>(sz2);
}

void main() {
    cout << CompareDate<YYYYMMDD>("20151025", "20151026") << endl;
    cout << CompareDate<YYYYMMDD>("20151025", "20151024") << endl;
    cout << CompareDate<YYYYMMDD, YYYY_MM_DD>("20151025", "2015/10/26") << endl;
    cout << CompareDate<YYYYMMDD, YYYY_MM_DD>("20151025", "2015/10/24") << endl;
    cout << CompareDate<YYYYMMDD, DD_MM_YYYY>("20151025", "26/10/2015") << endl;
    cout << CompareDate<YYYYMMDD, DD_MM_YYYY>("20151025", "24/10/2015") << endl;
}

输出

-1
1
-1
1
-1
1

1

您需要从字符串中提取数字数据。最坏的情况是一堆循环和字符串转整数转换函数。

您可以使用sscanf和sprintf轻松完成此操作。如果您习惯于printfscanf,那么这很容易理解,并且您可以轻松地将其适应其他情况。没有秘密魔法函数调用。

#include <stdio.h>
void main()
{
    char* date1 = "9\\12\\2012"; 
    char* date2 = "6\\11\\2013"; 

    int day1,month1,year1;
    int day2,month2,year2;

    sscanf(date1,"%d\\%d\\%d",&day1,&month1,&year1); //reads the numbers
    sscanf(date2,"%d\\%d\\%d",&day2,&month2,&year2); //from the string

    if (year1<year2 || month1<month2 || day1<day2) //compares 2 dates
    {
        printf("date1 < date2\n");
    }
    else
    {
        printf("date1 >= date2\n");
    }

    char newdate[15];

    sprintf(newdate,"%d\\%d\\%d",13,2,1998); //make a date string from numbers
    printf("%s\n",newdate);
}

谢谢,但我只有一个反斜杠''在D\M\Y之间,而不是两个。 - David Faizulaev
2
第二个是转义斜杠 - fbstj
3
我希望自那个日期起没有人使用它,因为日期比较是错误的。应该是 if (year1 != year2) { return year1 < year2; } 等等。 - mandrake

0

我也遇到了同样的问题,并想出了一个简单的解决方案。您可以使用以下函数对日期进行序列化,然后比较序列号。更大的序列号意味着更大的日期。

序列号 = YYYY ×100,000,000 + MM ×1,000,000 + DD*10,000 + hour * 100 + min *1

例如:比较12/1/2023 00:00和11/30/20223 23:59 12/1/2023 00:00-> 2023100,000,000 + 12×1,000,000 + 3110,000 +0100 + 01 = 202,312,010,000 11/30/2023 23:59-> 2023 * 100,000,000 + 111,000,000 + 3010,000 + 23*100 + 59 = 202,311,302,359

202,312,010,000 > 202,311,302,359,因此12/1/2023 00:00是更大的日期。

这适用于所有相关日期。

如果您想测量更小的增量,比如秒,可以从最小的增量(在本例中为秒)开始设置乘数因子为1,然后每次递增100来增加乘数因子。 例如:对于毫秒级时间: 1/1/2024 01:30:45 ... MM/DD/YYYY HH:MM:SS

2024x10,000,000,000 + 1x100,000,000 + 1x1,000,000 + 1x10,000 + 30x100 + 45x1 = 序列号。

然后您可以比较序列号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接