Search a range of dates with Keyboard Maestro on macOS

The now-available upgraded search features afford a neat new capability: you can search across a range of dates!

This Keyboard Maestro macro is a bit of a quilt, made of patched-together ideas from across the Internet.

Once it’s enabled, if you trigger it, it presents a window where you can input a start date and an end date using natural language. For example: “Yesterday” and “July 30.”

After a moment, it will set your clipboard to a range of dates in the Daily Notes format, formatted to be able to search your notes in Obsidian using the new search. Like so:
(2020-07-19 OR 2020-07-20 OR 2020-07-21 OR 2020-07-22 OR 2020-07-23 OR 2020-07-24 OR 2020-07-25 OR 2020-07-26 OR 2020-07-27 OR 2020-07-28 OR 2020-07-29 OR 2020-07-30)

This looks wacky, but who cares?! You can now search your notes for e.g., that conversation you had about conceptual modelling a couple of months ago, scoping it by date.

Please note: if you have customized the date format of your Daily Notes plugin, you need to change the format this macro uses to suit. It’s the second step in the macro.

Here’s some bad screenshots of the macro: (the date format script is pasted in full below)



Screen Shot 2020-07-20 at 2.59.02 PM

And you can download it here.


The date format script (from Keyboard Maestro’s forums):

var ptyScriptName 	= "Convert Any Date String to Any Formatted Date";
var ptyScriptVer 		= "2.0";
var ptyScriptDate 	= "2018-05-01";
var ptyScriptAuthor = "JMichaelTX";  // heavy lifting by @ComplexPoint;

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PURPOSE:
	• Convert Any* Date String to Any* Formatted Date, using data from KM Macro
		where "Any" is probably those that conform to the Unicode Date formats (Ref #2)
	
RETURNS:	Date/Time String formatted as requested, 
					both as a script return, and as a KM Variable "Local__DateOutput"

REQUIRED:
	1.	macOS 10.11.6+
	2.	Mac Applications
			• Keyboard Maestro 8.2+
			
	3.	Keyboard Maestro Variables
				•	GET (input)
					•	Local__DateSourceStr
					• Local__DateOutputFormat
					
				• SET (output)
					•	Local__DateOutput		
				
TAGS:	

REF:  The following were used in some way in the writing of this script.

	1.	2018-05-01, ComplexPoint, Keyboard Maestro Discourse
			Convert clipboard date to yyyy-mm-dd
			https://forum.keyboardmaestro.com/t/convert-clipboard-date-to-yyyy-mm-dd/3155/16?u=jmichaeltx
			
	2.	2013-09-18, unicode.org/Peter Edberg, www.unicode.org
			UTS #35: Unicode LDML: Dates, Ver 33
			https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
(() => {		// this function will auto-run when script is executed
    'use strict';
		
		var scriptResults = "TBD";

try {	//~~~~~~~~~~~ START TRY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	

	var app = Application.currentApplication()
	app.includeStandardAdditions = true
		
	//--- EXAMPLES --- (all statements in this block may be removed)
	
	var date1Str = dateStrToFormattedDate("30/12/ 2017", "MMM dd, yyyy");
	//-->"May 01, 2018"
	
	
	var date2Str = dateStrToFormattedDate("2018-04-15", "");
	//-->"Apr 15 2018"
	
	var date3Str = dateStrToFormattedDate("", "");
	//-->"May 1 2018"

	
	//-----------------------------------------------------------
	
	//--- GET KM VARS with Default Values ---
	
	
	var kmeApp 						= Application("Keyboard Maestro Engine");
	var kmInst 						= app.systemAttribute("KMINSTANCE");

	var dateSourceStr 		= kmeApp.getvariable('Obsidian date range search start',  {instance: kmInst}) || "today";
	var dateOutputFormat 	= kmeApp.getvariable('Obsidian date format',  {instance: kmInst}) || "yyyy-MM-dd";
	
	var dateOutputStr 		= dateStrToFormattedDate(dateSourceStr, dateOutputFormat);

	//--- Set KM Output Variable Even if Date is empty string --

	kmeApp.setvariable('Local__DateOutput', { to: dateOutputStr,  instance: kmInst });
	
	if (dateOutputStr) {
	scriptResults					= dateOutputStr;
	
	} else {		// Return Error Msg if Data Can't be converted
	
		throw new Error("Unable to Convert Date from: " + dateSourceStr + "   Using format: '" + dateOutputFormat + "'");
	}
	
} //~~~~ END TRY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

catch (oError) {
	
	if (oError.errorNumber === -128) {	// User Canceled
	
		scriptResults =  "[USER_CANCELED]\n\n"
			+ "SCRIPT: " + ptyScriptName + "   Ver: " + ptyScriptVer
	}
	
	else {
		var errNum = oError.errorNumber || "Custom Error";
		scriptResults = "[ERROR]\n\n"
			+ "Error Number: " + errNum + "\n"
			+ oError.message
			+ "\n\nSCRIPT: " + ptyScriptName + "   Ver: " + ptyScriptVer
			
	} // END if/else on ERROR Number
	
} //~~~~ END TRY/CATCH BLOCK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	
	return scriptResults;
	
	//~~~~~~~~~~~~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~~~~~~~
		
	function dateStrToFormattedDate(pDateStr, pFormatStr) {	
	
	/*
		For Date/Time Format Syntax, see
		https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
		
		For macOS Locale Identifiers, see
		##TBD##
	*/
		//--- SET DEFAULT VALUES ---
	
		pDateStr 		= pDateStr 		|| 'today';				// Default input date string
		pFormatStr 	= pFormatStr 	|| 'yyyy-MM-dd';	// Default output format

		//--- USE ObjC to Convert Input Date String and Output as Formatted ---
		
    const nsDateFmtr = $.NSDateFormatter.alloc.init;
		
    nsDateFmtr.setLocale($.NSLocale.localeWithLocaleIdentifier('en_US_POSIX'));
    nsDateFmtr.setDateFormat(pFormatStr);
		
		//--- Use .js to Convert DataType from ObjC to JavaScript (same as ObjC.unwrap) ---
		var dateStrNewFormat = nsDateFmtr.stringFromDate($.NSDate.dateWithNaturalLanguageString(pDateStr)).js;
		
		//--- Return Empty String if Conversion Fails (undefined) ---
		return (dateStrNewFormat || "");
  };

})();
4 Likes