NTP rollover-safe design with ESP8266 (Curiosity)
concatenation of context sensitive and context-free is context sensitive or not?
Mathematically, why does mass matrix / load vector lumping work?
Giant Steps - Coltrane and Slonimsky
Compiling C files on Ubuntu and using the executable on Windows
What makes Ada the language of choice for the ISS's safety-critical systems?
How do I prevent employees from either switching to competitors or opening their own business?
Should I give professor gift at the beginning of my PhD?
Meaning of 'lose their grip on the groins of their followers'
Overlapping String-Blocks
Is a lack of character descriptions a problem?
Pre-1972 sci-fi short story or novel: alien(?) tunnel where people try new moves and get destroyed if they're not the correct ones
Is using haveibeenpwned to validate password strength rational?
Does Disney no longer produce hand-drawn cartoon films?
Arriving at the same result with the opposite hypotheses
Why can my keyboard only digest 6 keypresses at a time?
How come the nude protesters were not arrested?
Second (easy access) account in case my bank screws up
Zeros of the Hadamard product of holomorphic functions
What is the actual quality of machine translations?
Can U.S. Tax Forms Be Legally HTMLified?
Generate basis elements of the Steenrod algebra
Soft question: Examples where lack of mathematical rigour cause security breaches?
How did old MS-DOS games utilize various graphic cards?
How to use memset in c++?
NTP rollover-safe design with ESP8266 (Curiosity)
The Arduino NTP implementation is rather naive in some respects. It basically just grabs the time in seconds from the raw packet, and then converts it to Unix time via subtraction. How would it be possible to create an implementation that is safe from at least this next NTP rollover (due in 2036)? I'd rather not design something that might suddenly fail in strange ways in a decade or two when I have forgotten why it might do so (but it's not horribly important if it's not easily fixed).
If it can make it to 2100, I'd have larger problems (the RTC would crap itself), so just this rollover is fine.
The existing implementation (https://github.com/arduino-libraries/NTPClient/blob/master/NTPClient.cpp):
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
esp8266 time
add a comment |
The Arduino NTP implementation is rather naive in some respects. It basically just grabs the time in seconds from the raw packet, and then converts it to Unix time via subtraction. How would it be possible to create an implementation that is safe from at least this next NTP rollover (due in 2036)? I'd rather not design something that might suddenly fail in strange ways in a decade or two when I have forgotten why it might do so (but it's not horribly important if it's not easily fixed).
If it can make it to 2100, I'd have larger problems (the RTC would crap itself), so just this rollover is fine.
The existing implementation (https://github.com/arduino-libraries/NTPClient/blob/master/NTPClient.cpp):
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
esp8266 time
add a comment |
The Arduino NTP implementation is rather naive in some respects. It basically just grabs the time in seconds from the raw packet, and then converts it to Unix time via subtraction. How would it be possible to create an implementation that is safe from at least this next NTP rollover (due in 2036)? I'd rather not design something that might suddenly fail in strange ways in a decade or two when I have forgotten why it might do so (but it's not horribly important if it's not easily fixed).
If it can make it to 2100, I'd have larger problems (the RTC would crap itself), so just this rollover is fine.
The existing implementation (https://github.com/arduino-libraries/NTPClient/blob/master/NTPClient.cpp):
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
esp8266 time
The Arduino NTP implementation is rather naive in some respects. It basically just grabs the time in seconds from the raw packet, and then converts it to Unix time via subtraction. How would it be possible to create an implementation that is safe from at least this next NTP rollover (due in 2036)? I'd rather not design something that might suddenly fail in strange ways in a decade or two when I have forgotten why it might do so (but it's not horribly important if it's not easily fixed).
If it can make it to 2100, I'd have larger problems (the RTC would crap itself), so just this rollover is fine.
The existing implementation (https://github.com/arduino-libraries/NTPClient/blob/master/NTPClient.cpp):
unsigned long highWord = word(this->_packetBuffer[40], this->_packetBuffer[41]);
unsigned long lowWord = word(this->_packetBuffer[42], this->_packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
this->_currentEpoc = secsSince1900 - SEVENZYYEARS;
esp8266 time
esp8266 time
edited May 30 at 23:20
VE7JRO♦
1,80151324
1,80151324
asked May 30 at 21:00
RDragonrydrRDragonrydr
429
429
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
This implementation is perfectly fine. The calculations are done with
unsigned numbers, so they are naturally rollover safe. The day NTP time
rolls over, secsSince1900 will become a very small number, and
subtracting SEVENZYYEARS from it will cause an extra roll over. Owing
to the rules of modular arithmetics, these two rollovers compensate and
you are guaranteed to get the correct result modulo
232 s.
In the end, you get a Unix time as an unsigned 32-bit integer. Unix time
is traditionally signed, which makes the 32-bit representation roll over
in January 2038. The authors of this library have instead chosen to
represent it as an unsigned number, which means it will roll over in
February 2106.
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the lowNbits of anN x Nmultiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?
– Peter Cordes
May 31 at 6:21
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("schematics", function ()
StackExchange.schematics.init();
);
, "cicuitlab");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "540"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2farduino.stackexchange.com%2fquestions%2f65883%2fntp-rollover-safe-design-with-esp8266-curiosity%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
This implementation is perfectly fine. The calculations are done with
unsigned numbers, so they are naturally rollover safe. The day NTP time
rolls over, secsSince1900 will become a very small number, and
subtracting SEVENZYYEARS from it will cause an extra roll over. Owing
to the rules of modular arithmetics, these two rollovers compensate and
you are guaranteed to get the correct result modulo
232 s.
In the end, you get a Unix time as an unsigned 32-bit integer. Unix time
is traditionally signed, which makes the 32-bit representation roll over
in January 2038. The authors of this library have instead chosen to
represent it as an unsigned number, which means it will roll over in
February 2106.
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the lowNbits of anN x Nmultiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?
– Peter Cordes
May 31 at 6:21
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
add a comment |
This implementation is perfectly fine. The calculations are done with
unsigned numbers, so they are naturally rollover safe. The day NTP time
rolls over, secsSince1900 will become a very small number, and
subtracting SEVENZYYEARS from it will cause an extra roll over. Owing
to the rules of modular arithmetics, these two rollovers compensate and
you are guaranteed to get the correct result modulo
232 s.
In the end, you get a Unix time as an unsigned 32-bit integer. Unix time
is traditionally signed, which makes the 32-bit representation roll over
in January 2038. The authors of this library have instead chosen to
represent it as an unsigned number, which means it will roll over in
February 2106.
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the lowNbits of anN x Nmultiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?
– Peter Cordes
May 31 at 6:21
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
add a comment |
This implementation is perfectly fine. The calculations are done with
unsigned numbers, so they are naturally rollover safe. The day NTP time
rolls over, secsSince1900 will become a very small number, and
subtracting SEVENZYYEARS from it will cause an extra roll over. Owing
to the rules of modular arithmetics, these two rollovers compensate and
you are guaranteed to get the correct result modulo
232 s.
In the end, you get a Unix time as an unsigned 32-bit integer. Unix time
is traditionally signed, which makes the 32-bit representation roll over
in January 2038. The authors of this library have instead chosen to
represent it as an unsigned number, which means it will roll over in
February 2106.
This implementation is perfectly fine. The calculations are done with
unsigned numbers, so they are naturally rollover safe. The day NTP time
rolls over, secsSince1900 will become a very small number, and
subtracting SEVENZYYEARS from it will cause an extra roll over. Owing
to the rules of modular arithmetics, these two rollovers compensate and
you are guaranteed to get the correct result modulo
232 s.
In the end, you get a Unix time as an unsigned 32-bit integer. Unix time
is traditionally signed, which makes the 32-bit representation roll over
in January 2038. The authors of this library have instead chosen to
represent it as an unsigned number, which means it will roll over in
February 2106.
answered May 30 at 22:04
Edgar BonetEdgar Bonet
25.6k22546
25.6k22546
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the lowNbits of anN x Nmultiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?
– Peter Cordes
May 31 at 6:21
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
add a comment |
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the lowNbits of anN x Nmultiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?
– Peter Cordes
May 31 at 6:21
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
Huh. That's actually rather cool. I knew of a similar method for millis(), but didn't know this worked for NTP as well. Thanks!
– RDragonrydr
May 30 at 23:09
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the low
N bits of an N x N multiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?– Peter Cordes
May 31 at 6:21
@RDragonrydr: carry propagates from low to high in addition/subtraction. The low bits of the result do not depend on any higher bit positions, so if you want a 32-bit result it's always safe to truncate your inputs instead of doing a 64-bit subtract and truncating the result. Same for left shift, or the low
N bits of an N x N multiply. See also Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?– Peter Cordes
May 31 at 6:21
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
I knew that, but I didn't know that the Arduino's method would manage to handle the rollover in NTP, not quite accidentally, but without needing to detect it per se. I figured that, since the time is an absolute delta past a certain start date, that any rollover would HAVE to give the wrong time once it occurred.
– RDragonrydr
May 31 at 18:31
add a comment |
Thanks for contributing an answer to Arduino Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2farduino.stackexchange.com%2fquestions%2f65883%2fntp-rollover-safe-design-with-esp8266-curiosity%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown