简体   繁体   English

比较两个日期时间戳的算法

[英]Algorithm to compare two date time stamps

I need to implement a timestamp comparison in C (not using any libraries).我需要在 C 中实现时间戳比较(不使用任何库)。

I am trying to figure out an optimal algorithm as the routine is going to be used intensively.我正在尝试找出最佳算法,因为该例程将被大量使用。

My input data is two time stamps, a and b, each of one comprises the following:我的输入数据是两个时间戳,a 和 b,每个时间戳包含以下内容:

year
month
day
hour
minute

In C pseudocode:在 C 伪代码中:

struct Timestamp {
    int year;
    int month;
    int day;
    int hour;
    int minute;
};

struct Timestamp a;
struct Timestamp b;

I am trying several approaches including nested if's and a switch combining each value:我正在尝试几种方法,包括嵌套 if 和组合每个值的开关:

int timestamp_comparison(int a, int b) {
    if(a>b) return 2;
    if(a=b) return 1;
    if(a<b) return 0;
}
...
c_year = timestamp_comparison(a.year, b.year);
c_month = timestamp_comparison(a.month, b.month);
c_day = timestamp_comparison(a.day, b.day);
c_hour = timestamp_comparison(a.hour, b.hour);
c_minute = timestamp_comparison(a.minute, b.minute);

comparison = c_year * 10000 + c_month * 1000 + c_day * 100 + c_hour * 10 + c_minute;
...

But I would like to know if there is an already algorithm I could leverage on.但我想知道是否有一个我可以利用的算法。 I do not like to use external libraries.我不喜欢使用外部库。

Instead of using return values 0 , 1 and 2 , I suggest to use <0 , 0 and >0 .我建议不要使用返回值012 ,而是使用<00>0 This is more common, matches the semantics of strcmp etc., qsort or bsearch and can be implemented using simple subtraction and comparison with 0.这个比较常见,匹配strcmp等、 qsortbsearch的语义,可以使用简单的减法和与 0 的比较来实现。

/*
 * @retval <0 if a < b
 * @retval 0 if a == b
 * @retval >0 if a > b
 */
int compare_timestamps(struct Timestamp a, struct Timestamp b)
{
    int result;

    result = a.year - b.year;
    if(result != 0) return result;

    result = a.month - b.month;
    if(result != 0) return result;

    result = a.day - b.day;
    if(result != 0) return result;

    result = a.hour - b.hour;
    if(result != 0) return result;

    result = a.minute - b.minute;

    return result;
}

As mentioned in Jim Mischel's comment, the algorithm assumes that the subtraction doesn't result in integer rollover.正如 Jim Mischel 的评论中提到的,该算法假设减法不会导致整数翻转。 This is valid for normal values of month , day , hour and minute fields.这对monthdayhourminute字段的正常值有效。 It is a reasonable assumption for "usual" year values.这是对“通常”年份值的合理假设。 It will not be valid for the year field if abs(a.year) + abs(b.year) > INT_MAX .如果abs(a.year) + abs(b.year) > INT_MAX year字段abs(a.year) + abs(b.year) > INT_MAX To handle year values in the full range of INT_MIN .. INT_MAX the algorithm would have to be changed.要处理整个INT_MIN .. INT_MAX范围内的year值,必须更改算法。

When comparing the timestamps, 2 concerns come into play比较时间戳时,有两个问题会起作用

Range of year年份范围

If the used range of .year is [INT_MIN...INT_MAX] , avoid a.year - b.year as it may overflow.如果.year的使用范围是[INT_MIN...INT_MAX] ,请避免a.year - b.year因为它可能会溢出。

Primary values主要价值

Are the members always in their primary range?成员总是在他们的主要范围内吗? Example: Is minute in the range 0-59?示例: minute是否在 0-59 范围内?

Is so, a simple compare and returning -1,0,1 uses the common C idiom (a>b) - (a<b) , something many compilers recognize and emit efficient code.是这样,一个简单的比较和返回 -1,0,1 使用常见的 C 习语(a>b) - (a<b) ,这是许多编译器识别并发出有效代码的东西。

int timestamp_compare(const struct Timestamp *ts2, const struct Timestamp *ts1) {
  if (ts1->year  != ts2->year)  return (ts2->year  > ts1->year)  - (ts2->year  < ts1->year);
  if (ts1->month != ts2->month) return (ts2->month > ts1->month) - (ts2->month < ts1->month);
  if (ts1->day   != ts2->day)   return (ts2->day   > ts1->day)   - (ts2->day   < ts1->day);
  if (ts1->hour  != ts2->hour)  return (ts2->hour  > ts1->hour)  - (ts2->hour  < ts1->hour);
  return (ts2->day > ts1->day) - (ts2->day < ts1->day);
}

If not, form a linear count of minutes and then compare.如果不是,请形成分钟的线性计数,然后进行比较。

long long minutes(const struct Timestamp *ts) {
  return ((tbd_day_number(ts->year, ts->month, ts->day)*24LL + ts->hour)*60 + ts->minute;
}

int timestamp_compare(const struct Timestamp *ts2, const struct Timestamp *ts1) {
  long long m1 = minutes(ts1);
  long long m2 = minutes(ts2);
  return (m2 > m1) - (m2 < m1);
}

If your struct contains its members in a sorted manner, like in your case, (year is more significant than month, and so on...) and since in a struct, members are 'most likely' to be stored in a contiguous manner:如果您的结构以排序方式包含其成员,例如在您的情况下(年份比月份更重要,依此类推...)并且由于在结构中,成员“最有可能”以连续方式存储:

see: Using Contiguous Memory of C Struct Members请参阅: 使用 C 结构成员的连续内存

you can try using byte by byte comparison like so:您可以尝试使用逐字节比较,如下所示:

#include <stdlib.h>

// members of struct are stored contigously
struct Timestamp
{
    int year;
    int month;
    int day;
    int hour;
    int minute;
};


int timestamp_comparison(const struct Timestamp a, const struct Timestamp b)
{
    unsigned i;
    unsigned struct_size = sizeof(struct Timestamp) / sizeof(int);
    const int* t1 = (const int*)&a;
    const int* t2 = (const int*)&b;

    // compare byte by byte
    for (i = 0; i < struct_size; i++)
    {
        if (*t1 != *t2)
            return *t1 - *t2;

        ++t1;
        ++t2;
    }

    return 0;
}

int main()
{
    // example
    struct Timestamp a = {1, 1, 2, 1, 1};
    struct Timestamp b = {1, 1, 1, 7, 1};
    int comp = timestamp_comparison(a, b);

    return 0;
}



I'm not saying this is better, than the already posted answer, just different.我并不是说这比已经发布的答案更好,只是不同。 And for any other structs like yours, it'll work the same way.对于像您这样的任何其他结构,它的工作方式相同。

here a minor improvement:这里有一个小改进:

Your PC is working in binary so base 2 is what he can best您的 PC 以二进制方式运行,因此以 2 为基数是他最擅长的

You could replace:你可以替换:

comparison = c_year * 10000 + c_month * 1000 + c_day * 100 + c_hour * 10 + c_minute;

by (your values are all lower than 4) so you can: by(您的值都低于 4),因此您可以:

comparison = c_year * 256 + c_month * 64 + c_day * 16 + c_hour *4 + c_minute;

Or this (less readable but 'without' arithmetic):或者这个(可读性较差但“没有”算术):

comparison = c_year << 8 | c_month <<6 | c_day <<4 | c_hour <<2 | c_minute;

But if you really have a speed improvement by this, can only be validated with profiling.但是,如果您真的通过这种方式提高了速度,则只能通过分析进行验证。

depending on your data it could be faster only to compare what you need:根据您的数据,仅比较您需要的数据可能会更快:

int val;
if(1!=(val=timestamp_comparison(a.year, b.year)))
  return val;
if(1!=(val=timestamp_comparison(a.month, b.month)))
  return val;
if(1!=(val=timestamp_comparison(a.c_day, b.c_day)))
  return val;
if(1!=(val=timestamp_comparison(a.c_hour, b.c_hour)))
  return val;
return timestamp_comparison(a.c_minute, b.c_minute);

But as I mentioned above, profiling is you friend when it is about optimization.但正如我上面提到的,在优化方面,分析是你的朋友。


Ps ps

if(a>b) return 2;
if(a=b) return 1;
if(a<b) return 0;

is a bit unusual definition.是一个有点不寻常的定义。 More common is :更常见的是:

if(a>b) return value >=1
if(a=b) return 0;
if(a<b) return value <=-1

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

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