Я пытаюсь реализовать свой собственный клиент NTP.
Я могу отправлять и получать сообщения NTP, и теперь мне нужно преобразовать их в «реальное» время. Я создал функцию, чтобы сделать это, но по какой-то причине я получаю все поля правильными, за исключением поля дня, которое на 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
как это завершено дней, а не количество частичный дней.
Рассмотрим ввод в 1 секунду (черт, лучше, сделайте это модульным тестом), который должен разрешиться до 01.01.1900 00:00:01 — это даст daysPast
как 0, который является числом прошедших дней, он не учитывает текущий день.
Конечно, вам также нужно учитывать, является ли текущий год високосным, при расчете дня в году; и для полноты, и для совместимости в 2100 году ваш алгоритм високосных лет — наивно.