将 NTP 时间转换为日期时偏移 1 天

Getting offset by 1 day when converting NTP time to date

我正在尝试实现我自己的 NTP 客户端。

我可以发送和接收 NTP 消息,我现在需要做的是将其转换为 "real" 时间。我已经创建了一个函数来执行此操作,但出于某种原因,我得到了所有字段的正确信息,除了晚了 1 天的日期字段。

我还用笔、纸和计算器做了一些快速计算,我得到了相同的结果,所以一定是我遗漏了什么。

这是我的代码:

void setTime(uint32_t seconds, uint32_t fraction)
{
    int yearsPassed = seconds / (60 * 60 * 24 * 365);

    year = 1900 + yearsPassed;

    int leapYears = yearsPassed / 4;

    int secondsLeft = seconds - yearsPassed * 365 * 24 * 60 * 60;

    secondsLeft -= leapYears * 60 * 60 * 24;

    int daysPassed = secondsLeft / (60 * 60 * 24);

    secondsLeft -= daysPassed * 60 * 60 * 24;

    int hoursPassed = secondsLeft / (60*60);

    secondsLeft -= hoursPassed * 60 * 60;

    int minutesPassed = secondsLeft / 60;

    secondsLeft -= minutesPassed * 60;

    hour = hoursPassed + SUMMERTIME_OFFSET;
    minute = minutesPassed;
    second = secondsLeft;

    us = (fraction * (pow((float)10,(float)6)) / (pow((float)2,(float)32)));

    month = getMonth(daysPassed);
    day = getDay(month, daysPassed);
}

例如,使用此代码我可以获得时间 2015/4/28 14:3:15.351731,但日期应该是 29 而不是 28。我最初的想法是我计算的闰年是错误的,是少了 1 天,但这似乎是正确的。

编辑

getMonth() 和 getDay() 的代码。它们还没有完全实现,因为我想编写尽可能少的代码来测试它是否有效。

int getMonth(int daysPassed)
{
    if (daysPassed < 32)
        return 1;
    else if (daysPassed < 60)
        return 2;
    else if (daysPassed < 91)
        return 3;
    else if (daysPassed < 121)
        return 4;
    else if (daysPassed < 152)
        return 5;
    else 
        return 6;
}

int getDay(int month, int daysPassed)
{
    switch (month)
    {
    case 1:
        return daysPassed;
        break;
    case 2:
        return daysPassed - 31;
        break;
    case 3:
        return daysPassed - 59;
        break;
    case 4:
        return daysPassed - 90;
        break;
    case 5:
        return daysPassed - 120;
        break;
    default:
        return 6;
        break;
    }
}

您的 daysPast 上有一个 fencepost 错误,因为它是 completed 天,而不是 partial天。

考虑 1 秒的输入(哎呀,更好的是,让它成为一个单元测试),它应该解析为 1/1/1900 00:00:01 - 它会给你的 daysPast 作为 0虽然是过去的天数,但不考虑当天。

当然,在计算年中的第几天时,还需要考虑当年是否为闰年;为了完整性和 2100 年的兼容性,你的闰年算法有点天真。