Date and time calculations in dzvents  [Solved]

Easy to use, 100% Lua-based event scripting framework.

Moderator: leecollings

Post Reply
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Date and time calculations in dzvents

Post 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.
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Date and time calculations in dzvents

Post 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
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: Date and time calculations in dzvents

Post by rrozema »

Very helpful @waaren. Thank you
dannybloe
Posts: 1355
Joined: Friday 29 August 2014 11:26
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Ermelo
Contact:

Re: Date and time calculations in dzvents

Post 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.
Creator dzVents - RPi3, loads of zwave devices, esp8266, evohome.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: Date and time calculations in dzvents

Post 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.
dannybloe
Posts: 1355
Joined: Friday 29 August 2014 11:26
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Ermelo
Contact:

Re: Date and time calculations in dzvents

Post 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.
Creator dzVents - RPi3, loads of zwave devices, esp8266, evohome.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: Date and time calculations in dzvents

Post 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.
dannybloe
Posts: 1355
Joined: Friday 29 August 2014 11:26
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Ermelo
Contact:

Re: Date and time calculations in dzvents

Post 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
Creator dzVents - RPi3, loads of zwave devices, esp8266, evohome.
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: Date and time calculations in dzvents

Post by rrozema »

:-) thanks. I'm just suggesting that further improvements may be possible.
dannybloe
Posts: 1355
Joined: Friday 29 August 2014 11:26
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Ermelo
Contact:

Re: Date and time calculations in dzvents

Post by dannybloe »

I know :-) Ideas and pull-request are always welcome.
Creator dzVents - RPi3, loads of zwave devices, esp8266, evohome.
User avatar
papoo
Posts: 126
Joined: Friday 22 January 2016 22:14
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10
Location: France
Contact:

Re: Date and time calculations in dzvents

Post by papoo »

in Time documentation i dont see timestamp support. is there a way to use with? (to use with some APi for example)
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Date and time calculations in dzvents

Post 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)
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
User avatar
papoo
Posts: 126
Joined: Friday 22 January 2016 22:14
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.10
Location: France
Contact:

Re: Date and time calculations in dzvents

Post by papoo »

thanks, work fine
Piacco
Posts: 69
Joined: Friday 14 November 2014 9:33
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Date and time calculations in dzvents

Post 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
User avatar
waaren
Posts: 6028
Joined: Tuesday 03 January 2017 14:18
Target OS: Linux
Domoticz version: Beta
Location: Netherlands
Contact:

Re: Date and time calculations in dzvents  [Solved]

Post 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
}
Debian buster, bullseye on RPI-4, Intel NUC.
dz Beta, Z-Wave, RFLink, RFXtrx433e, P1, Youless, Hue, Yeelight, Xiaomi, MQTT
==>> dzVents wiki
Piacco
Posts: 69
Joined: Friday 14 November 2014 9:33
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Date and time calculations in dzvents

Post by Piacco »

Thanks again Waaren :D
Now I can go on with my script
Piacco
Posts: 69
Joined: Friday 14 November 2014 9:33
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Date and time calculations in dzvents

Post 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
}
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest