Three methods of obtaining the date and time

Using snippets of code that I've found on this forum and elsewhere, here are three methods of obtaining the time and date that I've used.
The first method (and the one I prefer) uses the NIST Internet Time Service (ITS) and the Daytime Protocol. You'll have to do a little arithmetic to convert UTC to local time. I prefer using the ITS since the Daytime Protocol incorporates a two digit code (00 to 99) that indicates whether the United States is on Standard Time (ST) or Daylight Saving Time (DST).
The second method uses the Network Time Protocol (RFC-1305). This requires that your ESP8266 firmware incorporate the sntp and rtctime modules. See NodeMCU custom builds for firmware incorporating these modules. Again, you'll have to do the conversion from UTC to local time. You'll also have to determine when to adjust for Daylight Saving Time.
The third method retrieves the local date and time from the web site Time.is. This site looks up your location based on your IP address and provides your local time already compensated for Daylight Saving Time (if applicable). Although this method is probably the easiest of the three, its use is somewhat problematic since the terms of use for the site state: "Automatic refresh and any usage from within scripts and apps is forbidden."
Again, my thanks to you for your good work if you recognise some of your code here.
The first method (and the one I prefer) uses the NIST Internet Time Service (ITS) and the Daytime Protocol. You'll have to do a little arithmetic to convert UTC to local time. I prefer using the ITS since the Daytime Protocol incorporates a two digit code (00 to 99) that indicates whether the United States is on Standard Time (ST) or Daylight Saving Time (DST).
Code: Select all
-- connects to a NIST Daytime server to get the current date and time
TZ=-5 -- my time zone is Eastern Standard Time
year=0 -- global year
month=0 -- global month
day=0 -- global day
hour=0 -- global hour
minute=0 -- global minute
second=0 -- global second
function getDayTime()
local tt=0
local conn=net.createConnection(net.TCP,0)
conn:connect(13,"time.nist.gov")
-- on connection event handler
conn:on("connection",
function(conn, payload)
--print("Connected...")
end -- function
) -- end of on "connecttion" event handler
-- on receive event handler
conn:on("receive",
function(conn,payload)
--print(payload)
--1234567890123456789012345678901234567890123456789
-- JJJJJ YR-MO-DA HH:MM:SS TT L H msADV UTC(NIST) *
if string.sub(payload,39,47)=="UTC(NIST)" then
year=tonumber(string.sub(payload,8,9))+2000
month=tonumber(string.sub(payload,11,12))
day=tonumber(string.sub(payload,14,15))
hour=tonumber(string.sub(payload,17,18))
minute=tonumber(string.sub(payload,20,21))
second=tonumber(string.sub(payload,23,24))
tt=tonumber(string.sub(payload,26,27))
hour=hour+TZ -- convert from UTC to local time
if ((tt>1) and (tt<51)) or ((tt==51) and (hour>1)) or ((tt==1) and (hour<2)) then
hour=hour+1 -- daylight savings time currently in effect, add one hour
end
hour=hour%24
end -- if string.sub(payload,39,47)=="UTC(NIST)" then
end -- function
) -- end of on "receive" event handler
-- on disconnect event handler
conn:on("disconnection",
function(conn,payload)
--print("Disconnected...")
conn=nil
payload=nil
end -- function
) -- end of on "disconnecttion" event handler
end -- function getDayTime()
-- Execution starts here...
print("\ncontacting NIST server...")
getDayTime() -- contact the NIST daytime server for the current time and date
tmr.alarm(5,500,0, -- after a half second...
function()
if year~=0 then
print(string.format("%02d:%02d:%02d %02d/%02d/%04d",hour,minute,second,month,day,year))
else
print("Unable to get time and date from the NIST server.")
end
end
)
The second method uses the Network Time Protocol (RFC-1305). This requires that your ESP8266 firmware incorporate the sntp and rtctime modules. See NodeMCU custom builds for firmware incorporating these modules. Again, you'll have to do the conversion from UTC to local time. You'll also have to determine when to adjust for Daylight Saving Time.
Code: Select all
-- sync the ESP8266 Real Time Clock (RTC) to an NTP server
-- retrieve and display the time and date from the ESP8266 RTC
-- requires the sntp and rtctime firmware modules
timeZone=-4 -- time zone (Eastern Daylight Time); -5 for Eastern Standard Time
hour=0
minute=0
second=0
day=0
month=0
year=0
-- returns the hour, minute, second, day, month and year from the ESP8266 RTC seconds count (corrected to local time by tz)
function getRTCtime(tz)
function isleapyear(y) if ((y%4)==0) or (((y%100)==0) and ((y%400)==0)) == true then return 2 else return 1 end end
function daysperyear(y) if isleapyear(y)==2 then return 366 else return 365 end end
local monthtable = {{31,28,31,30,31,30,31,31,30,31,30,31},{31,29,31,30,31,30,31,31,30,31,30,31}} -- days in each month
local secs=rtctime.get()
local d=secs/86400
local y=1970
local m=1
while (d>=daysperyear(y)) do d=d-daysperyear(y) y=y+1 end -- subtract the number of seconds in a year
while (d>=monthtable[isleapyear(y)][m]) do d=d-monthtable[isleapyear(y)][m] m=m+1 end -- subtract the number of days in a month
secs=secs-1104494400-1104494400+(tz*3600) -- convert from NTP to Unix (01/01/1900 to 01/01/1970)
return (secs%86400)/3600,(secs%3600)/60,secs%60,m,d+1,y --hour, minute, second, month, day, year
end
print("\ncontacting NTP server...")
sntp.sync("0.pool.ntp.org") -- sync the ESP8266 RTC with the NTP server
tmr.alarm(0,500,0,
function()
-- get the hour, minute, second, day, month and year from the ESP8266 RTC
hour,minute,second,month,day,year=getRTCtime(timeZone)
if year ~= 0 then
-- format and print the hour, minute second, month, day and year retrieved from the ESP8266 RTC
print(string.format("%02d:%02d:%02d %02d/%02d/%04d",hour,minute,second,month,day,year))
--print(string.format("%02d:%02d:%02d %02d/%02d/%04d",getRTCtime(timeZone)))
else
print("Unable to get time and date from the NTP server.")
end
end
)
The third method retrieves the local date and time from the web site Time.is. This site looks up your location based on your IP address and provides your local time already compensated for Daylight Saving Time (if applicable). Although this method is probably the easiest of the three, its use is somewhat problematic since the terms of use for the site state: "Automatic refresh and any usage from within scripts and apps is forbidden."
Code: Select all
-- connects to the web site "time.is" to retrieve the local time and date
year=0 -- global year
month=0 -- global month
day=0 -- global day
dow=0 -- global day of week
hour=0 -- global hour
minute=0 -- global minute
second=0 -- global second
--connect to time.is to get the current time and date
function getTime()
-- return the number corresponding to the three letter abbreviation of the month
function nmonth(month) return (string.find("JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC",string.upper(month))+2)/3 end
-- return the number corresponding to the three letter abbreviation of the day of week
function ndow(dow) return (string.find("SUNMONTUEWEDTHUFRISAT",string.upper(dow))+2)/3 end
local conn=net.createConnection(net.TCP,0)
conn:connect(80,"time.is")
conn:on("connection",
function(conn, payload)
conn:send("HEAD / HTTP/1.1\r\n"..
"Host: time.is\r\n"..
"Accept: */*\r\n"..
"User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"..
"\r\n\r\n")
end --function
) --end of on "connection" event handler
conn:on("receive",
function(conn,payload)
--print(payload)
conn:close()
local p=string.find(payload,"Expires: ") -- find the time and date string in the payload from time.is
if p~=nil then
-- print(string.sub(payload,p,p+39))
-- extract numbers corresponfing to the hour, minute, second, day, month
-- and year from the payload received from time.is in response to our HEAD request
-- p+0123456789012345678901234567890123456789
-- Expires: Sat, 30 Jan 2016 06:15:11 -0500
dow=ndow(string.sub(payload,p+9,p+11))
hour=tonumber(string.sub(payload,p+26,p+27))
minute=tonumber(string.sub(payload,p+29,p+30))
second=tonumber(string.sub(payload,p+32,p+33))
day=tonumber(string.sub(payload,p+14,p+15))
month=nmonth(string.sub(payload,p+17,p+19))
year=tonumber(string.sub(payload,p+21,p+24))
else
-- print("time.is update failed!")
end
end --function
) --end of on "receive" event handler
conn:on("disconnection",
function(conn,payload)
conn=nil
payload=nil
end --function
) -- end of on "disconnecttion" event handler
end
-----------------------------------------------------------------------------
-- script execution starts here...
-----------------------------------------------------------------------------
print("\nContacting time.is...")
getTime() -- contact time.is for the current time and date
tmr.alarm(0,500,0, -- after a half second...
function()
if year ~= 0 then
print(string.format("%02d:%02d:%02d %02d/%02d/%04d",hour,minute,second,month,day,year))
else
print("Unable to get time and date from the time.is.")
end
end
)
Again, my thanks to you for your good work if you recognise some of your code here.