Tinderbox User-to-User Forum (for formal tech support please email: info@eastgate.com)
Tinderbox Users >> Agent, Actions, Rules & Automation >> Daily Automated Updates

Message started by Ian Gibbons on May 2nd, 2016, 4:28pm

Title: Daily Automated Updates
Post by Ian Gibbons on May 2nd, 2016, 4:28pm


I am trying to automatically update 'To Do' notes - notes containing various daily tasks - on a daily basis using agents. I'm using prototypes to help distinguish visually between 'complete' and 'still to do' notes. Ideally, at the end of the day I would like to have the 'complete' notes to revert to a the 'still to do' prototype.

Is there a simple way to do this?
Specifically, I am wondering how tinderbox handles situations when the computer is shut down during a scheduled update time, and if I should set up a 'toggle' attribute and script which checks to see if the prototype has been updated in the last cycle, or perhaps there is a more elegant way to handle this.  

Sorry if my question is too vague, I'm pretty new to this and would really appreciate any suggestions.


Title: Re: Daily Automated Updates
Post by Mark Anderson on May 3rd, 2016, 4:48am

If I understand correctly, you need to do two things when completing. set the completions state and record the date-time. For simplicity, I'll assume a Boolean $IsCompleted is the primary completion marker* and the date/time of completion is in Date-type $CompletionDate.

* you can of course set prototypes, etc., based on the completion state but at this point such aspects just overcomplicate the core task of re-setting completion flags.

Use a stamp or some other action to set (in this order):

$CompletionDate = date("now"); $IsComplete=true;

We want to (re-)set completion date first so an agent or rule can check and reset completed tasks from previous days. Here's an agent example:

Query:  $IsComplete & ($CompletionDate < date("today+00:00"))
Action:   $IsComplete=false;

The date() query argument bears explanation. The 'today' date designator is the current system date-time [sic] at the moment of code execution.  But we want the beginning of the current day. The "today + 00:00" is parsed by date to set the current date-time (i.e. now) and set its time element to zero hours:minutes (Tinderbox doesn't really use seconds). In the same way date("today + 12:00") would return midday on the current day.

Thus the agent looks for completed tasks that are complete but on a day before today and sets them as not complete.

A point to bear in mind is your reset logic runs off a date and most simple UI controls like a tick-box aren't dates. For instance, ticking a box doesn't fire an event, but next agent/rule cycle the note's tick-box state can be tested. But, if you don't know when the box was ticked, the action code has nothing to work the reset logic.

So at this point it is worth asking, how do you intend to mark items complete. If you're happy to us a stamp, then the above method could work (I tested a minimal example in v6.5.0). If you were aiming to use $Checked in an outline or any Boolean in a key attribute, I think you'd need a different logic.

Title: Re: Daily Automated Updates
Post by Ian Gibbons on May 3rd, 2016, 11:34am

Great answer -- thanks so much!

I think stamps will be a good way to do this.
I'm also curious about two things --
first, how strenuous are the agent query comparisons you have suggested in terms of cpu usage?

and also, why is the order important to stamp actions?

Title: Re: Daily Automated Updates
Post by Mark Anderson on May 3rd, 2016, 12:16pm

The answer, for someone making light use of actions and queries is that there isn't a heavy load and often cycle time is almost instant.  It is the case that some actions/query terms are more taxing than others. A complex regex pattern using $Text.contains() on every note will need more effort than just testing a Boolean.

Another short answer is don't worry about cycle times unless/until you see a slow down at which point - thanks to TB's support for incremental formalisation - it is normally pretty simple to add hitherto unneeded efficiency tweaks to code. IOW - don't worry about these things unless you find the need to do so.

The is no 'must' to using a stamp. I was simply guessing that you might have been intending to use key attribute tick-boxes to mark completed state. The nature of your desired logic is you need to set  the completion date at the same time as a marker like a boolean. You want all completions to expire at the end of the current day and for a global completion state reset to occur on first use of Tinderbox on a new day. Thus Tinderbox needs to know when you ticked a completion box. You might assume a rule in the ticked note could check the tick-box state and set a completion time. But, as rules and agents run alongside one another, an agent - or another rule - might reset the tick-box before your desired rule updates the completion time.  The point of a stamp is to ensure both actions (the 'visible' completion marker, and the date/time of the event) are captured together, with the date/time occurring first to pre-empt unintentional resets.

There are multiple ways to resolve this - I picked one to get you going. The easy part is applying the desired logic in an optimal setting. The hard part is ensuring the logic is firm against human unpredictability.

If you're coming at this from a coding perspective - Tinderbox doesn't have events (on open, on click, or the like). Because you want to reset your completion state (however implemented in visible/UI terms) you need a way to track whether the completion occurred today or sometime in the past as those two possibilities have different outcomes.

Title: Re: Daily Automated Updates
Post by Ian Gibbons on May 5th, 2016, 6:31am

Amazing - thank you again. Now you have me intrigued about finding a logic for checkboxes!

I created an agent to do the updates on each task note, with the query below:

$Prototype=="iterative task";

the agent action as follows:

if(date("today")>=$NextUpdate){$Checked=false; $NextUpdate="tomorrow + 00:00"}

$NextUpdate is a user date attribute I created for this operation.
This if statement doesn't seem to be working for me, as the notes become unchecked after a 10 - 15 second wait. Do you spot any problems with the syntax?

Title: Re: Daily Automated Updates
Post by Mark Bernstein on May 5th, 2016, 10:08am

Itís better to use the date() operator to construct dates:

     $NextUpdate=date("tomorrow 00:00")

Title: Re: Daily Automated Updates
Post by Mark Anderson on May 5th, 2016, 10:20am

Ah, you've been caught out by the default 'never' value for un-initialised Date attributes. The 'never' value is both before than the oldest date and later than the latest date. See more on date evaluation.

The un-ticking problem you cite arises if a task is a new note, in which case $NextUpdate will not be set and will have a value of 'never'. 'today' is greater than 'never' (though not equal to it).

Also, you're not testing if $NextUpdate is yesterday (i.e. before the current day) but whether it is before the system current date time. †'today' is a date time and actually evaluates to the same value as 'now'. The '=' †of the >+ is not needed either. 00:00 is the easiest time today and must be greater than any date/time before today, the latter being the date/times we want to match.

I also think it reads more easily - for later fault-finding - †to ask "is $NextUpdate less then (i.e. earlier than) the beginning of today?" rather than the reverse as in the current code.

If we try:
if($NextUpdate & $NextUpdate < date("today + 00:00")){$Checked=false; $NextUpdate=date("tomorrow + 00:00")}

We ask "If $NextUpdate has a non-default value is it also before the start of the current day?" Note I've also added, as best practice a date() wrapper to the date/time assignment in the {} code part of the action. The code works without this, but the intent is clearer (especially when read in two years time whilst trying to change the code).

Now a note is tested for an explicit $NextUpdate, and the un-tick issue goes away. But we get a new issue - new notes never get reset! As intimated previously, you need to initialise $NextUpdate on first use.

If all tasks live in one (or several containers), the container $OnAdd could be used to initialise the attribute for new tasks with the current time:

$NextUpdate = date("now");

Alternatively, we could use the agent action to do this instead of the above, by combining the two action - though note the ordering, which is important and the semi-coon between discrete if() statements.

if($NextUpdate=="never"){$NextUpdate = date("now")};
if($NextUpdate & $NextUpdate < date("today + 00:00")){$Checked=false; $NextUpdate=date("tomorrow + 00:00")}

Note that first the agent checks if $NextUpdate is initialised. †If it isn't, it sets the attribute to the current date/time. The check state doesn't matter. If the task is incomplete, when ticked later today it will still have a date time in the current day. Then, the process carries on with the previous code.

Now we've put the two bits together we can combine the two resulting in fewer if() tests overall. Here's the final cut:

if($NextUpdate) {
† if($NextUpdate < date("today + 00:00")) {
     $Checked=false; $NextUpdate=date("tomorrow + 00:00");
† };
} else {
† $NextUpdate = date("now")

The indenting is just for clarity and isn't needed in the action code box if typing this in.

(tested in v6.5.0)

~~~~ edit

I should perhaps note that if($NextUpdate) is just a shorthand way of writing if($NextUpdate==true)

Title: Re: Daily Automated Updates
Post by Ian Gibbons on May 6th, 2016, 12:30pm

Thank you! This is a big improvement. I also appreciate your attention to the code's legibility.

Just a question scanning the suggested solution:
if($NextUpdate) {
 if($NextUpdate < date("today + 00:00")) {
    $Checked=false; $NextUpdate=date("tomorrow + 00:00");
} else {
 $NextUpdate = date("now")

...does this not update only once every two days? $NextUpdate is set to "tomorrow + 00:00" but it seems that the if condition -- if($Next Update < date ("today + 00:00")) -- will not be satisfied until the day after tomorrow.

Title: Re: Daily Automated Updates
Post by Mark Anderson on May 6th, 2016, 3:37pm

I don't think so. †Frankly, I find these today/tomorrow/etc test always need real-world validation as just changing dates in a doc sometimes misses an edge case.

"today+00:00" is 00:00:00 of today. Anything '<' (less) will be yesterday. †If you're worrying about the semantics of 00:00, by all means use 00:01. That won't bite unless you expect task to reset before a minute past midnight.

Let's assume today is 6/5/16 (6 May 2016). "today + 00:00" is 06/05/2016 00:00. "tomorrow + 00:00" would be 0/7/05/2016 00:00. As I say, if worried about midnight semantics use 00:01.

Anyway, I think the logic is correct. Still, a day is not so long - make a test file and check it tomorrow and see if task reset as expected.

Do ask if still stuck. †:)

edit: typos

Title: Re: Daily Automated Updates
Post by Ian Gibbons on May 10th, 2016, 11:20am

Still stuck -- I decided to change my original idea. Now I am trying to check dates as a container rule that evaluates whether any of its children notes were created "today".

I've tried many approaches, but one of the nicer solutions seems like something along the lines of the following rule:

if(any(children, $Created == date("today"))){
// change appearance -- updated
} else {
// change appearance -- pending update

This assumes two behaviours, both which I unfortunately haven't been able to make work in expected ways:
First, that date("today") returns a date data-type to be compared against $Created.
Second, that "==" only compares the year month and day [not the hours and minutes].

I recently ran some tests on empty notes for date("today + 00:00").

Given this rule:
$TodaysDate = date("today + 00:00");
...if I set $TodaysDate to be a date data-type -- yields "2016-05-28, 9:52 PM" !?

...yet if $TodaysDate is set as a string -- yields "2016-05-09, 12:00 AM" , the correct date. EDIT: I started writing this post yesterday -- but got sidetracked!

I have been reading the acrobatfaq (I think you wrote this?? ), and it said that the date(string) operator is used to coerce a date from a string, yet why would it read out in the way I intended only when coerced back to a string?

Also, if I am missing something in my if(any()) logic above -- please enlighten me! Thanks again.

Title: Re: Daily Automated Updates
Post by Mark Anderson on May 10th, 2016, 12:30pm

Given this rule:
$TodaysDate = date("today + 00:00");
...if I set $TodaysDate to be a date data-type -- yields "2016-05-28, 9:52 PM" !?

I can't replicate this. where are you 'seeing' this value?

To test avoiding extraneous code, I created a new (v6.5.0) TBX file and added a note, setting $StartDate and $MyString as key attributes. I added a stamp with code:

$StartDate = date("today + 00:00");

I then stamped the note (at 17:18 on 10 May 2016) and I get:

$StartDate KA value: '10/05/2016, 00:00'
$MyString KA value: '10/05/2016, 00:00'

If I had used date("today") I'd expect the time element to be 17:18.

Aside: I used a stamp as I want to run the action just once - again to rule out any issues to do with other code, iterating, etc.

I'd suggest you stop testing in your work doc and resolve this issue in a minimal new test doc so you can be sure other code isn't interfering. It's a seeming chore, but often it is starting over in a test file that something seemingly breaking in an actual work file now works. This makes it easier to start looking for what might be the affecting your original test.

Let's resolve this before moving on the the any() issue as it seems one depends on the other.

aTbRef: yes, that's me writing it based on black-box (i.e. user) testing of the app: I've no under-the-hood access.

Title: Re: Daily Automated Updates
Post by Ian Gibbons on May 10th, 2016, 4:06pm

In my work file I've been 'seeing it' in the key attribute pane, just above the text field on the map.

I did as you suggested in a new file, using a stamp and mein gott, it's still happening to me.
$StartDate = date ("today + 00:00"); ( -> 2016-06-01, 4:03 PM)
$MyString = $StartDate;                   †( -> 2016-06-23, 4:03 PM)
$MyString2 = date ("today + 00:00") ( -> 2016-05-10, 12:00 AM)

The plot thickens -- interestingly still the direct definition of a string via date() seems to actually work.

Is there something in my TB (6.5) or Mac settings that might be causing this?

Title: Re: Daily Automated Updates
Post by Mark Anderson on May 10th, 2016, 4:19pm

What OS locale are you using? Are you using cusome date settings? I ask as AM/PM times would suggest a US locale but the yyy-mm-dd date order doesn't sound familiar.

Title: Re: Daily Automated Updates
Post by Ian Gibbons on May 10th, 2016, 10:43pm

It's using a Canadian date, I switched to American and the test cleared (as in all three dates showing up at the proper time and date: today at 12:00 AM). Very interesting.

Title: Re: Daily Automated Updates
Post by Mark Anderson on May 11th, 2016, 4:02am

I'm aware 'just' handling dates correctly can, unseen, get more complex under the hood due to locales, time zones, user settings, etc. See this example, for instance.

I'd suggest dropping an email to formal support (info@eastgate.com) with a bit of the detail here as to your OS locale settings and the problem encountered. I suspect your configuration has hit a new edge case for date handling.

Tinderbox User-to-User Forum (for formal tech support please email: info@eastgate.com) » Powered by YaBB 2.2.1!
YaBB © 2000-2008. All Rights Reserved.