我试图在C中实现两个简单的转换器,日期/时间到时间戳,反之亦然,不依赖于时间库例程,例如mktime等。
时间戳以秒为单位,日期/时间结构采用以下格式:
unsigned char year:0到99(表示范围2000到2099)
unsigned char month:1到12
unsigned char day:1到31
unsigned char小时:0到23
unsigned char分钟:0到59
unsigned char second:0到59
我想对dt2ts转换器有第二个意见(假设输入是合法的):
unsigned int dt2ts(const dt_t* dt)
{
static unsigned short days[] = {0,31,59,90,120,151,181,212,243,273,304,334};
return ((((dt->year*365+dt->year/4)+days[dt->month-1]+dt->day)*24+dt->hour)*60+dt->minute)*60+dt->second;
}
除此之外,我很感激帮助完成ts2dt转换器:
void ts2dt(unsigned int ts,dt_t* dt)
{
dt->second = ts%60; ts /= 60;
dt->minute = ts%60; ts /= 60;
dt->hour = ts%24; ts /= 24;
dt->day = ?????;
dt->month = ?????;
dt->year = ?????;
}
由于
答案 0 :(得分:2)
OP可以很好地处理小时,分钟,秒。对Y,M,D有点帮助。
注意:从2000年1月1日到2099年12月31日的天数至少需要16位整数。即使unsigned
为2个字节,以下内容仍然有效。
unsigned DivRem(unsigned Dividend, unsigned Divisor, unsigned *Remainder) {
unsigned Quotient = Dividend/Divisor;
*Remainder = Dividend - Quotient*Divisor;
return Quotient;
}
void Day2000ToYMD(unsigned DaySince2000Jan1, unsigned *Y, unsigned *M, unsigned *D) {
unsigned OlympiadDay; // Every 4 years is an Olympiad
*Y = 4*DivRem(DaySince2000Jan1, 365*4+1, &OlympiadDay);
*D = 1;
if (OlympiadDay >= (31+29-1)) { // deal with Feb 29th and after
OlympiadDay--;
if (OlympiadDay == (31+29-1)) {
(*D)++;
}
}
unsigned YearDay; // Day of the year 0 to 364
*Y += DivRem(OlympiadDay, 365, &YearDay);
static const unsigned short days[] = {0,31,59,90,120,151,181,212,243,273,304,334,365};
*M = 1;
while (days[*M] <= YearDay) (*M)++;
*D += YearDay - days[*M - 1];
}
[编辑]提供的答案试图将年度概念保持为1月1日至12月31日。由于这个答案不需要处理大约100年和400年的闰年,我我一直保持着这种风格。
一般情况下,一旦添加了这两条规则,如果将年初的一年移至3月1日并于2月28日/ 29日结束,则数学变得更容易。 FWIW,这个 是对朱利安/格里高利历的古代发展的更一致的看法。因此,* Oct * ober是第8个月,* Dec *余烬是第10个月。