JavaScript date manipulations in TextExpander

A few days ago, Teddy Svoronos tweeted this request:

@TextExpander trying to get a work week snippet that populates mondays to fridays date (eg, 7/20/15 - 7/24/15) that works on ios. any tips?
  — Teddy Svoronos (@tedsvo) Wed Jul 22 2015 6:07 PM

I was busy with paying work at the time, so naturally I stopped what I was doing and wasted some time working out a solution. This is it.

1:  var oneday = 24*60*60*1000;
2:  var today = new Date();
3:  var wdToday = today.getDay();
4:  var daysAway = 1 - wdToday;
5:  if (daysAway <= 0) { daysAway += 7; }
6:  var nextMonday = new Date(today.getTime() + daysAway*oneday)
7:  var theFriday = new Date(nextMonday.getTime() + 4*oneday)
8:  nextMonday.toDateString() + ' to ' + theFriday.toDateString();

It gives the date range of the next working week in a format that Teddy probably doesn’t like at all. I sure don’t.

Mon Jul 27 2015 to Fri Jul 31 2015

JavaScript doesn’t have a flexible date/time formatting minilanguage like strftime or its many descendants. Instead it has a bunch of to*String functions, none of which are probably what anyone wants. So if you want to stick with pure JavaScript, you’ll have to dig in and extract the various parts of the date to get a better format. Or…

There are libraries like Moment.js that’ll do time and date formatting, and you can take advantage of them in TextExpander by using the snippet trick: save the JavaScript code of the library in a plain text snippet of its own and give it a long abbreviation that you’ll never use for any other snippet. Then invoke that snippet at the top of every JavaScript that uses the library.

I copied the minified source code of moment.js and pasted it into a new snippet that I gave the abbreviation momentjslibrary, a name I’ll never use (except in this post).

TextExpander Moment.js snippet

With that in place, I can rewrite my next week snippet to give more compact output:

1:  %snippet:momentjslibrary%
2:  var today = moment();
3:  var wdToday = moment().day()
4:  var daysAway = 1 - wdToday;
5:  if (daysAway <= 0) { daysAway += 7; }
6:  nextMonday = today.add(daysAway, 'days')
7:  nextMonday.format('M/D') + ' to ' + nextMonday.add(4, 'days').format('M/D')

Calling this snippet inserts

7/27 to 7/31

I’m sure Moment.js has a cleaner way to define nextMonday, but I find its documentation of the day method ambiguous when it comes to the definitions of “last Monday,” “next Monday,” and “this Monday.” To avoid the ambiguity, I stuck with my old code in Lines 4 and 5.

By fiddling with the arguments to the format method, you can get pretty much any output you like. And the great thing is that unlike AppleScript snippets, JavaScript snippets can be used in both the OS X version and the iOS version (as long as you don’t invoke any JavaScript for Automation functions).

TextExpander has many date manipulation and formatting features built in, but I don’t think there’s any way for the built-ins to reproduce what this JavaScript can do.