2

我正在尝试在 C 中实现两个简单的转换器,日期/时间到时间戳,反之亦然,而不依赖于时间库例程,例如 mktime 等。

时间戳以秒为单位,日期/时间结构采用以下格式:

  • 无符号字符年份:0 到 99(代表范围 2000 到 2099)

  • 无符号字符月份:1 到 12

  • 无符号字符日:1 到 31

  • 无符号字符小时:0 到 23

  • 无符号字符分钟:0 到 59

  • 无符号字符秒: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   = ?????;
}

谢谢

4

1 回答 1

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 *ember 是第 10 个月。

于 2013-11-03T20:08:59.190 回答