This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

How to correctly parse a long series of Timestamps and account for DST
#1
Hi,
I am creating a script to parse a JSON object full of weather data from https://api.met.no. I am developing a script that can produce a detailed forecast of the next 4 hours, plus a summary forecast for the next 9 days (individually).  I have it pretty much working, and thought I was doing well until... Daylight Savings Time is about to start in my country (on 28 March we will move from GMT to GMT+1). For the last month or so, I could parse their Json array perfectly and extract/process anything I needed, but the DST date is now looming and has manifested an issue in my script as the '28th-March-and-beyond' data is now in their JSON object. 

I'll gladly publish the whole thing once it's done, but for now, I have created this code snippet to portray the issue. In real life, you parse through an array of maybe 90 timeslices, each one identified by an ISO 8601 Date formatted string. I convert each one to an epoch timestamp, so I can later sort them into day-long slices, to do min/max calcs of the temperature etc. I don't show the looping here, but have instead hardcode a timestamp just before and just after the DST change to simulate it. I have also double-checked the time on my LM is correct, and set to Europe/Dublin, which is basically GMT. I don't want to set it to UTC (which never changes) because my LM is normally synced with NTP servers, which automatically does the DST change, and other schedules, etc rely on this..

The problem (i think) is that my LM is currently not in DST mode (correctly) but the script needs to selectively choose when to offset the times found in the JSON for DST in the list of dates as you roll over them... Hopefully, the code example explains this better!

Code:
local time_string_before_DST = "2021-03-27T06:00:00Z"
-- DST comes into effect in the hours between these two timestamps..
local time_string_after_DST  = "2021-03-28T06:00:00Z"

function conv_to_timestamp(string_to_convert) 
  pattern="(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:(%d+)(%u)"
  -- execute a match
  m_year,m_month,m_day,m_hour,m_min,m_sec,m_zone = string_to_convert:match(pattern) 
  --log(m_day,m_month,m_year,m_hour,m_min,m_sec,m_zone) 
  local calculated_timestamp=(os.time{year=m_year, month=m_month, day=m_day, hour=m_hour, min=m_min , sec=m_sec}) 
  return calculated_timestamp
end
  
local time_stamp_before_DST = conv_to_timestamp(time_string_before_DST)
local time_stamp_after_DST  = conv_to_timestamp(time_string_after_DST)

log("time_stamp_before_DST is: " .. time_stamp_before_DST) -- This outputs 1616824800, which is epoch for 27-03-2021 06:00:00, so is fine
log("time_stamp_after_DST is: " .. time_stamp_after_DST)   -- This outputs 1616907600, which is epoch for 28-03-2021 05:00:00, so is ONE HOUR too early. Need 1616911200 ...

-- Typical method found online to offset....
temp_date_1 = os.date("!*t") 
offset = os.time()-os.time(temp_date_1)
--log("offset "..offset) 

local my_corrected_timestamp1 = time_stamp_before_DST + offset
local my_corrected_timestamp2 = time_stamp_after_DST + offset

log("my_corrected_timestamp1 " .. my_corrected_timestamp1) -- Still 1616824800
log("my_corrected_timestamp2 " .. my_corrected_timestamp2) -- Still 1616907600, so still one hour out..

-- But then I though of checking for DST
if temp_date_1.isdst == true then log("temp_date_1 in a DST period") end
if temp_date_1.isdst == false then log("temp_date_1 is NOT in a DST period") end  -- This logs , so is true

temp_date_2 = os.date("!*t")
temp_date_2.isdst = true -- Seems to work, but How to apply this dynamically?
offset_2 = os.time()-os.time(temp_date_2)

local my_corrected_timestamp3 = time_stamp_before_DST + offset_2
local my_corrected_timestamp4 = time_stamp_after_DST + offset_2

log("my_corrected_timestamp3 " .. my_corrected_timestamp3) -- This outputs 1616828400, which is epoch for 27-03-2021 07:00:00, so is now one hour too late
log("my_corrected_timestamp4 " .. my_corrected_timestamp4) -- This outputs 1616911200, which is epoch for 27-03-2021 06:00:00, which is perfect...except the one above is now wrong..

-- How to determine when to apply the "isdst = true" trick, based on the incoming value ?
Reply
#2
I'll answer my own question... After experimentation, the answer is to just force ISDST to be FALSE for all timestamps in the first function.., which then always matches the content of the JSON feed, because they are only ever provided in UTC... I was mixing up DST and timezone offsets, which are different things...

This works for me now:

Code:
local time_string_before_DST = "2021-03-27T06:00:00Z"
-- DST comes into effect in the hours between these two timestamps..
local time_string_after_DST  = "2021-03-28T06:00:00Z"
 
function conv_to_timestamp(string_to_convert) 
  pattern="(%d+)%-(%d+)%-(%d+)%a(%d+)%:(%d+)%:(%d+)(%u)"
  -- execute a match
  m_year,m_month,m_day,m_hour,m_min,m_sec,m_zone = string_to_convert:match(pattern) 
  --log(m_day,m_month,m_year,m_hour,m_min,m_sec,m_zone) 
  local calculated_timestamp=(os.time{year=m_year, month=m_month, day=m_day, hour=m_hour, min=m_min , sec=m_sec, isdst=false})  -- add isdst=false here
  return calculated_timestamp
end


local time_stamp_before_DST = conv_to_timestamp(time_string_before_DST)
local time_stamp_after_DST  = conv_to_timestamp(time_string_after_DST)

log("time_stamp_before_DST is: " .. time_stamp_before_DST) -- This outputs 1616824800, which is epoch for 27-03-2021 06:00:00, so is fine
log("time_stamp_after_DST is: " .. time_stamp_after_DST)   -- This outputs 1616911200, which is epoch for 28-03-2021 06:00:00, so is fine
Reply


Forum Jump: