Page 1 of 1

Date and time calculations in dzvents

Posted: Tuesday 29 January 2019 13:11
by rrozema
dzvents is my first contact with lua. I can understand lua's logic constructs and even the event based logic in dzvents. But the time and date functionality keeps eluding me. Can someone please post some sample code that illustrates the proper way to do these actions in dzvents?

I will give some examples of things i'd like to know:

- Test if a particular datetime is after (greater than) a given datetime.

- Calculate the datetime value that is n seconds after a given datetime. And calculate the datetime value that is n minutes, hours, days, weeks, months, years, etc after a given datetime.

- Calculate the datetime value that is n seconds before a given datetime.

- Calculate the number of seconds or minutes or hours or etc between 2 given datetime values.

- Calculate only the date part of a given datetime value.

Calculate only the time part of a given datetime value.

- Get the current time in UTC (no daylight saving time differences)

- Calculate the UTC equivalent for a given datetime plus timezone.

Re: Date and time calculations in dzvents

Posted: Tuesday 29 January 2019 17:40
by waaren
rrozema wrote: Tuesday 29 January 2019 13:11 dzvents is my first contact with lua. I can understand lua's logic constructs and even the event based logic in dzvents. But the time and date functionality keeps eluding me. Can someone please post some sample code that illustrates the proper way to do these actions in dzvents?
Don't know if these example are a proper way of fiddling with date / times but atleast they are A way.

Code: Select all

-- timeExamples.lua

return {
    on      =   {   
                    timer           =   { "every minute"},
                    -- timer           =   { "never"},
                   
                },

    logging =   {   level           =   domoticz.LOG_DEBUG,
                    marker          =   "timeExamples"    },

    execute = function(dz)
        local Time = require('Time')
        
       
        local now           = Time() -- current time
        local month
        local today         = dz.time.rawDate
        local tonight       = today .. " 23:59"

        local function lpad(str, len, char)
            if char == nil then char = ' ' end
            return string.rep(char, len - #str) .. str
        end
        
        local function logWrite(str,level)             -- Support function for shorthand debug log statements
            dz.log(tostring(str),level or dz.LOG_DEBUG)
        end
    
        local function header(str)
            logWrite("");logWrite(lpad("",80,"="));logWrite(lpad(str,42));logWrite(lpad("",80,"="))
        end
        
        local function isFirstTimeEarlier(firstTime,lastTime)  -- Test if a particular datetime is after (greater than) a given datetime.
           return firstTime.compare(lastTime).compare < 0 
        end
        
        local function newdate(base,secs,minutes,hours,days,years)
            local day, month, year = string.match('03-05-2014', '(%d%d)-(%d%d)-(%d%d%d%d)')
        end
 
        local function makeSeconds(sec, min, hour, day, month, year ) -- simplified (month=30, year=365)
            if sec  == nil then sec  = 0 end
            if min  == nil then min  = 0 else min = min * 60 end
            if hour == nil then hour = 0 else hour = hour * 3600 end
            if day  == nil then day  = 0 else day  = day * 24 * 3600 end
            if year == nil then year = 0 else year = year * 365 * 24 * 3600 end
            return sec + min + hour + day + year
        end
        
        local function getTimezone()  -- in seconds
            local now = os.time()
            return os.difftime(now, os.time(os.date("!*t", now))) 
        end
        
        local function getTZOffset(timezone)
            local h, m = math.modf(timezone / 3600)
            return string.format("%+.4d", 100 * h + 60 * m)
        end
        
        header("From time()")
        logWrite ("now                           ==>> "  .. tostring(now))
        logWrite ("now.year                      ==>> "  .. tostring(now.year))
        logWrite ("now.month                     ==>> "  .. tostring(now.month))
        logWrite ("now.day                       ==>> "  .. tostring(now.day))
        logWrite ("now.hour                      ==>> "  .. tostring(now.hour))
        logWrite ("now.min                       ==>> "  .. tostring(now.min))
        logWrite ("now.sec                       ==>> "  .. tostring(now.sec))
        logWrite ("now.isdst                     ==>> "  .. tostring(now.isdst))      -- daylight saving time

        header("From dz.time()")
        logWrite ("now                           ==>> "  .. tostring(dz.time))
        logWrite ("now.year                      ==>> "  .. tostring(dz.time.year))
        logWrite ("now.month                     ==>> "  .. tostring(dz.time.month))
        logWrite ("now.day                       ==>> "  .. tostring(dz.time.day))
        logWrite ("now.hour                      ==>> "  .. tostring(dz.time.hour))
        logWrite ("now.min                       ==>> "  .. tostring(dz.time.min))
        logWrite ("now.sec                       ==>> "  .. tostring(dz.time.sec))
        logWrite ("now.isdst                     ==>> "  .. tostring(dz.time.isdst))      -- daylight saving time
        logWrite ("now.isUTC                     ==>> "  .. tostring(dz.time.isUTC))      -- UTC time

        header("from dz.time")
        logWrite ("current                        ==>> "  .. tostring(dz.time.raw))
        logWrite ("today                          ==>> "  .. tostring(today))
        logWrite ("tonight                        ==>> "  .. tostring(tonight))

        header("constructed time objects")   
        local pastTime      = Time('2016-3-12 07:35:00')        
        local futureTime    = Time('2022-5-10 07:35:00')        
        local playTime      = Time(dz.time.raw)        
              
        logWrite ("pastTime                       ==>> "  .. tostring(pastTime.raw))
        logWrite ("futureTime                     ==>> "  .. tostring(futureTime.raw))
        logWrite ("Playtime                       ==>> "  .. tostring(playTime.raw))
        
        header("check times")
        logWrite("pastTime   > now ?              ==>> " .. tostring(isFirstTimeEarlier(pastTime,playTime)))
        logWrite("futureTime > now ?              ==>> " .. tostring(isFirstTimeEarlier(futureTime,playTime)))

        header("Time calculations")    
           -- os.time calculates the number of seconds since 1/1/1970 00:00:00 given a time object
        logWrite("now                             ==>> " ..  os.date("%A, %d %B %Y (%H:%M:%S)",os.time(playTime)))
        
        -- os.date formats the number o seconds from os.time in the requested format
        logWrite("now + 120 sec                   ==>> " .. os.date("%A, %d %B %Y (%H:%M:%S)",os.time(playTime) + makeSeconds(nil,2))) 
        logWrite("now + some time                 ==>> " .. os.date("%A, %d %B %Y (%H:%M:%S)",os.time(playTime) + makeSeconds(1,2,3,4,5,6))) -- plus 6 years, 5 months etc 
        logWrite("now - some time years           ==>> " .. os.date("%A, %d %B %Y (%H:%M:%S)",os.time(playTime) - makeSeconds(1,2,3,4,5,6))) -- minus 6 years, 5 months etc 
        
        header("Time deltas")    
        logWrite("years  between  now and future  ==>> " .. dz.utils.round(pastTime.compare(futureTime).days / 365,1))
        logWrite("months between  now and future  ==>> " .. dz.utils.round(pastTime.compare(futureTime).days / 30,1))
        logWrite("days   between  now and future  ==>> " .. pastTime.compare(futureTime).days)
        logWrite("hours  between  now and future  ==>> " .. pastTime.compare(futureTime).hours)
        logWrite("minutes between now and future  ==>> " .. pastTime.compare(futureTime).minutes)
        logWrite("seconds between now and future  ==>> " .. pastTime.compare(futureTime).seconds)

        header("parts of date")
        logWrite("Datepart only                   ==>> " .. playTime.rawDate)
        logWrite("Timepart only                   ==>> " .. playTime.rawTime)

        header("UTC stuff")
        local playTimeUTC = os.date("!*t")
        logWrite("UTC Time                        ==>> "  .. os.date("%A, %d %B %Y (%H:%M:%S)",os.time(playTimeUTC)))
        logWrite("UTC Time ISO                    ==>> "  .. playTime.getISO())
        logWrite("UTC Time diff                   ==>> "  .. getTimezone() / 3600)
        logWrite("UTC Time diff                   ==>> "  .. getTZOffset(getTimezone()))
        logWrite("UTC Time calc                   ==>> "  .. os.date("%A, %d %B %Y (%H:%M:%S)",os.time(playTime) - makeSeconds(getTimezone())))

        logWrite("")
    end
}

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 6:43
by rrozema
Very helpful @waaren. Thank you

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 11:12
by dannybloe
Why don't you use dzVents Time object for this. Afaik it can do all of the above. Especially when you use the compare function.

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 12:11
by rrozema
I agree, that api looked promising, however i did try it and it didn't quite work as expected at the time. I think it was because of the many different date/time storage formats lua provides... At least to me it wasn't clear how to get done what i needed. I will try again and let you know what i find.

I didn't get the compare to work at first. From waaren's example i now see how it is supposed to work, but the syntax looks too complex to me. I'm much more familiar with something like having a property function <object>.gt(<another object>) returning true or false. Plus other variants like .gte() for greater-than-or-equal, .lt() for less-than, .lte() for less-than-or-equal, .eq() for equal and .neq() for not-equal.

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 12:55
by dannybloe
The .compare attribute of the compare() results should give you just that information I believe. I created the Time object and the compare function so you don't have to deal with Lua's horrible date/time support.

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 13:24
by rrozema
I know that now. But it is not intuitive: I couldn't figure out how to work with it without an example of how to use it. And even now it still looks overcomplicated with a conpare() function and an additional compare property.

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 13:26
by dannybloe
Well, it's one line of code. But if that's too complicated then I'd say use the Lua functions. You'll love them :-p

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 13:30
by rrozema
:-) thanks. I'm just suggesting that further improvements may be possible.

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 15:01
by dannybloe
I know :-) Ideas and pull-request are always welcome.

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 21:50
by papoo
in Time documentation i dont see timestamp support. is there a way to use with? (to use with some APi for example)

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 22:12
by waaren
papoo wrote: Sunday 03 February 2019 21:50 in Time documentation i dont see timestamp support. is there a way to use with? (to use with some APi for example)
Try

Code: Select all

domoticz.time.dDate 
same as

Code: Select all

os.time(domoticz.time)

Re: Date and time calculations in dzvents

Posted: Sunday 03 February 2019 23:13
by papoo
thanks, work fine

Re: Date and time calculations in dzvents

Posted: Thursday 02 April 2020 12:03
by Piacco
Hello,

I'm trying to get the actual month and the past month as an string.

But I'm getting this error:
2020-04-02 11:55:41.607 Error: dzVents: Error: (3.0.1) Get actual and past month: ...oticz/scripts/dzVents/generated_scripts/Actual_Month.lua:18: attempt to call a string value (field 'monthName')

Could someone explain me what is going wrong :shock:

Code: Select all

return 
{

on = { 
	devices = { 'Tussenruimte'} ,
       
    },

 logging = 
    {
        level = domoticz.LOG_DEBUG,
        marker = "Get actual and past month"
    },

    execute = function(dz, device)
	    
	    os.time(dz.time)
	    local ActualMonth = dz.time.monthName()
            local PastMonth = dz.time.monthName(-1)
		dz.log(ActualMonth)
		dz.log(PastMonth)
	
	   
     end
}
Greetings,
Piacco

Re: Date and time calculations in dzvents  [Solved]

Posted: Thursday 02 April 2020 13:09
by waaren
Piacco wrote: Thursday 02 April 2020 12:03 I'm trying to get the actual month and the past month as an string. Could someone explain me what is going wrong :shock:
You try to use an attribute as a function.

Code: Select all

return
{

    on = 
    {
        devices = 
        { 
            'Tussenruimte'
        },
    },

    logging =
    {
        level = domoticz.LOG_DEBUG,
        marker = 'Get actual and past month',
    },

    execute = function(dz)

        local ActualMonth = dz.time.monthName  -- monthName is attribute so do not use () 
        dz.log('Actual month is ' .. ActualMonth, dz.LOG_DEBUG)

        -- addDays is a method (function) of dz.time . It returns a time object
        local someTime = dz.time.addDays(-1 * dz.time.day) -- make a new time object current minus today's days (is last day of previous month)

        local lastMonth = someTime.monthName
        dz.log('Last month is '  .. lastMonth, dz.LOG_DEBUG)

    end
}

Re: Date and time calculations in dzvents

Posted: Wednesday 08 April 2020 21:50
by Piacco
Thanks again Waaren :D
Now I can go on with my script

Re: Date and time calculations in dzvents

Posted: Saturday 27 February 2021 20:36
by Piacco
I have a little script to wake up my chickens. It works well, I just want to make it a little bit smarter.
When the time between sunset and sunrise is more than 13 hours, then the light does not need to be switched on.
Has dzVents the possibility to extract sunrise and sunset?

ps. What happend when sunrise is equal to 6 o'clock, is the light turned on and off?

Code: Select all

return {
	on = {
		timer = { 
		          'at 06:00',
		          'at 20:00',
		          'at sunrise',
		          'at sunset',
		        },
		   },
	
    logging = { level = domoticz.LOG_DEBUG, marker = 'Kipenhok' },
		
	execute = function(dz)
              
            if  dz.time.matchesRule("between 06:00 and sunrise") == true then  -- lamp aan tussen 6 uur en zonsopkomst
			    dz.devices('Kippenhok').switchOn().checkFirst()
            end
        
            if  dz.time.matchesRule("at sunrise") == true then                 -- lamp uit na zonsopkomst
                dz.devices('Kippenhok').switchOff().checkFirst()
		    end
        
            if dz.time.matchesRule("between sunset and 20:00") == true then    -- lamp aan tussen zonsondergang en 20 uur
			   dz.devices('Kippenhok').switchOn().checkFirst()
            end
    
            if dz.time.matchesRule("at 20:00") == true then                    -- lamp uit om 20 uur
				dz.devices('Kippenhok').switchOff().checkFirst()
		    end
    end
}
edit: I have changed the script, i tink this should be working :D

Code: Select all

return {
	on = {
		timer = { 
		       -- 'every minute',
		          'at 06:00',
		          'at 20:00',
		          'at sunrise',
		          'at sunset',
		        },
		   },
	
    logging = { level = domoticz.LOG_DEBUG, marker = 'Kippenhok' },
		
	execute = function(dz)
  
            local 	  checkTimeInMinutesSunrise    = 6 * 60 + 30                                          -- 6:30  
			local 	  checkTimeInMinutesSunset     = 19 * 60 + 30                                         -- 19:30 
            local     timeDifferenceSunsetSunrise  = dz.time.sunsetInMinutes - dz.time.sunriseInMinutes
            local     checkHours = 13 * 60                                                                -- is 13 uur          
            
            if    timeDifferenceSunsetSunrise < checkHours then                                           -- Als tijd tussen zonopkomst en zonsondergang > 13 uur dan geen licht
		     
				if  dz.time.matchesRule("at 06:00") then  						                      -- Lamp aan om 6 uur en zonsopkomst is niet om 6:30
					if dz.time.sunriseInMinutes > checkTimeInMinutesSunrise then
				       dz.devices('Kippenhok').switchOn().checkFirst()
                    end
					
                elseif dz.time.matchesRule("at sunrise") then                                     -- lamp uit na zonsopkomst
                       dz.devices('Kippenhok').switchOff().checkFirst()
		    
		        elseif dz.time.matchesRule("at sunset")  then                                      -- lamp aan tussen zonsondergang en 20 uur
			           if dz.time.sunsetInMinutes < checkTimeInMinutesSunset then
				          dz.devices('Kippenhok').switchOn().checkFirst()
                       end
                
				elseif dz.time.matchesRule("at 20:00")   then                                       -- lamp uit om 20 uur
				       dz.devices('Kippenhok').switchOff().checkFirst()
		        end
			end

    end
}