Openssl 代码中提供了函数 ASN1_TIME_set ,把 time_t 格式的时间转化为 ASN1_TIME

函数原型为

ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t)

但是没有找到类似 ASN1_TIME_get 函数,把 ASN1_TIME 转化为 time_t

从网上找个代码,实现了 ASN1_TIME_get ,测试结果正确。 [win2003 VC6 下测试通过 ]

代码:

int mypint( const char ** s,

int n,

int min,

int max,

int * e

)

{

int retval = 0;

while (n) {

if (**s < '0' || **s > '9') { *e = 1; return 0; }

retval *= 10;

retval += **s - '0';

--n; ++(*s);

}

if (retval < min || retval > max) *e = 1;

return retval;

}

time_t ASN1_TIME_get ( ASN1_TIME * a,

int *err

)

{

char days[2][12] =

{

{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },

{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }

};

int dummy;

const char *s;

int generalized;

struct tm t;

int i, year, isleap, offset;

time_t retval;

if (err == NULL) err = &dummy;

if (a->type == V_ASN1_GENERALIZEDTIME) {

generalized = 1;

} else if (a->type == V_ASN1_UTCTIME) {

generalized = 0;

} else {

*err = 1;

return 0;

}

s = a->data; // Data should be always null terminated

if (s == NULL || s[a->length] != '\0') {

*err = 1;

return 0;

}

*err = 0;

if (generalized) {

t.tm_year = mypint(&s, 4, 0, 9999, err) - 1900;

} else {

t.tm_year = mypint(&s, 2, 0, 99, err);

if (t.tm_year < 50) t.tm_year += 100;

}

t.tm_mon = mypint(&s, 2, 1, 12, err) - 1;

t.tm_mday = mypint(&s, 2, 1, 31, err);

// NOTE: It's not yet clear, if this implementation is 100% correct

// for GeneralizedTime... but at least misinterpretation is

// impossible --- we just throw an exception

t.tm_hour = mypint(&s, 2, 0, 23, err);

t.tm_min = mypint(&s, 2, 0, 59, err);

if (*s >= '0' && *s <= '9') {

t.tm_sec = mypint(&s, 2, 0, 59, err);

} else {

t.tm_sec = 0;

}

if (*err) return 0; // Format violation

if (generalized) {

// skip fractional seconds if any

while (*s == '.' || *s == ',' || (*s >= '0' && *s <= '9')) ++s;

// special treatment for local time

if (*s == 0) {

t.tm_isdst = -1;

retval = mktime(&t); // Local time is easy :)

if (retval == (time_t)-1) {

*err = 2;

retval = 0;

}

return retval;

}

}

if (*s == 'Z') {

offset = 0;

++s;

} else if (*s == '-' || *s == '+') {

i = (*s++ == '-');

offset = mypint(&s, 2, 0, 12, err);

offset *= 60;

offset += mypint(&s, 2, 0, 59, err);

if (*err) return 0; // Format violation

if (i) offset = -offset;

} else {

*err = 1;

return 0;

}

if (*s) {

*err = 1;

return 0;

}

// And here comes the hard part --- there's no standard function to

// convert struct tm containing UTC time into time_t without

// messing global timezone settings (breaks multithreading and may

// cause other problems) and thus we have to do this "by hand"

//

// NOTE: Overflow check does not detect too big overflows, but is

// sufficient thanks to the fact that year numbers are limited to four

// digit non-negative values.

retval = t.tm_sec;

retval += (t.tm_min - offset) * 60;

retval += t.tm_hour * 3600;

retval += (t.tm_mday - 1) * 86400;

year = t.tm_year + 1900;

if ( sizeof (time_t) == 4) {

// This is just to avoid too big overflows being undetected, finer

// overflow detection is done below.

if (year < 1900 || year > 2040) *err = 2;

}

// FIXME: Does POSIX really say, that all years divisible by 4 are

// leap years (for consistency)??? Fortunately, this problem does

// not exist for 32-bit time_t and we should'nt be worried about

// this until the year of 2100 :)

isleap = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);

for (i = t.tm_mon - 1; i >= 0; --i) retval += days[isleap][i] * 86400;

retval += (year - 1970) * 31536000;

if (year < 1970) {

retval -= ((1970 - year + 2) / 4) * 86400;

if ( sizeof (time_t) > 4) {

for (i = 1900; i >= year; i -= 100) {

if (i % 400 == 0) continue ;

retval += 86400;

}

}

if (retval >= 0) *err = 2;

} else {

retval += ((year - 1970 + 1) / 4) * 86400;

if ( sizeof (time_t) > 4) {

for (i = 2100; i < year; i += 100) {

// The following condition is the reason to

// start with 2100 instead of 2000

if (i % 400 == 0) continue ;

retval -= 86400;

}

}

if (retval < 0) *err = 2;

}

if (*err) retval = 0;

return retval;

}