This object is in archive! 

Need a way to store and compare dates/times

David Pritchard shared this idea 8 years ago
Under Consideration

A way is needed to store date variables and compare dates, for example to obtain time span differences.

Replies (17)

photo
1

How accurate do you need it to be? Maybe you can create an infinite loop (repeat puzzle) that waits 10 second each iteration, and increment a value by 10 for each loop.

photo
1

You mean a rule running constantly, just to measure elapsed time? Maybe it could work, but it seems a bit inefficient for comparing two dates.

Actually, I only need accuracy measured in hours, so I could put long wait times in the rule. It's a possibility.

photo
2

Yes, inefficient and not a very elegant, but it might work.


I miss a scripting language...

photo
2

Yes, I think it's a basic design error in the Zipabox not to allow users to go "under the hood" and play with the Javascript themselves. If you don't allow users to write scripts freely, then you have to design a complete high-level UI to meet all likely user requirements. Clearly, Zipato are not even close to that.

photo
1

Do you want to measure something?


If so, use two virtual switches. First you fire at the begin of action and the second at the end. Then you can read exactly the difference manually.

photo
1

How? There's no way to subtract one time value from another, nor is there a way to store a time value. I want to measure elapsed time.

photo
1

David,

I too have been trying to find a way to do this, but find myself hitting the "walls of limitation" in the Zipato universe: Variables cannot hold numbers large enough to calculate seconds if you'd want to minick UnixTime or even time since beginning of the year.

Any tips or tricks will be highly welcomed!

photo
1

I think the variables can store those values, because if you store a time value in a variable and then send the value to yourself in an email, you see a number corresponding to the milliseconds elapsed since midnight. Similarly, the date value is a Unix-style date-time value with the seconds since 1/1/1970 (if I remember correctly).


The difficulty is that you can't switch back from the variable to the time representation, or at least all my attempts have ended in failure. Time of (variable with time value) doesn't seem to yield anything useful. So all you can do is work with the numbers. In very simple cases, that's feasible - for example, you store the time value at 16:00 and then again at 19:00, and subtract and divide to get the elapsed time in hours or minutes. But if the comparison is between 23:00 and 01:00, it gets more complicated.


For times, it's doable if you create a subroutine to work it out and some variables dedicated to holding the values. For dates, it's nightmarishly complex. The worst thing is, it's already done - all we need is proper time variables.

photo
1

A related annoyance is that you can't work with sunrise or sunset as variables. Sometimes I'd like to know how many minutes it is until sunset, or since sunrise, and then do something, or something else, according to that. That doesn't really fit into the scheduler-driven scheme that Zipabox gives us.


My solution is built open a few other things that I do to supplement the Zipabox's capabilities. First, I take data from external sources using a Google Apps Script, and send the data to virtual meters in the Zipabox. So, for example, I get weather data from Wunderground and OpenWeatherMap and temperature and humidity readings from my Tado thermostat. The Apps Script runs every few minutes to update these values.


I noticed that OpenWeatherMap has sunrise and sunset times for Madrid (and they're even correct - OWM is not always accurate!) and decided to try sending them to the Zipabox. Because time variables don't work, I opted to send the hour and the minute as separate numbers (the Apps Script can easily extract them). Then I have my subroutine (which also sets the "daytime" variable) work out the minutes since sunrise/sunset and until sunrise/sunset, as applicable. The subroutine runs regularly so it's regularly refreshed.


Then, to update the numbers between updates from the script, I use my "master scheduler controller" rule, which runs every minute, to add or subtract from those variables.


The master scheduler rule is what I use to run a series of subroutines that need to run every 10, 15 or 30 minutes. I find it more reliable than a whole load of rules with schedulers, which always give me trouble.


If you want an example of the Google Apps Script I can also post one.

photo
1

David,

Thats' really cool! -And it's great that you share your rules so others can learn.

Yes, please also share your Google Apps Script.

(Btw: What is your approach to handling complete rule standstill if the internet link is down so Zipabox can't get the sunset/sunrise data?)

Brgds, Robert

photo
1

Here's my weather data script from Google Apps. I've carefully blanked out all the serial numbers and API keys - please alert me if I missed anything!

This obtains weather information from Wunderground and OpenWeatherMap (both of which you'd need to sign up for to get an API key), and sends the data to virtual meters in the Zipabox. It runs every 15 minutes or so. I find Wunderground to be more accurate and reliable than either OWM or the Zipabox weather information, but you can't always guarantee that you'll get up-to-date information from any given provider, so I send the day, hour and minute of each update to the Zipabox too, and then using a set of rules run every few minutes, decide which bit of information is most up-to-date and reliable. All this goes into a single, definitive virtual weather meter which I use in my other rules.

OWM is the only source I have for sunrise/sunset so that's what I use for now.

You can also extend this idea to get pollution data, for example - if you can find any! I'm still looking.

function GetWeatherData()

{

var lock = LockService.getPublicLock();

lock.waitLock(30000); // wait 30 seconds before conceding defeat.

// Prepare standard HTTP POST stuff

var options =

{

"contentType" : "text/plain",

"method" : "post"

};

// Basic time info

var nMinuteInMilliseconds = 60*1000;

var nHourInMilliseconds = 60*60*1000;

var nDayInMilliseconds = 60*60*24*1000;

// Get current date/time

var dateNow = new Date();

var nYear = dateNow.getFullYear();

var nMonth = dateNow.getMonth() + 1;

var nDay = dateNow.getDate();

var nHour = dateNow.getHours();

var nMinute = dateNow.getMinutes();

// Call openweathermap API

var urlowm = 'http://api.openweathermap.org/data/2.5/weather?id=xxxxxxx&appid=xxxxxxx&units=metric'

var responseOWM = UrlFetchApp.fetch(urlowm);

var nReponseCodeOWM = responseOWM.getResponseCode();

if (nReponseCodeOWM == 200)

{

var contentTextOWM = responseOWM.getContentText();

var conditionsOWM = Utilities.jsonParse(contentTextOWM);

var nCloudCoverOWM = conditionsOWM.clouds.all;

var nTemperatureOWM = conditionsOWM.main.temp;

var nMinTemperatureOWM = conditionsOWM.main.temp_min;

var nMaxTemperatureOWM = conditionsOWM.main.temp_max;

var nWindSpeedOWM = conditionsOWM.wind.speed;

var nSunriseDateTime = conditionsOWM.sys.sunrise;

var nSunsetDateTime = conditionsOWM.sys.sunset;

// Get hour/minute of sunset

var dateOWMSunset = new Date(conditionsOWM.sys.sunset*1000);

var nHourSunset = dateOWMSunset.getHours();

var nMinuteSunset = dateOWMSunset.getMinutes();

// Get hour/minute of sunrise

var dateOWMSunrise = new Date(conditionsOWM.sys.sunrise*1000);

var nHourSunrise = dateOWMSunrise.getHours();

var nMinuteSunrise = dateOWMSunrise.getMinutes();

// Get date-time of observation

var dateOWM = new Date(conditionsOWM.dt*1000);

// Compare to current date

var nHoursDifference = Math.floor(((dateNow - dateOWM) % nDayInMilliseconds) / nHourInMilliseconds);

var nMinutesDifference = Math.floor(((dateNow - dateOWM) % nDayInMilliseconds) / nMinuteInMilliseconds);

// Hours part from the timestamp

//var hoursOWM = dateOWM.getHours();

// Minutes part from the timestamp

//var minutesOWM = "0" + dateOWM.getMinutes();

// Seconds part from the timestamp

//var secondsOWM = "0" + dateOWM.getSeconds();

// Send OWM cloud cover to Zipabox virtual meter

var resultZipaboxOWMClouds = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value1="; + nCloudCoverOWM, options);

var nReponseCodeOWMClouds = resultZipaboxOWMClouds.getResponseCode();

// Send OWM temperature to Zipabox virtual meter

var resultZipaboxOWMTemp = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value9="; + nTemperatureOWM, options);

var nReponseCodeOWMTemp = resultZipaboxOWMTemp.getResponseCode();

// Send OWM min temperature to Zipabox virtual meter

var resultZipaboxOWMTempMin = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value6="; + nMinTemperatureOWM, options);

var nReponseCodeOWMTempMin = resultZipaboxOWMTempMin.getResponseCode();

// Send OWM max temperature to Zipabox virtual meter

var resultZipaboxOWMTempMax = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value7="; + nMaxTemperatureOWM, options);

var nReponseCodeOWMTempMax = resultZipaboxOWMTempMax.getResponseCode();

// Send OWM wind speed to Zipabox virtual meter

var resultZipaboxOWMWindSpeed = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value5="; + nWindSpeedOWM, options);

var nReponseCodeOWMWindSpeed = resultZipaboxOWMWindSpeed.getResponseCode();

// Send OWM sunrise hour to Zipabox virtual meter

var resultZipaboxOWMSunriseHour = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value4="; + nHourSunrise, options);

var nReponseCodeOWMSunriseHour = resultZipaboxOWMSunriseHour.getResponseCode();

// Send OWM sunrise minute to Zipabox virtual meter

var resultZipaboxOWMSunriseMin = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value3="; + nMinuteSunrise, options);

var nReponseCodeOWMSunriseMin = resultZipaboxOWMSunriseMin.getResponseCode();

// Send OWM sunset hour to Zipabox virtual meter

var resultZipaboxOWMSunsetHour = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value2="; + nHourSunset, options);

var nReponseCodeOWMSunsetHour = resultZipaboxOWMSunsetHour.getResponseCode();

// Send OWM sunset minute to Zipabox virtual meter

var resultZipaboxOWMSunsetMin = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value16="; + nMinuteSunset, options);

var nReponseCodeOWMSunsetMin = resultZipaboxOWMSunsetMin.getResponseCode();

// Send age of observation in hours to virtual meter

var resultZipaboxOWMAge = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwwwwwww&value8="; + nHoursDifference, options);

var nReponseCodeOWMAge = resultZipaboxOWMAge.getResponseCode();

if (nReponseCodeOWMClouds == 200 && nReponseCodeOWMTemp == 200 && nReponseCodeOWMAge == 200 && nReponseCodeOWMTempMin == 200 && nReponseCodeOWMTempMax == 200 && nReponseCodeOWMWindSpeed == 200 && nReponseCodeOWMSunriseHour == 200 && nReponseCodeOWMSunriseMin == 200 && nReponseCodeOWMSunsetHour == 200 && nReponseCodeOWMSunsetMin == 200)

{

// Send OpenWeather update month, day and hour to Zipabox

var resultZipaboxMonth = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwww&value4="; + parseInt(nMonth), options);

var resultZipaboxDay = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwww&value2="; + parseInt(nDay), options);

var resultZipaboxHour = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwww&value3="; + parseInt(nHour), options);

}

}

// Call Zipato weather API

// Need to login first

//var url = 'https://my.zipato.com:443/zipato-web/v2/meteo/weather?location=LEVS';

//var responseZipato = UrlFetchApp.fetch(url);

//var nReponseCodeZipato = responseZipato.getResponseCode();

//if (nReponseCodeZipato == 200)

//{

// var contentText = responseZipato.getContentText();

// Logger.log(contentText);

// var recipient = Session.getActiveUser().getEmail();

// var subject = 'Zipato weather output';

// var body = Logger.getLog();

// MailApp.sendEmail(recipient, subject, body);

// var conditionsZipato = JSON.parse(contentText);

// var todaysConditionsZipato = conditionsZipato;

// }

// Call Wunderground API

var url = 'http://api.wunderground.com/api/xxxxxxxxxxx/conditions/forecast/alert/q/<latitudehere>,<longitudehere>.json';

var responseWunderground = UrlFetchApp.fetch(url);

var nReponseCodeWunderground = responseWunderground.getResponseCode();

if (nReponseCodeWunderground == 200)

{

var contentText = responseWunderground.getContentText();

var conditions = Utilities.jsonParse(contentText);

var todaysConditions = conditions;

var sIcon = todaysConditions.current_observation.icon;

var nIcon = 0;

switch (sIcon)

{

case 'clear': nIcon = 1; break;

case 'mostlysunny': nIcon = 2; break;

case 'icy': nIcon = 3; break;

case 'smoke': nIcon = 4; break;

case 'dusty': nIcon = 5; break;

case 'hazy': nIcon = 6; break;

case 'partlycloudy': nIcon = 7; break;

case 'mostlycloudy': nIcon = 8; break;

case 'chancerain': nIcon = 9; break;

case 'showers': nIcon = 10; break;

case 'mist': nIcon = 11; break;

case 'rain': nIcon = 12; break;

case 'chancesnow': nIcon = 13; break;

case 'snow': nIcon = 14; break;

case 'cloudy': nIcon = 15; break;

case 'rain_snow': nIcon = 16; break;

case 'fog': nIcon = 17; break;

case 'foggy': nIcon = 18; break;

case 'chancestorm': nIcon = 19; break;

case 'storm': nIcon = 20; break;

case 'thunderstorm': nIcon = 21; break;

}

// Get current rain in mm now

var nRainMMNow = parseFloat(todaysConditions.current_observation.precip_today_metric);

// Get rain in mm and probability of precipitation forecast for today

var nRainMMForecast = todaysConditions.forecast.simpleforecast.forecastday[0].qpf_day.mm;

var nPoPForecast = todaysConditions.forecast.simpleforecast.forecastday[0].pop;

if (nRainMMForecast == null)

{

nRainMMForecast = 0;

}

// Get current temperature (C)

var nTemperatureC = todaysConditions.current_observation.temp_c;

// Get min temperature (C)

var nMinTemperatureC = todaysConditions.forecast.simpleforecast.forecastday[0].low.celsius;

// Get max temperature (C)

var nMaxTemperatureC = todaysConditions.forecast.simpleforecast.forecastday[0].high.celsius;

// Get wind speed

var nWindSpeed = todaysConditions.current_observation.wind_kph;

// Get observation date/time

var dateWundergroundObservation = new Date(todaysConditions.current_observation.observation_epoch*1000);

// Compare to current date

var nHoursDifferenceW = Math.floor(((dateNow - dateWundergroundObservation) % nDayInMilliseconds) / nHourInMilliseconds);

var nMinutesDifferenceW = Math.floor(((dateNow - dateWundergroundObservation) % nDayInMilliseconds) / nMinuteInMilliseconds);

// Send icon to Zipabox virtual meter

var resultZipaboxIcon = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value1="; + parseInt(nIcon), options);

//var sReponseText = resultZipabox.getContentText();

var nReponseCode = resultZipaboxIcon.getResponseCode();

// Send rain data to virtual meter

var resultRainToday = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value9="; + nRainMMForecast, options);

var resultRainNow = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value7="; + nRainMMNow, options);

var resultPoP = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value8="; + nPoPForecast, options);

// Send temperature to virtual meter

var resultTemp = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value6="; + parseInt(nTemperatureC), options);

// Send min temperature to virtual meter

var resultTempMin = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value3="; + parseInt(nMinTemperatureC), options);

// Send max temperature to virtual meter

var resultTempMax = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value4="; + parseInt(nMaxTemperatureC), options);

// Send wind speed to virtual meter

var resultWindSpeed = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value2="; + parseInt(nWindSpeed), options);

// Send age of observation in hours to virtual meter

var resultAge = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=yyyyyyyyyyyyyyyyyyyyy&ep=zzzzzzzzzzzzzzzzzz&value5="; + parseInt(nHoursDifferenceW), options);

if (nReponseCode == 200 && resultRainToday.getResponseCode() == 200 && resultRainNow.getResponseCode() == 200 && resultPoP.getResponseCode() == 200 && resultTemp.getResponseCode() == 200 && resultAge.getResponseCode() == 200 && resultTempMin.getResponseCode() == 200 && resultTempMax.getResponseCode() == 200 && resultWindSpeed.getResponseCode() == 200)

{

// Send Wunderground update month, day and hour to Zipabox

var resultZipaboxMonth = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwww&value7="; + parseInt(nMonth), options);

var resultZipaboxDay = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwww&value5="; + parseInt(nDay), options);

var resultZipaboxHour = UrlFetchApp.fetch("https://my.zipato.com/zipato-web/remoting/attribute/set?serial=yyyyyyyyyyyy&apiKey=zzzzzzzzzzzzzzzzzzzzz&ep=wwwwwwwwwwwwwwwww&value6="; + parseInt(nHour), options);

var nReponseCodeMonth = resultZipaboxMonth.getResponseCode();

var nReponseCodeDay = resultZipaboxDay.getResponseCode();

var nReponseCodeHour = resultZipaboxHour.getResponseCode();

}

}

lock.releaseLock();

}

photo
1

There's also a failed attempt to access the Zipato weather API there. The reason for that is that (at least in my case), much of the weather data you can see by accessing the API directly is unavailable or blank in the Zipabox itself. For example, the sunrise, sunset, temp max and temp min values are always 0 or blank.

photo
1

Great work David! I will check out the script and maybe try to port it to the Norwegian open weather api at http://www.yr.no. If it's ok with you.


Marius

photo
1

Sure, go ahead. If that API is good and has data for Spain, I might be interested!

photo
1

Yes, I think it covers Europe, but I am not sure how accurate the forecasts are, outside of Scandinavia

photo
1

David, Thanks for posting your code.

The Norwegian Meorological Service available at http://yr.no has worldwide coverage, although the granulatity is best for Norway and Northern Europe, as per their FAQ here: http://api.met.no/faq.html

They supply weather data for free, also for app developers.


Here's the weather forecast for Madrid, Spain:

https://www.yr.no/place/Spain/Madrid/Madrid/?spr=eng

Brgds Robert

photo
1

Correction of my rule. There was a bug that meant MinutesUntilSunrise wasn't calculated properly.

Leave a Comment
 
Attach a file