[英]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
.我建议不要使用返回值
0
、 1
和2
,而是使用<0
、 0
和>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
等、 qsort
或bsearch
的语义,可以使用简单的减法和与 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.这对
month
、 day
、 hour
和minute
字段的正常值有效。 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.