将 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 年的兼容性,你的闰年算法有点天真。
我正在尝试实现我自己的 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 年的兼容性,你的闰年算法有点天真。