Accepting input for both value and units in ICUDateTimePlus

Hi,

I’m experimenting with a date generator snippet that I’d like to accept input for both the value and the units of ICUDateTimePlus.

Step 1: Prompt with 2 variables (Delay and Unit)

Step 2: Insert text using %ICUDateTimePlus%Delay%Unit%yyyy-MM-dd%

But this doesn’t work as I believe some of the % needed to convert the variables into values are missing.

Any guidance on how to get this working would be very much appreciated as I’ve been trying variants for a while without any success :-).

thanks

Have you tried this syntax yet?

%ICUDateTimePlus%%Variable%Delay%%Variable%Unit%%yyyy-MM-dd%

Also, it seems like you might be leaving out a crucial operand between the Delay and Unit variables; as-is, you’ll only end up with their respective numbers side by side, which would lead to their being interpreted as a new and different number (i.e. if Delay is 2 and Units is 18, including them as just %Variable%Delay%%Variable%Unit% will result in 218), which I’m guessing isn’t what you want, so you’ll probably want to include a * or / between them as appropriate for what you’re trying to accomplish.

That doesn't seem to work either. Entered "4" and "Weeks" and the output is %ICUDateTimePlus%Variable4Weeks%yyyy-MM-dd%

I got the escapes somewhat right… but the format is not evaluated anymore. I guess I can’t really call that right, right? :slight_smile:

Got it. Turns out you need a lot more %s, and an additional filtering step. Here's a working proof-of-concept:

Calculate ICUDateTimePlus with Variables.kmmacros (2.8 KB)
34 PM

This syntax:

%ICUDateTimePlus%%%Variable%LocalDelay%%%%Variable%LocalUnit%%yyyy-MM-dd%

Expands to %ICUDateTimePlus%4%Weeks%yyyy-MM-dd% during the "Set Variable" step, so from there, we just need to process its now properly-formatted tokens with the filter action, giving us 2018-05-17.

1 Like

The Filter step with Process Tokens is both a TIL and the solution!!!

Thanks @gglick

This is the final version:

(nb even if it uses ICUDateTimePlus it seems to work with negative numbers too).

Thanks @gglick for the help.

1 Like

It is working, but only because you are confusing the parser just the right amount. You should double all the percent characters you do not want expanded, so something like:

%%ICUDateTimePlus%%%Variable%LocalDelay%%%%Variable%LocalUnit%%%yyyy-MM-dd%%

Highlighting the doubled percentages by replacing %% with ## it would be:

##ICUDateTimePlus##%Variable%LocalDelay%##%Variable%LocalUnit%##yyyy-MM-dd##

Each of those doubled percentages are converted to a single percentage, which the remaining are part of the Variable tokens.

1 Like

Sometimes confusing things just the right amount is the best one can hope for :slightly_smiling_face:
Thanks for the clarification!

1 Like

Peter, this all continues to be confusing to me.

In the KM Wiki, Dates and Times -- Add time to Date, we show this, which I just verified:

image

where "DAT_Days" is a KM Variable, used for the amount parameter.

but this fails:

image

where the only real difference is I used a KM Variable, "DAT__Units", instead of the "Days" hard-coded unit. Why?

If we can use a KM Variable for the amount parameter, then logic dictates that we should be able to use one for the units parameter. Should this be changed?

IAC, we need to update the KM Wiki to make it clear and correct.

% ICUDateTimePlus%DAT__Days%Days%EEE, MMM d, yyyy h:mm%

That is fine because the section between the second and third percent (DAT__Days ) is a calculation field, so there is no problem using a variable there. And indeed @gglick’s version could be simplified to:

%%ICUDateTimePlus%%LocalDelay%%%Variable%LocalUnit%%%yyyy-MM-dd%%

The section between the third and fourth percent (Days) is plain text, there is no processing done on it. This is the part of the OP’s issue ("Accepting input for … units in ICUDateTimePlus") that requires jumping through hoops.

Because tokens can contain calculations (which generally do not include % characters), but tokens cannot contain tokens (which do contain percent characters and therefore make the parser impossible).

Logic only dictates that if you consider numeric fields and text fields interchangeable, which they are not.

The wiki is clear and correct I believe. If you want to add this extra case of being able to specify the units, that might be worthwhile, although it seems an extreme case - generally you can just use the smallest unit (eg Seconds) and adjust your variable as necessary.

And what makes one be a "calculation" field and the other a "text" field?
How would anyone know? I don't see any indications of this.

<rant>
Isn't this just a design choice you have made for using the ICU date/times?
In spite of knowing the formula (double % to get one), it makes things very complex and very hard to read. Plus we then have to add another "Filter" action, which doesn't make sense calling it a "filter", when it is really doing a conversion.

On top of all this is that the KM requires for us to reverse the normal programming convention where all text is a variable, command, or keyword, etc, unless it is in some form of quotes. And I don't understand the need for this. Once we have gone through all the hoops to get the number of %'s correct, why can't you just evaluate it as normal?

It is the combination of all of this not-so-clear-logic that makes this very hard to use, and very frustrating.
</rant>

Presumably by reading the documentation on the token.

The third field of the token is the Time Units, and it has a set of possible values. It's not a calculation, it is essentially the same as the first part of the token (“ICUDateTimePlus”) - just a string which has some meaning.

You mean to not have any processing? No, its not just a design choice, you can't put text tokens inside text tokens, it would be impossible to parse. I could allow a variable name instead, as long as the variable name didn't match any of the possible token values, but that would be inconsistent with everything and prone to disaster.

That’s what a filter is - it takes some sort of input and converts it into some sort of output.

That is because this is text, not a programming language. This is text, and then it has a template engine which allows you to insert non-text elements into it. This is the same style used in many other places (such as Mail Merge form letters for example). So there needs to be some way to specify, within the text, that a part is not just plain text. That is where the percent encoded tokens come in (in other template engines, other characters might be used, like angle brackets for example).

So now you have a token, within text, like %LongDate%. And from that, extended, gives tokens like %ICUDateTimePlus%5%Days%yyyy-MM-dd%. Within that, there are four fields:

  • ICUDateTimePlus - plain text, one of a set of possible values , defines the token
  • 5 - calculation (which cannot include % characters)
  • Days - plain text, one of a set of possible values, defines the time units
  • yyyy-MM-dd - this is actually another template engine with the ICU Date Time format. In this case, most of the characters are actually standins for substituted text, but all non-substituted text is passed through unchanged.

I understand that by the time you start taking this rather complex token, and wanting to do more than it was designed form, things have gotten pretty complicated, but that complexity comes from the nature of the problem, none of this is just "a design choice", or more, it is a consequence of higher level design choices.

I suppose Keyboard Maestro text fields count be more like some sort of programming language, where things are quoted, but do you really want to have to say things like:

I can’t imagine that being a net-benefit.

There isn't any practical way for me to support tokens within the plain text section of other tokens because the parser would have no hope of figuring out what it meant - the fields within tokens have to not include percent characters in order for the parser to figure it out.

There is some exception to this in that calculations that include brackets must have the brackets balanced, and therefore text within them can have percent characters. So you can actually have percent characters within tokens, as long as they are within nested brackets (at least in some cases). This allows the Calculate token to contain text functions like this:

The Words variable contains %Calculate%CHARACTERS(%Variable%Words%)% characters.

So maybe I could introduce some sort of style like this:

%ICUDateTimePlus%DAT__Days%[%Variable%DAT__Units%]%EEE, MMM d, yyyy h:mm%

But the square brackets would have to be recognised and removed, and then its not really text, since now the meaning of the square brackets are special, and so its only applicable to cases where the token can only have a set of know values that cannot include the square bracket (otherwise it would inexplicably change the meaning of text that just had square brackets at the start and end).

Hopefully this explains why it is like this. None of this is just some sort of capricious design choice on my part, it is a consequence of the whole setup and trying to do (and allow to be done) more than Keyboard Maestro is designed to do. In this case, if the solution of using the Process Tokens filter to get a second level of indirection is too onerous, then accept that ICUDateTimePlus cannot be used in this way. The Process Token filter is more or less specifically designed to allow this sort of excess.

1 Like

Peter, thanks for taking the time to fully explain why the ICU token works like it does.

After having read and thought about this, I guess I'd find two things helpful if they could be done:

  1. Provide a ICUDateTime popup builder that would build the complicated embedding of variables in the token, that would be located in the Insert Token > Dates popup.
  2. Provide an Action Gear Option to process the computed token without requiring a follow-on Filter Action.
  3. On a related topic, provide the same type popup builder for using dynamic variables. #2 would also work for this.

I suspect many other user would also find this helpful. It seems we have had many discussions on configuring the ICUDateTime token.

1 Like

This is on the todo list, though it is a lot of work so I have no idea when it might happen.

I don’t follow. You mean add another option to the options already in the Gear menu:

  • Process Text Normally
  • Process Text Tokens Only
  • Process Nothing

You want something like "Process Tokens Twice"?

It's possible, but it seems a bit bizarre, and doesn't remove any of the complexity of doubling all the %’s etc.

I don’t know what you mean by this.

Well, I would call it something like "Process/Resolve All Tokens".
What's bizarre about it? Just asking KM to resolve the text until no tokens remain -- only the resulting data. IOW, perform the same function as a follow-on Filter Action.

When we create a dynamic KM Variable, it looks much like the ICUDateTime in terms of tokens and multiple %.

image
IAC, the result is:
%Variable%VarNameAfterResolvingTokens%

So, #2 would simple resolve this final token like it would the ICUDateTime.

Those two are not the same thing. What happens if the resulting data contains something that looks like a token.

For example what happens with input of %%%%%%%%?

What happens if the resulting data is supposed to have a couple percent characters in it?

Sure, but as I said, it only removes the need for the Filter: Process Tokens action, it does not remove the complexity of getting the input correct in the first place, properly doubling the appropriate percent characters. So the reduction in complexity seems fairly low.

I think we must be talking about different things.

Ask yourself the same questions, but apply to the Filter action.

All I'm asking for is exactly the same thing that a follow-on Filter action would provide, but provide it as an option in the gear menu.

So, if the Filter produces unusable results, then this new option would as well. I'm sure you are well aware of "GIGO".

Yes, that is what I originally said, “Process Tokens Twice”. That would be the equivalent of Process Tokens followed by Filter: Process Tokens. Which is not equivalent to “Process/Resolve All Tokens”, which is more like "Process Tokens until it stops changing".

Well, I guess I'll beat this dead horse one more time, then quit wasting our time. :wink:

“Process Tokens until it stops changing” is really what I'd like, and it would be the equivalent to the user entering one or more Filter Actions. Both can lead to erroneous/unusable results if the user feeds them bad data.

But if you don't see the utility in that, then just ignore this. OTOH, perhaps it should be ignored in any case. If the user has something that complex he/she is trying to write in KM, it is likely esoteric and they should probably be using another language. I'm sure you have bigger fish to fry. :wink:

1 Like