mirror of
https://github.com/guanzhi/GmSSL.git
synced 2026-05-07 00:46:17 +08:00
496 lines
12 KiB
C
496 lines
12 KiB
C
#include "u_time.h"
|
|
|
|
//convert timestamp to struct tm
|
|
int GMSSL_gmtime(const time_t *timep, struct tm *tm_time)
|
|
{
|
|
time_t timestamp = *timep;
|
|
unsigned int four_year_num;
|
|
unsigned int one_year_hours;
|
|
|
|
const static unsigned char Days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
const static unsigned int ONE_YEAR_HOURS = 8760;
|
|
const static unsigned int FOUR_YEAR_HOURS = 35064;
|
|
|
|
if (timestamp > 0x7FFFFFFF)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
tm_time->tm_isdst = 0;
|
|
|
|
tm_time->tm_sec = (int)(timestamp % 60);
|
|
timestamp /= 60;
|
|
|
|
tm_time->tm_min = (int)(timestamp % 60);
|
|
timestamp /= 60;
|
|
|
|
tm_time->tm_wday = (int)(timestamp/24 + 4) % 7;
|
|
|
|
four_year_num = timestamp / FOUR_YEAR_HOURS;
|
|
|
|
tm_time->tm_year=(four_year_num << 2) + 70;
|
|
|
|
timestamp %= FOUR_YEAR_HOURS;
|
|
|
|
while (1)
|
|
{
|
|
one_year_hours = ONE_YEAR_HOURS;
|
|
|
|
if ((tm_time->tm_year & 3) == 0)
|
|
{
|
|
one_year_hours += 24;
|
|
}
|
|
|
|
if (timestamp < one_year_hours)
|
|
{
|
|
break;
|
|
}
|
|
|
|
tm_time->tm_year++;
|
|
timestamp -= one_year_hours;
|
|
}
|
|
|
|
tm_time->tm_hour=(int)(timestamp % 24);
|
|
|
|
timestamp /= 24;
|
|
timestamp++;
|
|
|
|
tm_time->tm_yday = timestamp-1;
|
|
|
|
if ((tm_time->tm_year & 3) == 0)
|
|
{
|
|
if (timestamp > 60)
|
|
{
|
|
timestamp--;
|
|
}
|
|
else if (timestamp == 60)
|
|
{
|
|
tm_time->tm_mon = 1;
|
|
tm_time->tm_mday = 29;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (tm_time->tm_mon = 0; Days[tm_time->tm_mon] < timestamp; tm_time->tm_mon++)
|
|
{
|
|
timestamp -= Days[tm_time->tm_mon];
|
|
}
|
|
|
|
tm_time->tm_mday = (int)(timestamp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//convert struct tm to timestamp
|
|
time_t GMSSL_timegm(struct tm *tm)
|
|
{
|
|
static const int msum [2][12] = {
|
|
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, /* normal years */
|
|
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} /* leap years */
|
|
};
|
|
static const int mlen [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}
|
|
};
|
|
static const int tmstr_year= 1900; /* base of 'tm_year' in 'struct tm' */
|
|
static const int epoch_year= 1970; /* unix timestamp epoch */
|
|
static const int base_year= 1601; /* start of a 400-year period: used to be 1601,
|
|
but this allows larger range (in 64 bit)
|
|
mind you, this is proleptic Gregorian */
|
|
int year, ytmp, dtmp, ytmpe, dtmpe;
|
|
int isleapyear;
|
|
long long t;
|
|
|
|
if (!tm) return -1;
|
|
|
|
year = tm->tm_year + tmstr_year;
|
|
isleapyear= (year%4==0) - (year%100==0) + (year%400==0);
|
|
|
|
/* days between 'current year' and 'epoch_year' has to be calculated
|
|
in three steps: */
|
|
|
|
/* 1. days between current year and 'base_year' */
|
|
ytmp = year - base_year;
|
|
dtmp = ytmp*365 + ytmp/4 - ytmp/100 + ytmp/400;
|
|
|
|
/* 2. days between 'epoch year' and 'base_year' */
|
|
ytmpe = epoch_year - base_year;
|
|
dtmpe = ytmpe*365 + ytmpe/4 - ytmpe/100 + ytmpe/400;
|
|
|
|
/* 3. days between 'current year' and 'epoch_year' */
|
|
t = dtmp - dtmpe;
|
|
|
|
t += msum[isleapyear][tm->tm_mon];
|
|
t += tm->tm_mday-1;
|
|
|
|
t = t*24 + tm->tm_hour;
|
|
t = t*60 + tm->tm_min;
|
|
t = t*60 + tm->tm_sec;
|
|
|
|
return t;
|
|
}
|
|
|
|
//offset to struct tm
|
|
int GMSSL_gmtime_adj(struct tm *tm, long offset_sec)
|
|
{
|
|
time_t t = GMSSL_timegm(tm);
|
|
if(t == -1)
|
|
return -1;
|
|
|
|
t += offset_sec;
|
|
|
|
return GMSSL_gmtime(&t,tm) == 0;
|
|
}
|
|
|
|
//convert generalizedtime to tm
|
|
int asn1_generalizedtime_to_tm(char *gtime,struct tm *tm)
|
|
{
|
|
static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 };
|
|
static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 };
|
|
char *a;
|
|
int n, i, l, o;
|
|
|
|
l = strlen(gtime);
|
|
a = gtime;
|
|
o = 0;
|
|
/*
|
|
* GENERALIZEDTIME is similar to UTCTIME except the year is represented
|
|
* as YYYY. This stuff treats everything as a two digit field so make
|
|
* first two fields 00 to 99
|
|
*/
|
|
if (l < 13)
|
|
goto err;
|
|
for (i = 0; i < 7; i++) {
|
|
if ((i == 6) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
|
|
i++;
|
|
if (tm)
|
|
tm->tm_sec = 0;
|
|
break;
|
|
}
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = a[o] - '0';
|
|
if (++o > l)
|
|
goto err;
|
|
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = (n * 10) + a[o] - '0';
|
|
if (++o > l)
|
|
goto err;
|
|
|
|
if ((n < min[i]) || (n > max[i]))
|
|
goto err;
|
|
if (tm) {
|
|
switch (i) {
|
|
case 0:
|
|
tm->tm_year = n * 100 - 1900;
|
|
break;
|
|
case 1:
|
|
tm->tm_year += n;
|
|
break;
|
|
case 2:
|
|
tm->tm_mon = n - 1;
|
|
break;
|
|
case 3:
|
|
tm->tm_mday = n;
|
|
break;
|
|
case 4:
|
|
tm->tm_hour = n;
|
|
break;
|
|
case 5:
|
|
tm->tm_min = n;
|
|
break;
|
|
case 6:
|
|
tm->tm_sec = n;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Optional fractional seconds: decimal point followed by one or more
|
|
* digits.
|
|
*/
|
|
if (a[o] == '.') {
|
|
if (++o > l)
|
|
goto err;
|
|
i = o;
|
|
while ((a[o] >= '0') && (a[o] <= '9') && (o <= l))
|
|
o++;
|
|
/* Must have at least one digit after decimal point */
|
|
if (i == o)
|
|
goto err;
|
|
}
|
|
|
|
if (a[o] == 'Z')
|
|
o++;
|
|
else if ((a[o] == '+') || (a[o] == '-')) {
|
|
int offsign = a[o] == '+' ? -1 : 1, offset = 0;
|
|
o++;
|
|
if (o + 4 > l)
|
|
goto err;
|
|
for (i = 7; i < 9; i++) {
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = a[o] - '0';
|
|
o++;
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = (n * 10) + a[o] - '0';
|
|
if ((n < min[i]) || (n > max[i]))
|
|
goto err;
|
|
if (tm) {
|
|
if (i == 7)
|
|
offset = n * 3600;
|
|
else if (i == 8)
|
|
offset += n * 60;
|
|
}
|
|
o++;
|
|
}
|
|
if (offset && !GMSSL_gmtime_adj(tm, offset * offsign))
|
|
return 0;
|
|
} else if (a[o]) {
|
|
/* Missing time zone information. */
|
|
goto err;
|
|
}
|
|
return (o == l);
|
|
err:
|
|
return (0);
|
|
}
|
|
|
|
//convert utctime to tm
|
|
int asn1_utctime_to_tm(struct tm *tm, char *utime)
|
|
{
|
|
static const int min[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };
|
|
static const int max[8] = { 99, 12, 31, 23, 59, 59, 12, 59 };
|
|
char *a;
|
|
int n, i, l, o;
|
|
|
|
l = strlen(utime);
|
|
a = utime;
|
|
o = 0;
|
|
|
|
if (l < 11)
|
|
goto err;
|
|
for (i = 0; i < 6; i++) {
|
|
if ((i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
|
|
i++;
|
|
if (tm)
|
|
tm->tm_sec = 0;
|
|
break;
|
|
}
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = a[o] - '0';
|
|
if (++o > l)
|
|
goto err;
|
|
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = (n * 10) + a[o] - '0';
|
|
if (++o > l)
|
|
goto err;
|
|
|
|
if ((n < min[i]) || (n > max[i]))
|
|
goto err;
|
|
if (tm) {
|
|
switch (i) {
|
|
case 0:
|
|
tm->tm_year = n < 50 ? n + 100 : n;
|
|
break;
|
|
case 1:
|
|
tm->tm_mon = n - 1;
|
|
break;
|
|
case 2:
|
|
tm->tm_mday = n;
|
|
break;
|
|
case 3:
|
|
tm->tm_hour = n;
|
|
break;
|
|
case 4:
|
|
tm->tm_min = n;
|
|
break;
|
|
case 5:
|
|
tm->tm_sec = n;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (a[o] == 'Z')
|
|
o++;
|
|
else if ((a[o] == '+') || (a[o] == '-')) {
|
|
int offsign = a[o] == '+' ? -1 : 1, offset = 0;
|
|
o++;
|
|
if (o + 4 > l)
|
|
goto err;
|
|
for (i = 6; i < 8; i++) {
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = a[o] - '0';
|
|
o++;
|
|
if ((a[o] < '0') || (a[o] > '9'))
|
|
goto err;
|
|
n = (n * 10) + a[o] - '0';
|
|
if ((n < min[i]) || (n > max[i]))
|
|
goto err;
|
|
if (tm) {
|
|
if (i == 6)
|
|
offset = n * 3600;
|
|
else if (i == 7)
|
|
offset += n * 60;
|
|
}
|
|
o++;
|
|
}
|
|
if (offset && !GMSSL_gmtime_adj(tm, offset * offsign))
|
|
return 0;
|
|
}
|
|
return o == l;
|
|
err:
|
|
return 0;
|
|
}
|
|
|
|
//convert tm to generalizedtime
|
|
int asn1_tm_to_generalizedtime(struct tm *tm, char *gtime)
|
|
{
|
|
char p[20] = {0};
|
|
int i = 0, j = 0;
|
|
static const int min[6] = { 0, 1, 1, 0, 0, 0 };
|
|
static const int max[6] = { 9999, 12, 31, 23, 59, 59};
|
|
|
|
//year
|
|
int year0 = tm->tm_year + 1900;
|
|
if(year0 < min[i] || year0 > max[i])
|
|
goto err;
|
|
p[j++] = year0 / 1000 + '0';
|
|
year0 = year0 % 1000;
|
|
p[j++] = year0 / 100 + '0';
|
|
year0 = year0 % 100;
|
|
p[j++] = year0 / 10 + '0';
|
|
year0 = year0 % 10;
|
|
p[j++] = year0 + '0';
|
|
i++;
|
|
|
|
//month
|
|
int mon0 = tm->tm_mon + 1;
|
|
if(mon0 < min[i] || mon0>max[i])
|
|
goto err;
|
|
p[j++] = mon0 /10 + '0';
|
|
mon0 = mon0%10;
|
|
p[j++] = mon0 + '0';
|
|
i++;
|
|
|
|
//day
|
|
int day0 = tm->tm_mday;
|
|
if(day0 < min[i] || day0>max[i])
|
|
goto err;
|
|
p[j++] = day0 /10 + '0';
|
|
day0 = day0%10;
|
|
p[j++] = day0 + '0';
|
|
i++;
|
|
|
|
//hour
|
|
int hour0 = tm->tm_hour;
|
|
if(hour0 < min[i] || hour0>max[i])
|
|
goto err;
|
|
p[j++] = hour0 /10 + '0';
|
|
hour0 = hour0%10;
|
|
p[j++] = hour0 + '0';
|
|
i++;
|
|
|
|
//min
|
|
int min0 = tm->tm_min;
|
|
if(min0 < min[i] || min0>max[i])
|
|
goto err;
|
|
p[j++] = min0 /10 + '0';
|
|
min0 = min0%10;
|
|
p[j++] = min0 + '0';
|
|
i++;
|
|
|
|
//sec
|
|
int sec0 = tm->tm_sec;
|
|
if(sec0 < min[i] || sec0>max[i])
|
|
goto err;
|
|
p[j++] = sec0 /10 + '0';
|
|
sec0 = sec0%10;
|
|
p[j++] = sec0 + '0';
|
|
|
|
p[j++] = 'Z';
|
|
|
|
memcpy(gtime,p,j);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
return -1;
|
|
}
|
|
|
|
|
|
//convert asn1 tm to utctime
|
|
int asn1_tm_to_utctime(struct tm *tm, char *utime)
|
|
{
|
|
char p[20] = {0};
|
|
int i = 0, j = 0;
|
|
static const int min[6] = { 0, 1, 1, 0, 0, 0 };
|
|
static const int max[6] = { 99, 12, 31, 23, 59, 59};
|
|
|
|
//year
|
|
int year0 = tm->tm_year % 100;
|
|
if(year0 < min[i] || year0 > max[i])
|
|
goto err;
|
|
p[j++] = year0 / 10 + '0';
|
|
year0 = year0 % 10;
|
|
p[j++] = year0 + '0';
|
|
i++;
|
|
|
|
//month
|
|
int mon0 = tm->tm_mon + 1;
|
|
if(mon0 < min[i] || mon0>max[i])
|
|
goto err;
|
|
p[j++] = mon0 /10 + '0';
|
|
mon0 = mon0%10;
|
|
p[j++] = mon0 + '0';
|
|
i++;
|
|
|
|
//day
|
|
int day0 = tm->tm_mday;
|
|
if(day0 < min[i] || day0>max[i])
|
|
goto err;
|
|
p[j++] = day0 /10 + '0';
|
|
day0 = day0%10;
|
|
p[j++] = day0 + '0';
|
|
i++;
|
|
|
|
//hour
|
|
int hour0 = tm->tm_hour;
|
|
if(hour0 < min[i] || hour0>max[i])
|
|
goto err;
|
|
p[j++] = hour0 /10 + '0';
|
|
hour0 = hour0%10;
|
|
p[j++] = hour0 + '0';
|
|
i++;
|
|
|
|
//min
|
|
int min0 = tm->tm_min;
|
|
if(min0 < min[i] || min0>max[i])
|
|
goto err;
|
|
p[j++] = min0 /10 + '0';
|
|
min0 = min0%10;
|
|
p[j++] = min0 + '0';
|
|
i++;
|
|
|
|
//sec
|
|
int sec0 = tm->tm_sec;
|
|
if(sec0 < min[i] || sec0>max[i])
|
|
goto err;
|
|
p[j++] = sec0 /10 + '0';
|
|
sec0 = sec0%10;
|
|
p[j++] = sec0 + '0';
|
|
|
|
p[j++] = 'Z';
|
|
memcpy(utime,p,j);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
return -1;
|
|
} |