×

Date

All of the Omni applications incorporate the use of dates, especially OmniFocus and OmniPlan. The following materials demonstrate how to generate and manipulate the JavaScript date objects that are used by Omni Automation to describe points in time.

Deriving Dates Relative to Date

A common practice in scripts is to create JavaScript date objects that represent future dates relative to an origin date, such as today.

The following details three commonly used techniques for deriving such date objects.

1) Using JavaScript

The JavaScript language has built-in methods for creating and manipulating instances of its Date class (date objects).

This example Omni Automation script uses the built-in JavaScript methods to generate a date object that references an entry that occurs on the 20th of next month at 1:00PM

Using JavaScript Date Functions


// next month on the 20th at 1PM var d = new Date() var dateObj = new Date(d.getFullYear(), d.getMonth() + 1, 20, 13)

2) Using DateComponents Class

The DateComponents class (see details in section below) and its functions are included in the Omni Automaton Calendar class, which is shared by all Omni applications.

Using DateComponents you can avoid the complex nested date calculations inherent in the built-in JavaScript date handling. The use of DateComponents may require more statements, but is clearer to visualize, as in the following example that generates a date object referencing a time three days from today at 10:30AM

Using DateComponents Class and Functions
 

// in three days at 10:46AM var now = new Date() var today = Calendar.current.startOfDay(now) var dc = new DateComponents dc.day = 3 dc.hour = 10 dc.minute = 46 dc.second = 0 var dateObj = Calendar.current.dateByAddingDateComponents(today, dc)
 

3) Using Formatter Class Date Interpreters

In Omni applications, date entry fields support the entering of shortcut date terminology, such as the words: “today” or “tomorrow” or shorthand values like: “+3d” or “3 days”

The value for a date input field can written using any syntax supported by an OmniOutliner date field. For example:

Using an instance of the shared Formatter.Date class, you can convert those supported shorthand terms into date objects for use in scripts!

For example, the following script shows how to create a date object for three days from today at 9:30AM

Using Formatter Class and Functions


// in three days at 9:30AM var fmtr = Formatter.Date.withStyle(Formatter.Date.Style.Short) var dateObj = fmtr.dateFromString('3d @ 9:30a')
 

DateComponents Class

The DateComponents class represents the elements that comprise a date, such as day, hour, year, and minute.

Constructors

Instance Properties

The properties of an instance of the DateComponents class:

Script examples using the DateComponents class of the Calendar class instance functions:

Date Components from Date


var date = new Date() var dc = Calendar.current.dateComponentsFromDate(date) dc.month + "/" + dc.day + "/" + dc.year //--> 8/23/21
Date from Components


var dc = new DateComponents() dc.month = 12 dc.day = 31 dc.year = 2021 var date = Calendar.current.dateFromDateComponents(dc) //--> Fri Dec 31 2021 00:00:00 GMT-0800 (PST)
Components Between Dates


var startDate = new Date("8/1/2021") var endDate = new Date("10/15/2021") var result = Calendar.current.dateComponentsBetweenDates(startDate, endDate) console.log(result.month) //--> 2 console.log(result.day) //--> 14

Creating a relative date object 45 days and 17 hours from the start of today:

Generate Relative Future Date/Time


var now = new Date() var today = Calendar.current.startOfDay(now) console.log(today) //--> Wed Oct 14 2020 00:00:00 GMT-0700 (PDT) var duration = new DateComponents() duration.day = 45 duration.hour = 17 var targetDate = Calendar.current.dateByAddingDateComponents(today, duration) console.log(targetDate) //--> Sat Nov 28 2020 17:00:00 GMT-0800 (PST)

A function for retrieving all occurrences of a specified weekday in a specified month. In JavaScript, the index of a weekday is an integer from 0 (Sunday) to 6 (Saturday).

Get All Occurrences of Weekday in Month


function weekdayOccurrencesInMonth(weekdayIndex, monthIndex, yearIndex){ var cal = Calendar.current var dc = new DateComponents() dc.day = 1 dc.month = monthIndex dc.year = yearIndex var monthLength = new Date(yearIndex, monthIndex, 0).getDate() var matchedDates = new Array() for (var i = 1; i < (monthLength + 1); i++) { dc.day = i var d = cal.dateFromDateComponents(dc) if (d.getDay() === weekdayIndex){matchedDates.push(d)} } return matchedDates }

Using the function to get the 2nd Monday of May 2021:

2nd Monday of May 2021


var secondMonday = weekdayOccurrencesInMonth(1, 5, 2021)[1] console.log(secondMonday)

Date Comparison Functions

The properties and functions of the DateComponents class can be used to create comparison functions that check whether the provided date object falls on a specific date or range.

A function that returns true if the provided date/time takes place today:

Does this take place today?


function dateOccursToday(dateToCheck){ var cal = Calendar.current var now = new Date() var midnightToday = cal.startOfDay(now) var dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 1 var midnightTomorrow = cal.dateFromDateComponents(dc) return ( dateToCheck >= midnightToday && dateToCheck < midnightTomorrow) }}

A function that returns true if the provided date/time took place yesterday:

Did this take place yesterday?


function dateOccurredYesterday(dateToCheck){ var cal = Calendar.current var now = new Date() var midnightToday = cal.startOfDay(now) var dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day - 1 var midnightYesterday = cal.dateFromDateComponents(dc) return ( dateToCheck >= midnightYesterday && dateToCheck < midnightToday) }

A function that returns true if the provided date/time takes place tomorrow:

Does this take place tomorrow?


function dateOccursTomorrow(dateToCheck){ var cal = Calendar.current var now = new Date() var midnightToday = cal.startOfDay(now) var dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 1 var midnightTomorrow = cal.dateFromDateComponents(dc) dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 2 var dayAfterTomorrow = cal.dateFromDateComponents(dc) return (dateToCheck >= midnightTomorrow && dateToCheck < dayAfterTomorrow) }}

A function that returns true if the provided date/time takes place next week:

Does this take place next week?


function dateOccursNextWeek(dateToCheck){ var fmatr = Formatter.Date.withStyle(Formatter.Date.Style.Short) var weekStart = fmatr.dateFromString('next week') var dc = new DateComponents() dc.day = 7 var followingWeek = Calendar.current.dateByAddingDateComponents(weekStart, dc) return (dateToCheck >= weekStart && dateToCheck < followingWeek) }

A function that returns true if the provided date/time takes place this month:

Does this take place this month?


function dateOccursThisMonth(dateToCheck){ var cal = Calendar.current var currentMonthIndex = cal.dateComponentsFromDate(new Date()).month var targetMonthIndex = cal.dateComponentsFromDate(dateToCheck).month return (targetMonthIndex === currentMonthIndex) }

A function that returns true if the provided date/time takes place next month:

Does this take place next month?


function dateOccursNextMonth(dateToCheck){ var cal = Calendar.current var dc = cal.dateComponentsFromDate(new Date()) dc.day = 1 dc.month = dc.month + 1 var nextMonth = cal.dateFromDateComponents(dc) var nextMonthIndex = cal.dateComponentsFromDate(nextMonth).month var targetMonthIndex = cal.dateComponentsFromDate(dateToCheck).month return (nextMonthIndex === targetMonthIndex) }

A function that returns true if the provided date/time takes place on the provided target date:

Does this take place on target date?


function dateOccursOnTargetDate(dateToCheck, targetDate){ var cal = Calendar.current var targetDateStart = cal.startOfDay(targetDate) var dc = cal.dateComponentsFromDate(targetDateStart) dc.day = dc.day + 1 var dayAfterTargetDate = cal.dateFromDateComponents(dc) return ( dateToCheck >= targetDateStart && dateToCheck < dayAfterTargetDate) }

Date Library

To provide easy access to the comparison functions from other scripts and plug-ins, the comparison functions have been placed into a single-file plug-in library file. This Omni Automation library can be called from within scripts or plug-ins for any of the Omni applications. TAP|CLICK the “Download Library” button to download the library plug-in archive.

The library, once installed, can be loaded and called in scripts using the following statements:

Calling the Date Library


var libFile = PlugIn.find("com.omni-automation.all.date-library") var lib = libFile.library("all-date-library") // lib.function-to-call() lib.info()

The example library includes a function titled info() that returns the names and values of all of the library’s properties and functions. Adding this function to the libraries you create is a good practice, and provides users with a quick way to learn how to use your library.

Library Info Function


lib.info = function(){ var libProps = Object.getOwnPropertyNames(lib) libProps.forEach((propName, index) => { if (index != 0){console.log(" ")} console.log("•", propName) var item = lib[propName] if (typeof item === "string"){ console.log(item) } else if (typeof item === "function"){ console.log(item.toString()) } else if (typeof item === "object"){ if(item instanceof Version){ console.log(item.versionString) } else if(item instanceof PlugIn){ console.log(item.identifier) } } }) }
library-info

NOTE: In order to have the function code returned correctly when the library info() function is called, align your functions in the library to be flushed to the left side — removing some of preceding tabs:

The Date Comparison Library
 

/*{ "type": "library", "targets": ["omnifocus","omnigraffle","omnioutliner","omniplan"], "identifier": "com.omni-automation.all.date-library", "author": "Otto Automator", "version": "1.1", "description": "A library of date functions." }*/ (() => { var lib = new PlugIn.Library(new Version("1.1")); // returns true if provided date/time occurs today lib.dateOccursToday = function(dateToCheck){ var cal = Calendar.current var now = new Date() var midnightToday = cal.startOfDay(now) var dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 1 var midnightTomorrow = cal.dateFromDateComponents(dc) return ( dateToCheck >= midnightToday && dateToCheck < midnightTomorrow) } // returns true if provided date/time took place yesterday lib.dateOccurredYesterday = function(dateToCheck){ var cal = Calendar.current var now = new Date() var midnightToday = cal.startOfDay(now) var dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day - 1 var midnightYesterday = cal.dateFromDateComponents(dc) return ( dateToCheck >= midnightYesterday && dateToCheck < midnightToday) } // returns true if the provided date/time takes place tomorrow lib.dateOccurrsTomorrow = function(dateToCheck){ var cal = Calendar.current var now = new Date() var midnightToday = cal.startOfDay(now) var dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 1 var midnightTomorrow = cal.dateFromDateComponents(dc) dc = cal.dateComponentsFromDate(midnightToday) dc.day = dc.day + 2 var dayAfterTomorrow = cal.dateFromDateComponents(dc) return (dateToCheck >= midnightTomorrow && dateToCheck < dayAfterTomorrow) } // returns true if the provided date/time takes place next week lib.dateOccursNextWeek = function(dateToCheck){ var fmatr = Formatter.Date.withStyle(Formatter.Date.Style.Short) var weekStart = fmatr.dateFromString('next week') var dc = new DateComponents() dc.day = 7 var followingWeek = Calendar.current.dateByAddingDateComponents(weekStart, dc) return (dateToCheck >= weekStart && dateToCheck < followingWeek) } // returns true if the provided date/time takes place this month lib.dateOccurrsThisMonth = function(dateToCheck){ var cal = Calendar.current var currentMonthIndex = cal.dateComponentsFromDate(new Date()).month var targetMonthIndex = cal.dateComponentsFromDate(dateToCheck).month return (targetMonthIndex === currentMonthIndex) } // returns true if the provided date/time takes place next month lib.dateOccurrsNextMonth = function(dateToCheck){ var cal = Calendar.current var dc = cal.dateComponentsFromDate(new Date()) dc.day = 1 dc.month = dc.month + 1 var nextMonth = cal.dateFromDateComponents(dc) var nextMonthIndex = cal.dateComponentsFromDate(nextMonth).month var targetMonthIndex = cal.dateComponentsFromDate(dateToCheck).month return (nextMonthIndex === targetMonthIndex) } // returns true if the provided date/time takes place on the provided target date lib.dateOccursOnTargetDate = function(dateToCheck, targetDate){ var cal = Calendar.current var targetDateStart = cal.startOfDay(targetDate) var dc = cal.dateComponentsFromDate(targetDateStart) dc.day = dc.day + 1 var dayAfterTargetDate = cal.dateFromDateComponents(dc) return ( dateToCheck >= targetDateStart && dateToCheck < dayAfterTargetDate) } lib.info = function(){ var libProps = Object.getOwnPropertyNames(lib) libProps.forEach((propName, index) => { if (index != 0){console.log(" ")} console.log("•", propName) var item = lib[propName] if (typeof item === "string"){ console.log(item) } else if (typeof item === "function"){ console.log(item.toString()) } else if (typeof item === "object"){ if(item instanceof Version){ console.log(item.versionString) } else if(item instanceof PlugIn){ console.log(item.identifier) } } }) } return lib; })();

Here’s an example script calling the library:

Call Date Comparison Library


var libFile = PlugIn.find("com.omni-automation.all.date-library") var lib = libFile.library("all-date-library") var date = new Date(new Date().setHours(25, 15, 0)) if (lib.dateOccurrsTomorrow(date)){console.log("Date occurs tomorrow!")}