# Yet another date calculator

## Recommended Posts

Date Calculator

Hello there!

I needed a bit of motivation to learn Python and Alfred workflows, so I thought I’d kill two horses with one bullet, so to speak.

Right, so this is a date calculator – kind of. It won’t tell you when you will the lottery, or how long you’ve got to hide your ‘arty videos’ before your wife gets home, but it will answer one or two very simple questions about dates.

For example, if you enter

dcalc 25.12.14 - 18.01.14

then it will tell you the number of days between those dates. Note that the workflow parses the command as you enter it, so you’ll see invalid commandinvalid expression and invalid formaterrors as you type. Once you’ve completed the command then you’ll be given the result.

You could also try

dcalc 25.12.14 - now

for the number of days until Christmas. (Always seems so far away . . .)

Maybe you don’t want it in days, but would rather it in weeks:

dcalc 25.12.14 - now w

or days and weeks

dcalc 25.12.14 - now wd

or years, months, weeks and days

dcalc 25.12.14 - now ymwd

or

dcalc 25.12.14 - now long

will do the same thing. Personally, I always use the long format because it’s more accurate.

For those who like to look ahead, you can add days to a date

dcalc now + 6d

or weeks

dcalc 18.12.14 + 9w

or combine ‘em

dcalc 18.12.12 + 5y 9d 3w - 2d + 1d 1w

What does that mess do?

• Take the date 18.12.12
• Then take off 2 days
• And then add another 1 week

If you want to know what week number you’re in, then try this:

dcalc today wn

Or for a specific date:

dcalc 25.12.14 wn

You can also use the today thing in other places too:

dcalc today + 4d

And we have another thing called time because the workflow can handle times too:

dcalc time + 6h 8M

will add 6 hours and 8 minutes to the current time. Note the capital ‘M’ to denote minutes. Odd, I know . . . sorry, but the workflow has to distinguish between this and a small ‘m’ (for months). I figured make this one a capital because it would see much less use. (It has for me.)

If you just want the current time, then just enter

dcalc time

Here’s another time calculation

dcalc 14:35 + 6h

That’s the time 6 hours from now, and for real nerdiness:

dcalc 21.06.14@14:20 - 23.01.12@09:21 long

Probably not all that useful, but some of this other stuff might be. You know all about

dcalc now

For giving you the current time and date. While you can use

dcalc tomorrow

for tomorrow’s date, and as you would expect

dcalc tomorrow + 1d

will give you the day after tomorrow.

dcalc next tue

will give you the date next Tuesday. Or for for Thursday you could enter

dcalc next tue + 2d

if you’re still a little too inebriated to realise that

dcalc next thu

will give you the same answer.

That about covers it, I think. I haven’t done anything clever with locales, but you can pick a different date format with

dcalcset date format

And we also support both 12-hour and 24-hour time formats.

dcalcset time format

I would recommend sticking with the 24-hour format; it's a lot easier to type because the AM/PM symbols have to be in upper case.

You can also set the combined date and time format using:

dcalcset date and time format

If you’re ever puzzled by invalid command or invalid expression errors, then start with the settings; they might be set incorrectly.

Oh, almost forgot.

dcalc easter

Is the date for next Easter Sunday, for no other reason that I can never remember it, and now there’s an easy way to find out how many days until Christmas:

dcalc today - christmas

And to celebrate finishing my new book, I decided to add:

dcalc passover

Alternative parser

If surround a simple expression in double quotes, then something quite magical happens:

dcalc "4 hours 8 minutes after 4pm"

or

dcalc "6 weeks and 4 days after next wednesday"

or

dcalc "1 day after tomorrow"

Yup! A natural date language parser!

You can even combine it with the existing parser:

dcalc "next friday" + 1d

This is a little bit experimental (I might drop it later if it proves to be problematic), but I thought I'd throw it in for a bit of a fun.

Credits

A list of things that made my first attempt at Python programming possible:

• Dean Jackson for his more-than-slightly awesome Alfred Workflow framework(Jetbrains(HumanFriendly(Python-DateUtil(PyPEG(ParseDateTime(Programming Praxis(MIT(http://opensource.org/licenses/MIT) one will do. :-)

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files (the "Software"), to deal

in the Software without restriction, including without limitation the rights

to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

copies of the Software, and to permit persons to whom the Software is

furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in

all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE

AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Edited by MuppetGate
• Replies 132
• Created

#### Posted Images

It will only say: Invalid command!

Very nice.

Have you thought about making a Script Filter, so that you get the result/error message live?

Kinda like this:

Edited by deanishe

It will only say: Invalid command!

Like he said, you probably need to check the settings.

For whatever reason, the default date format in the workflow is "dd-mm-yy", not "dd.mm.yy" as in the description…

It will only say: Invalid command!

Yes, not only did I forget to set the correct default, I also forgot to credit the HumanFriendly folk for a library.

I'll sort it out later today.

It will only say: Invalid command!

Okay, that should have taken care of it.

Very nice.

Have you thought about making a Script Filter, so that you get the result/error message live?

Kinda like this:

That's very clever!

I'll have a crack at it when I've checked some examples.

It's child's play compared to the rest of the workflow. Very impressive stuff!

You just need to change the Keyword to a Script Filter and use wf.add_item() and wf.send_feedback() instead of print().

Here's the hacky wrapper I made to turn it into a Script Filter. Lines 26, 28 and 31 are the important bits, the rest is just boilerplate:

```from __future__ import print_function, unicode_literals

import sys
from StringIO import StringIO

from workflow import Workflow, ICON_ERROR

from date_calculator import main as other_main
from date_format_mappings import DEFAULT_WORKFLOW_SETTINGS

def main(wf):
# Replace sys.stdout to capture the script output
stdout_orig = sys.stdout
sys.stdout = StringIO()
# Run the script and grab the output
other_main(wf)
result = sys.stdout.getvalue()
# Put sys.stdout back together again, so wf.send_feedback() sends its
# output to the right place
sys.stdout.close()
sys.stdout = stdout_orig

# Add error/output to list of results
if result.startswith('Invalid '):
else:
wf.add_item(result, 'Copy to clipboard', valid=True, arg=result)

# Send XML output to Alfred
wf.send_feedback()

if __name__ == '__main__':
wf = Workflow(default_settings=DEFAULT_WORKFLOW_SETTINGS)
sys.exit(wf.run(main))
```
Here's how to make a Script Filter with Alfred-Workflow (you should probably skip straight to the section on Actions), and here are the docs on add_item().

You need to set a value for arg and valid=True in add_item() to make a result actionable.

I just used one of the system icons supported by Alfred-Workflow for the error message.

Edited by deanishe
Fix URLs

Thanks. The newer version works fine.

Thanks. The newer version works fine.

Great! :-)

Thanks for letting me know.

I've now implemented the 'parse-as-you-type' feature suggested by Dean, so there's a new version up On Packal.org

The newer, newer version works good to. I also like the feedback. I mostly use script filters in my workflows just so that I can get feedback easily. Thanks

Me again.

I've just dropped a new version of the date calculator onto Packal

Fixes a few bugs and simplifies the error reporting. Also added a few macros shortcuts for today, tomorrow, days of the week and Christmas

Pfft! It doesn't know my birthday. USELESS!

Nice update

I had a look in the workflow directory. There appears to be another copy of the workflow within the workflow. I suspect that wants removing…

Yup. It certainly does!

Done!

I'll get the hang of this one day . . .

Nice.

I've made a couple modifications you might consider:

I added one line to the DATE_MAPPINGS array in date_format_mappings.py - very clear code that was easy to customize:

``` 'yyyy-mm-dd':{'name': 'long inverted US date (-)','date-format':'%Y-%m-%d','regex':'\d{4}-\d{2}-\d{2}'},
```

I added an additional Applescript output from the dcalc script filter with a shift modifier to open Fantastical to the calculated date, with the following very simple script:

```on alfred_script(q)
tell application "Fantastical"
parse sentence (q)
end tell
end alfred_script
```

This makes for a nice quick way to quickly calculate a date and immediately start adding an event or checking what's on my calendar for that date.

Good thinking, dfay!

Especially sending it to Fantastical. I think Apple Calendar can handle simpler dates, too, but I'm not sure.

One minor gripe: yyyy-mm-dd is an international date format, not a US one.

Everyone uses it.

Nice.

I've made a couple modifications you might consider:

I added one line to the DATE_MAPPINGS array in date_format_mappings.py - very clear code that was easy to customize:

``` 'yyyy-mm-dd':{'name': 'long inverted US date (-)','date-format':'%Y-%m-%d','regex':'\d{4}-\d{2}-\d{2}'},
```

I added an additional Applescript output from the dcalc script filter with a shift modifier to open Fantastical to the calculated date, with the following very simple script:

```on alfred_script(q)
tell application "Fantastical"
parse sentence (q)
end tell
end alfred_script
```

This makes for a nice quick way to quickly calculate a date and immediately start adding an event or checking what's on my calendar for that date.

Thanks very much for that.

I'll add in the date format (not sure how I managed to miss it to be honest).

I figure that any additional outputs should be pretty easy for anyone to add; that's why I decided to keep the extra text down to a minimum, and tried to make it easy to parse. But a great suggestion, and I'm going to try out Fantastical.

Pfft! It doesn't know my birthday. USELESS!

Fixed.

Edited by MuppetGate

It doesn't work for me

I followed the instructions above, but "dcalcset list add dean xx-xx-xxxx" give me an "Invalid command" error

"dcalcset format" now appears to be an unknown command

You also appear to have removed the download link from the OP. It's got links to all the stuff you used to make the workflow (apart from Smirnoff), but there doesn't appear to be one to the actual workflow any more!

And another thing: the workflow description on Packal says "A very basic date calculator". Basic? Premium more like.

It doesn't work for me

I followed the instructions above, but "dcalcset list add dean xx-xx-xxxx" give me an "Invalid command" error

"dcalcset format" now appears to be an unknown command

You also appear to have removed the download link from the OP. It's got links to all the stuff you used to make the workflow (apart from Smirnoff), but there doesn't appear to be one to the actual workflow any more!

Okay, I imagine you're entering in the correct date format.

The dcalcset format seems to be okay at my end too.

I'll try loading it from packal to make sure I haven't missed anything.

Are you running with Python 2.7?

Edited by MuppetGate

Yeah, double-checked the format, deleted the settings file and re-installed before posting.

I'm on Mavericks, so Python 2.7.

FWIW, python will always refer to the system Python in Alfred, as it doesn't use your PATH. Unless someone was dumb enough to overwrite /usr/bin/python

Right, I'm going to have to sleep on this one, I think.

Can't think why this wouldn't work on your machine.

Always tricky when you can't see it running ...

Edited by MuppetGate

Quick question:

What happens if you enter

dcalcshow list