Any way to calculate "6 days from now" using core tools?

426 views
Skip to first unread message

Mark S.

unread,
Aug 20, 2019, 10:11:35 AM8/20/19
to TiddlyWiki
Or better yet, "6 days from given date."

Yes, I know there are plugins to allow additional math abilities.

But is there any way to do date math with existing core tools? Since there are a bunch of new math tools? I didn't see anything
that looked like it could do date math, but maybe I'm missing something?

In particular, I'd like to calculate  6, 10, 90 days out.

Thanks!

Mat

unread,
Aug 20, 2019, 3:18:41 PM8/20/19
to TiddlyWiki
Hi Mark

I found this algo


It should be enough with our new math functions. As an experiment I made the first part (the g function):

\define g(y, m, d)
<$set name=m value={{{ [[$m$]add[9]remainder[12]] }}}>
<$set name=y value={{{ [<m>divide[10]subtract[$y$]negate[]] }}}>
<$set name=y4 value={{{ [<y>add[4]] }}}>
<$set name=y100 value={{{ [<y>divide[100]] }}}>
<$set name=y400 value={{{ [<y>divide[400]] }}}>
<$set name=m3 value={{{ [<m>multiply[306]add[5]divide[10]] }}}>
{{{ [[365]multiply<y>add<y4>subtract<y100>add<y400>add<m3>add[$d$]subtract[1]] }}}
</$set></$set></$set></$set></$set></$set>
\end

This seems to work but it is only half of what is needed so I can't tell for sure. What you're asking for is

 d(g(y,m,d) + n)

which thus requires the d function and maybe also to mess a bit with the <<now>> macro to extract the desired bits. Or maybe it could be integrated into the function for a more elegant solution.

Tell me if you need more help and I'll fiddle a bit more. I'm a bit heavy on work for some time but I'm a tiddly junkie so small and well defined bits like these...

<:-)


Dave

unread,
Oct 14, 2019, 8:38:29 PM10/14/19
to TiddlyWiki
How would this actually work? (looking for the same thing)

I tried <<g 2019 11 14>> and got an answer of 738908.3635


Thanks 
- Dave

TonyM

unread,
Oct 14, 2019, 9:41:46 PM10/14/19
to TiddlyWiki
Mark,

I have successfully used Evans formulae plugin for this, however the native method I know of is as follows;

Although the days operator will not return the date for you to make use of it will be able to find tiddlers in which contain a standard date field that comply with the days operator, so you would use days[+6] days[+10] days[+90] to look that many days into the future.

you can then utilise a second days operator to eliminate days prior to today.

Here is a reply that I did in the past that helps using the days operator but not the use of two at once.

The trick I have found with the days operator is it is always relative to today, ie +4 or -4 represents dates passing through today
  • + 4 all dates in the future back today and further into the past
  • - 4 all days from 4 days ago through today in into the future
So (without retesting} [days[+4]days[-1] would be all dates upto 4 days in the future and also from yesterday (including those in the future).
Since the days operator returns the tiddler titles, from which you can extract the date that resulted from the days operator, you can do more with the date if required.

Warnings
  • It is quite easy to use two days operators that result in nothing because you eliminate all
  • Using the not ! and the + and - values can quickly trip you up because you are doing binary backflips, double negatives etc.. 

Hubert

unread,
Oct 15, 2019, 5:28:56 AM10/15/19
to TiddlyWiki
Hi Mark,

I know you've asked for a solution using core tools but I'm attaching a JS macro I made anyway in case you'd decide to use it.

The invocation is <<FutureDate YYYYMMDD y m d>> (y=years, m=months, d=days), so for example for 2 months and 15 days from the 1 December 2019 you would put <<FutureDate 20191201 0 2 15>>.

If you wish to calculate time from now, use:

\define date_offset()
<$set name=today value=<<now YYYY0MM0DD>>>
<<date_offset_2>>
</$set>
\end

\define date_offset_2()
<<FutureDate $(today)$ 0 0 90>>
\end

<<date_offset>>

The macro also works with negative numbers, so "Future" Date isn't very accurate in terms of name (feel free to rename, adjust, etc). The macro works on full days only (disregards time), so it doesn't care what timezone you're in, doesn't convert to UTC etc., it just adds/subtracts full years, months or days from the current (local) date.

The output is in the same format as the <<now>> macro, so YYYY0MM0DD (though without hours, minutes, seconds, etc. as it's time-agnostic). you can easily modify this macro if you wish a different output.

Please read the description.

Macro to find a future date based on the number of years, months or days from today.

Required input:
<<FutureDate YYYYMMDD y m d>>,
where YYYYMMDD is the starting date and y, m, d are, respectively, year(s), month(s) and/or day(s) to be added to the starting date.

Don't add more than 12 months in one parameter -- for example, instead of adding 18 months, add 1 year and 6 months.

Enjoy!

Hubert
$___Macros_FutureDate.js.json

Mark S.

unread,
Oct 15, 2019, 11:02:13 AM10/15/19
to TiddlyWiki
I forgot about this. This looks interesting, though convoluted. I've added it to my "todo" so maybe I won't forget.

Mark S.

unread,
Oct 15, 2019, 11:03:36 AM10/15/19
to TiddlyWiki
You get the number. You add the future number of days. You convert back.

Except the "convert back" part hasn't been written.

Mark S.

unread,
Oct 15, 2019, 11:09:58 AM10/15/19
to TiddlyWiki
Hi Tony,

Your approach assumes that there is a tiddler with a date field stamped accordingly. In this case there probably
would not be such a thing.

I suppose you could pre-generate a year's worth of tiddlers, but that seems inefficient.

Putting a calendar in a dictionary tiddler might work too, and would allow you to not have to use the awkward TW
date format.

Use case

With the javascript plugin, using TWC, I once had a fairly complete garden application. You have your seeds which
have a variety of important day markers: days til germination, days til harvest. You need to know if the plants are
on track. So you add the number of days to germination to the plant date, and then you can see if you are on
schedule. Repeat for harvest days. Since these are all future dates, there is unlikely to be existing tiddlers with
those date stamps.

Thanks!

Mark S.

unread,
Oct 15, 2019, 11:17:59 AM10/15/19
to TiddlyWiki
Hi Hubert,

A JS macro might be the way I'll have to go. I'm downloading your json for a look.

Note that you could combine your two TW macros by using <$macrocall $name=FutureDate ..../> in the first macro.

Thanks!

Hubert

unread,
Oct 15, 2019, 11:41:31 AM10/15/19
to TiddlyWiki
Hi Mark,

Note that you could combine your two TW macros by using <$macrocall $name=FutureDate ..../> in the first macro.

Thanks, I'm aware of that. It's just my habit of substituting things ;)

TonyM

unread,
Oct 15, 2019, 7:18:10 PM10/15/19
to TiddlyWiki
Mark,

Yes it does presume the future date exists, and this is practical if you have scheduled events. 

I do have an algorithm that can help with core tools only. Basically you do not forward date items you list them retrospectively and stamp them when reviewed..

Imagine something you wish to do fortnightly, stamp a field called fortnightly with now. Then create a tiddler called fortnightly and list all tiddlers with a fortnightly stamp older 14 days (the days operator does this). When you review that item hit a date stamp button that updates the fortnightly field and it will leave the list for a fortnight.

I am sure a variation of this would work for seed germination, it just takes a little cognitive sumersault.

Regards
Tony

Mark S.

unread,
Oct 21, 2019, 4:03:16 PM10/21/19
to TiddlyWiki
Hi Mat et al,

Ok, here's the complete kit ...  I hope. Including a sample helper macro for finding days from now.

The main thing that had to be changed in your macro is that all divisions had to be converted to integer divisions. I appended the "floor"
operator wherever needed to accomplish this.

\define g(y,m,d,offset:"0")
<$set name=m value={{{ [<__m__>add[9]remainder[12]] }}}>
<$set name=y value={{{ [<m>divide[10]floor[]negate[]add<__y__>] }}} >
<$set name=y4 value={{{ [<y>divide[4]floor[]] }}}>
<$set name=y100 value={{{ [<y>divide[100]floor[]] }}}>
<$set name=y400 value={{{ [<y>divide[400]floor[]] }}}>
<$set name=m306 value={{{ [<m>multiply[306]add[5]divide[10]floor[]] }}}>
<$set name=result value={{{ [[365]multiply<y>add<y4>subtract<y100>add<y400>add<m306>add[$d$]add[$offset$]subtract[1]] }}} >
<<result>>
</$set></$set></$set></$set></$set></$set></$set>
\end


\define d(g)
<$set name=daysperyear value="365.2425">
<!-- y = (10000*g + 14780)/3652425 -->
<$set name=y value={{{ [[10000]multiply<__g__>add[14780]divide[3652425]floor[]] }}}>
<!-- ddd = g - (365*y + y/4 - y/100 + y/400) -->
<$set name=y4 value={{{ [<y>divide[4]floor[]] }}}>
<$set name=y100 value={{{ [<y>divide[100]floor[]] }}}>
<$set name=y400 value={{{ [<y>divide[400]floor[]] }}}>
<$set name=dddtest value={{{ [[365]multiply<y>add<y4>subtract<y100>add<y400>negate[]add<__g__>] }}} >
<$set name=prioryear value={{{ [<y>subtract[1]] }}} >
<$set name=y value={{{ [<dddtest>prefix[-]then<prioryear>] [<dddtest>!prefix[-]then<y>] }}} >
<$set name=ddd value={{{ [[365]multiply<y>add<y4>subtract<y100>add<y400>negate[]add<__g__>] }}} >
<!-- mi = (100*ddd + 52)/3060 -->
<$set name=mi value={{{ [[100]multiply<ddd>add[52]divide[3060]floor[]] }}} >
<!-- mm = (mi + 2)%12 + 1 -->
<$set name=mm value={{{ [<mi>add[2]remainder[12]add[1]] }}} >
<!-- y = y + (mi + 2)/12 -->
<$set name=y value={{{ [<mi>add[2]divide[12]floor[]add<y>] }}} >
<!-- dd= ddd - (mi*306 + 5)/10 + 1 -->
<$set name=dd value={{{ [<mi>multiply[306]add[5]divide[10]floor[]negate[]add<ddd>add[1]] }}} >
<<y>>, <<mm>>, <<dd>> <br/>
</$set></$set></$set></$set></$set></$set></$set></$set></$set></$set></$set></$set></$set>
\end

\define daysfrom(y,m,d,o)
<$wikify name=future text="<<g $y$ $m$ $d$ $o$>>">
<$macrocall $name="d" g=<<future>>/>
</
$wikify>
\end

Days from: <<daysfrom 2019 10 21 11>>






On Tuesday, August 20, 2019 at 12:18:41 PM UTC-7, Mat wrote:

TonyM

unread,
Oct 21, 2019, 8:10:18 PM10/21/19
to TiddlyWiki
Mark,

This is powerfully done. It is true it needs to be packaged, so it can be readily used. In this version or an alternate macro perhaps the result could be presented in the date serial number format https://tiddlywiki.com/prerelease/#Date%20Fields, because then it could be saved in a date field and fed into the view widget date or relative date to be displayed in any format. The date serial number can then also be tested with > or < tests.

If your macro was to accept a date serial number as input plus the days from now (ideally negative days also), and output a date serial number, such a macro would be worthy of inclusion in the standard distribution. 

Perhaps even an operator (if that is possible)
daysfromnow:modified[+7]
would return a dateserial number, that could be immediately compared with another date.

Perhaps one day we may also have an operator
now[]
that would return a dateserial number of now!

Love your work!
Tony

Mat

unread,
Oct 22, 2019, 4:00:28 AM10/22/19
to TiddlyWiki
Cool stuff Mark!

Date manipulation is one of those border areas that you seemingly will never need... until you do. So thanks for sharing Mark.

<:-)

Soren Bjornstad

unread,
Dec 29, 2020, 6:31:50 PM12/29/20
to TiddlyWiki
Hi all,

I'm trying to use Mark S.'s solution, and it works great, except it appears to have a minor bug in leap years: when the result would be the 29th of February, it instead returns the 28th of February. It otherwise is doing all of the calculations for leap years correctly (e.g., adding 2 days on February 28, 2020 returns March 1, 2020).

I have to admit I have pretty much no clue what's going on with those filters, lol, so if someone is able to spot the issue I'd be much obliged.

TW Tones

unread,
Dec 29, 2020, 10:01:38 PM12/29/20
to TiddlyWiki
Soren,

There is a new format operator for dates;

Past this in a tiddler on tiddlywiki.com and see the result.

Note how it seems to honor months and leap years but will not increment the year.

{{{ [all[current]get[created]format:date[YYYY0MM0DD]] }}}
{{{ [all[current]get[created]format:date[YYYY0MM0DD]add[1]format:date[YYYY0MM0DD]] }}}
{{{ [all[current]get[created]format:date[YYYY0MM0DD]add[2]format:date[YYYY0MM0DD]] }}}

{{{ [[20000228]format:date[YYYY0MM0DD]add[1]format:date[YYYY0MM0DD]] }}}
{{{ [[20000228]format:date[YYYY0MM0DD]add[2]format:date[YYYY0MM0DD]] }}}

{{{ [[20210228]format:date[YYYY0MM0DD]add[1]format:date[YYYY0MM0DD]] }}}
{{{ [[20210228]format:date[YYYY0MM0DD]add[2]format:date[YYYY0MM0DD]] }}}

Regards
Tones

Soren Bjornstad

unread,
Dec 30, 2020, 6:37:59 PM12/30/20
to TiddlyWiki
Tones,

Thanks! I haven't gotten around to upgrading to 5.1.23 yet, so I'll give it a shot when I do. If it is unable to update the year, though, I don't think it will work in this case as I'm definitely going to need to cross year boundaries.

TW Tones

unread,
Dec 30, 2020, 6:50:30 PM12/30/20
to TiddlyWiki
Soren,

If you are only using it for short period such as 7-30 days, it would be possible to simple handle "Decembers" differently to fix the year problem. Or make use of the days operator.

Other date tools exist, perhaps review Eric's powerful http://tiddlytools.com/timer.html or Evans formulae plugin.

Tones

Stobot

unread,
Dec 30, 2020, 8:45:15 PM12/30/20
to TiddlyWiki
I'm similarly surprised that there's not an easier way to do this with core. I'm not really a Javascript user generally, but I took Jed's useful add-time.js and tweaked slightly to base it off of a base date, rather than current date. I worry about plugins also because of making my wiki "heavier" or future compatibility concerns, but this is super light-weight (code is short enough I'll post below) and I don't think reliant on any core things worth noting - so future compatibility shouldn't be an issue. My general rule is to try to only use plugins I can understand / maintain if necessary, so they have to be pretty dang simple. When I modified Jed's code slightly, I have this which I add to all my wikis:

If you feel like using this, just start a new tiddler, name it something like $:/macros/dateadd.js, change the tiddler type to "application/javascript" and save/reload. Then, you can do stuff like:
<<dateadd basedate:"20201201" days:20">> to get 20201221. I found it useful to continue to use YYYYMMDD notation because all of the stock dateformats start that way, and the days filter operators work with that format.

/*\
title: $:/stobot/macros/dateadd.js
type: application/javascript
module-type: macro

Takes a base date and adds days, months or years

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/

exports.name = "dateadd";

exports.params = [
    {name: "basedate"},
    {name: "days"},
    {name: "months"},
    {name: "years"},
    {name: "template"}
];

/*
Run the macro
*/
exports.run = function(basedate, days, months, years, template) {
    
    //Make each date object.
    
    if (basedate === "") {
        var newdate = new Date();
    } else {
        var baseyear = basedate.substr(0,4);
        var basemonth = basedate.substr(4,2);
        var baseday = basedate.substr(6,2);
        var newdate = new Date(Number(baseyear), Number(basemonth)-1, Number(baseday), 0, 0, 0);
    }

    var new_year = Number(newdate.getFullYear())+Number(years);
    var new_month = Number(newdate.getMonth())+Number(months);
    var new_day = Number(newdate.getDate())+Number(days);

    var output_date = new Date(new_year, new_month, new_day, 0, 0, 0);

    var result = (output_date.getFullYear()*10000) + ((output_date.getMonth()+1)*100) + (output_date.getDate());

    if(template === ""){
        return result;
    } else {
        return $tw.utils.formatDateString(output_date,template);
    }
};

})();

Mark S.

unread,
Dec 31, 2020, 8:21:36 PM12/31/20
to TiddlyWiki
I've updated the code at https://marxsal.github.io/various/playground.html .

It appears that the algorithm for converting the day number to the calendar date was actually wrong, but the real code as encapsulated in the sample awk script was correct. SO, after a major re-write, I think it is working now.

Keep in mind that the point of this exercise was to use tools available in the core and to overcome the limitations of the date format used by the core.
Reply all
Reply to author
Forward
0 new messages