Welcome, Guest. Please Login
Tinderbox
  News:
IMPORTANT MESSAGE! This forum has now been replaced by a new forum at http://forum.eastgate.com and no further posting or member registration is allowed. The forum is still accessible via read-only access for reference purposes. If you wish to discuss content here, please use the new forum. N.B. - posting in the new forum requires a fresh registration in the new forum (sorry - member data can't be ported).
  HomeHelpSearchLogin  
 
Pages: 1
Send Topic Print
Setting $StartDate from $Name (Read 9104 times)
David Bertenshaw
Full Member
*
Offline



Posts: 182

Setting $StartDate from $Name
Oct 19th, 2012, 5:34am
 
Edited:
by admin: Split out as a separate topic from "So, umm..., what is this app actually for?"


Right, caveat lector first of all: I've tried to answer this as an exercise to learn something myself. It works for me, but I've not done much testing and no doubt somebody more skilled will know better ways...

But, assuming you are rigid in your naming convention:

YYYY/MM/DD This is the note title

Then, if you put the following code into the Rule box of your note

$StartDate=format($Name.substr(8,2) + "/" + $Name.substr(5,2) + "/" +$Name.substr(0,4))

then it will populate the $StartDate attribute with the correct date. Note, I'm in the UK, so this will be DD/MM/YYYY. If you're in the US, then you'd obviously swap round the first two $Name.substr terms. (BTW, substr counting starts at 0, not 1.)

So, e.g. "2012/10/26 Desperately tried to work out what to do", $StartDate will become 26/10/2012 10:22. There are ways of stripping out the HH:MM if you want.

Of course you could put the expression into your Prototype.

Or you might want to use this as a one-off agent to populate existing notes, (and afterwards use the same substr function to strip out the date from the existing titles.)  Then for new ones enter the $StartDate in directly and use $DisplayExpression = $StartDate + " " + $Name to display the full Date + Title.

Now, one of the Marks will be along in 5 minutes to give you a much simpler and more logical way of doing this.... Wink
Back to top
 
« Last Edit: Oct 19th, 2012, 7:03am by David Bertenshaw »  
  IP Logged
Martin Boycott-Brown
Full Member
*
Offline



Posts: 27
Cambridge, UK
Re: So, umm..., what is this app actually for?
Reply #1 - Oct 19th, 2012, 6:13am
 
Amazing! Many thanks for that. I'll try it out with some dummy data.

I'm in the UK, too, so I use the same date format.

I think one of the Marks is in the US, so I suspect it will take him a few hours to wake up Wink.

Thanks again,
Martin.
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: So, umm..., what is this app actually for?
Reply #2 - Oct 19th, 2012, 6:48am
 
Yes, your code does works though TB's actually being forces to do some guesswork and figuring out you want a date from a string as we're passing a string to a data attribute ($StartDate). Stepping back, I see you want to make date-type data from a literal string(i.e. the text representation of a date).

Sidenote: I'd concur your point re day & month order in dates. If I recall, everywhere bar the US & Philippines uses DMY order; the latter do MDY order (Canada does doth). Ah, and China uses neither but YMD instead. Plus the delimiter varies by country: dot, slash, hyphen, space, etc. Anyway, being British myself, I'll stick with day-month order for this example.

At source we have a $Name of "2012/10/26 Desperately tried to work out what to do" and we want to make a valid TB date from that. Your approach of using String.substr() to get parts of $Name is on track. But what then? The obvious candidate is date() which has two alternate input forms. These are date(year,month,day,[hour,min]) and date.(string). We can use either:

date(year,…): $StartDate = date(($Name.substr(0,4)),($Name.substr(5,2)),($Name.substr(8,2)))
date(string): $StartDate = date($Name.substr(8,2) + "/" + $Name.substr(5,2) + "/" +$Name.substr(0,4))

Note, the extra parentheses in the first example around each $Name call are because that form takes number inputs not strings. The extra () around $Name.substr(0,4) means that when TB is given string "2012" when it expects a number, it automatically co-erces it to number 2012. A clearer but more verbose way to do the same thing is to use $Name.substr(0,4).toNumber which won't need the extra parentheses. For example:

$StartDate = date($Name.substr(0,4).toNumber,$Name.substr(5,2).toNumber,$Name.substr(8,2).toN
umber)


^^ unavoidable line wrap - code has no line break.

So, I'd go with the second option here - date(string). It's simpler, though do remember alter day/month order and delimiter type as pertinent to your locale.

Agents? Yes, for instance find all notes of a given prototype (assumption: we're certain all these start their title with a date) you could do this.  So to set $StartDate all "pBattle" prototyped notes:

Query: $Prototype=="pBattle"
Action: $StartDate = date($Name.substr(8,2) + "/" + $Name.substr(5,2) + "/" +$Name.substr(0,4))

Why "pBattle" as the prototype name?  Not required, but I've found it useful to use prefixes for my prototype (and template, etc.) names that I'll never use as a normal note name to avoid accidental name confusion. I might just want a note called "Battle".

Sorry for the long post, but rather than give just the answer I hope having the worked method helps bootstrap your learning, even if it does mean a bit more reading.
Back to top
 
« Last Edit: Oct 19th, 2012, 6:56am by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Martin Boycott-Brown
Full Member
*
Offline



Posts: 27
Cambridge, UK
Re: Setting $StartDate from $Name
Reply #3 - Oct 19th, 2012, 7:00am
 
Thank you -- that's very much appreciated -- and very clear. I hope others find it as useful as I do. I would guess that it is an operation that others might want to perform -- perhaps even to format dates in alternative ways for display purposes. And it never hurts to know more than one way to do things. And I realise it's also a useful demonstration of the basic technique of extracting data from one place and re-using it in another. Very valuable.

Best, Martin.
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Setting $StartDate from $Name
Reply #4 - Oct 19th, 2012, 10:01am
 
Here's a more advanced version of the above technique for an agent, using regular expressions. First, let's state some assumptions:
  • Date in $Name is in format YYYY/MM/DD.
  • $Name starts with date (i.e. first character is first Y digit).
  • day and month always have 2 digits, i.e. '04' for April and not '4'.
Agent code:

Query:  $Name.contains("^(\d{4})/(\d{2})/(\d{2})")
Action:  $MyDate = date($3+"/"+$2+"/"+$1")

Of course, the query could have other terms to restrict the scope of search. as written here it searches all notes. A break-down of the regular expression:
- From the start of the string ^
- a string of four digits & return as backreference $1
- a single forward slash
- a string of two digits & return as backreference $2
- a single forward slash
- a string of two digits & return as backreference $3
- any character matched any number of times (i.e. the rest of the title)

The () within the regular expression is what defines the back-reference. To match those parenthesis characters literally use \( and \) instead. By searching for NNNN/NN/NN at the beginning of the $Name we don't have to worry about whatever else is in the title - even another YYYY/MM/DD sequence.

The action then uses the contents of $1, $2 and $3 in string it creates. We insert the delimiters as literal string, quoted. The back-references, like references to string attribute values don't need quoting; think of $! as if it were $SomeString.

The date() used string is for general world Day-Month order, alter for US-style MD order:
  $MyDate = date ($2+"/"+$3+"/"+$1)
…or for a a system using YMD:
  $MyDate = date($1+"/"+$2+"/"+$3)

This isn't beginner stuff. But it's worth bearing in mind for one good reason. See how this technique never touched any note's $Rule leaving it free to do other stuff? Neat. Anyway, try it out. Once you see how it can work it may help give confidence to try the technique for yourself.  You don't have to use back references. This would find the same notes without creating the references:

 $Name.contains("^\d{4}/\d{2}/\d{2}")

Indeed, if you didn't always zero-pad days and months:

 $Name.contains("^\d{4}/\d{1,2}/\d{1,2}")

…but in the latter case you'd need in the action to check $@ and $3 were double-character before using for a date.

More on: back-references, regular expressions.
Back to top
 
« Last Edit: Oct 19th, 2012, 10:13am by Mark Anderson »  

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
David Bertenshaw
Full Member
*
Offline



Posts: 182

Re: Setting $StartDate from $Name
Reply #5 - Oct 19th, 2012, 11:25am
 
Thanks Mark,

As I said, I only tried to answer Martin's query as a learning exercise. I was chuffed enough that I got format() to work....

I tried to use date() but encountered all sorts of issues -- and your post explains that I should have used additional brackets, so that's useful.

I actually already use agents to set $StartDate automatically in my Journal -- each day's $Name is in the form "DD/MM/YYYY" anyway, so the new bit for me here was learning how to rearrange a reverse date for Martin's case.

In fact, I also use the prototype rule to set the $StartDate and $EndDate to HH:MM = 00:00 / 23:59, so that each note fills a day display nicely in timelines.

$StartDate = time($Name,00,00);$EndDate = time($Name,23,59)

or, for Martin's case, adapting your second option:

$StartDate = time($Name.substr(8,2) + "/" + $Name.substr(5,2) + "/" +$Name.substr(0,4),00,00)

The regex stuff looks interesting, but will take some time to assimilate...

Thanks again - fascinating stuff...

David
Back to top
 
 
  IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Setting $StartDate from $Name
Reply #6 - Oct 19th, 2012, 12:07pm
 
Glad you reminded me of time. If making lots of events - especially in the past - time is irrelevant. As you've shown, just add the info. For a 00:01 time you might use ,00,01 as the last two input or append the string or " 00:01" depending on which date type you use.

Hmm, what if you have titles starting DD/MM/YYYY and wanted then to start YYYY/MM/DD for easier sorting on $Name? Answer in a new thread.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Martin Boycott-Brown
Full Member
*
Offline



Posts: 27
Cambridge, UK
Re: Setting $StartDate from $Name
Reply #7 - Oct 20th, 2012, 3:06am
 
Many thanks for all of this -- amazing what you can do, and it raises all sorts of thoughts. I suppose it is technically possible to identify a date (provided you know what format it is) anywhere in the note. I'm thinking that you could probably find all notes that have DD/MM/YYYY somewhere in the content, for example.

I dabbled with regex in a couple of programs before -- powerful, but an awful lot of braces, dots and slashes. Gets confusing.

Cheers, Martin.
Back to top
 
 
  IP Logged
Mark Bernstein
YaBB Administrator
*
Offline

designer of
Tinderbox

Posts: 2871
Eastgate Systems, Inc.
Re: Setting $StartDate from $Name
Reply #8 - Oct 20th, 2012, 8:27am
 
Regular expressions do get confusing -- but it's a kind of confusion you can't get around.  It's not notational, just a matter of perverse punctuation.  

Image that you were going to reinvent regular expressions!  You're going to use something to mean "this matches any character", right?  That can either be some special character, or it could be something that isn't a character.  But if it's not a character, how do you enter it from your keyboard?  So, we'll use some character we don't need often in prose or verse:

    +:  matches any character

But we might have some crazy text that actually uses a '+' sign.  So we have another character that means, "Yeah: I mean THAT character":

    \+: matches a '+' character
    \\: matches a '\' character

And so we proceed.  It does get complicated because generalized formats can get complicated: how exactly, for example, do we know at a glance that $7,420.98  is an amount of money and that 74$.98,20 is not?  

In fact, the range of things that regular expressions can match (and the range of things that they cannot) is really one of the more beautiful results of basic computer science.

It's not just cooked up to vex you.
Back to top
 
« Last Edit: Oct 20th, 2012, 8:27am by Mark Bernstein »  
WWW   IP Logged
Mark Anderson
YaBB Administrator
*
Offline

User - not staff!

Posts: 5689
Southsea, UK
Re: Setting $StartDate from $Name
Reply #9 - Oct 20th, 2012, 11:39am
 
As Mark B points out regex are complex - but with a genuine purpose.

Meanwhile, here are some queries to find a YYYY/MM/DD sequence in $Text. First, match the sequence anywhere in $Text:

$Text.contains("(\d{4})/(\d{2})/(\d{2})")

Now only at the very beginning of $Text:

$Text.contains("^(\d{4})/(\d{2})/(\d{2})")

Now only at the very end of $Text:

$Text.contains("(\d{4})/(\d{2})/(\d{2})$")

All the above create separate backreferences to each of the YYYY MM and DD sequences. If you don't need these, simpler versions of all three of the regex above:

$Text.contains("\d{4}/\d{2}/\d{2}")
$Text.contains("^\d{4}/\d{2}/\d{2}")
$Text.contains("\d{4}/\d{2}/\d{2}$")

Want to match DD and MM where thay my be 1 or 2 digits? Then simply replace \d{2}, i.e. match only a 2 character sequence digits, with \d{1,2} which matches a sequence of 1 or 2 digits.
Back to top
 
 

--
Mark Anderson
TB user and Wiki Gardener
aTbRef v6
(TB consulting - email me)
WWW shoantel   IP Logged
Pages: 1
Send Topic Print