Попробую просуммировавть свои мысли. U -- число сек. от старта программы, R -- текущее реальное время (в секундах) полученное от какого-либо источника, B -- время (реальное) момента запуска, S -- время последней синхронизации от момента пуска программы, D -- ошибка накапливаемая за секунду, тактов таймера, Ts -- тактов таймера в секунду.
Изначально U:=0, B:=0, S:=0, D:=0. Таймер программируется на срабатывание раз в T:=Tps+D единиц счёта. В момент срабатывания вычисляется U:=U+1, таймер программируется на T:=T+Tps+D (таким образом тут нет накопления ошибки).
В какой-то момент времени происходит синхронизация (с временем N):
1) Если B==0 --> B:=R-U;
2) Если S==0 --> S:=U.
2.1) Иначе (S!=0) и ЕСЛИ U-S > minS тогда:
2.1.1) d:= Tps * (R-U-B) / (U-S) -- ошибка, тактов таймера за секунду.
2.1.2) Если |d| > maxD --> ничего не делать.
2.1.3) Иначе (|d| < maxD) --> D:=((N+1)*D+d)/N, где N -- небольшое целое...
3) B:=R-U;
4) S:=U.
Практически синхорнизация выполняется при вызове stime(N), например. time(time_t*) вычисляется как B+U.
Ограничение минимального интервала minS (на уровне десятков-сотен секунд) на котором проводится синхронизация нужно, чтобы не влияли прочие факторы (время передаётся через какой-то канал связи, с задержкой и т.п.)
Годный вариант? А как быть нехорошем случае, когда есть два источника времени (внешних), например. И периодически то с одним, то с другим синхронизируется... ?
Вариант, разрешить другой источник только в варианте, когда U-S < N*minS, а тот же источник, если U-S < minS.