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:
- 2d, –3w, 1h, 1y1m, and so on • Relative dates and times put the date at a certain amount of time from right now. Negative numbers represent times in the past.
- 2 days, –3 weeks, 1 hour, 1 year 1 month, and so on • You can use the full names of units too.
- yesterday, tomorrow, tonight, next thursday, last month, this friday, and so on • You can refer to relative dates using common words. “This”, “next”, and “last” have specific meanings: this friday always means the Friday in this week, next friday always means the Friday in the next week, and last friday always means the Friday in last week, regardless of what day today is. Other units work in the same way.
- september, fri, 2019, and so on • If you enter the name of a specific time period, the date will be at its beginning. So september means September first.
- 5/23/08 10a, 9.30.09 2:00 PM, and so on • You can use the short date format as defined in your Language & Region system preferences.
- 2w sat, 4d @ 5p, mon 6a, aug 6 tue 5p, and so on • Mix the available formats however you like.
- now, 9, 14:00, tom, and so on • Omni’s date parser makes its best guess at things like bare numbers, times, and word fragments.
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
new DateComponents() → (DateComponents) • Creates a new instance of the DateComponents class.
Instance Properties
The properties of an instance of the DateComponents class:
date (Date or null) • The date object of the component
day (Number or null) • The number of days in the component
era (Number or null) • The number of eras in the component
hour (Number or null) • The number of hours in the component
minute (Number or null) • The number of minutes in the component
month (Number or null) • The number of months in the component
nanosecond (Number or null) • The number of nanoseconds in the component
second (Number or null) • The number of seconds in the component
timeZone (TimeZone or null) • The time zone of the component
year (Number or null) • The year of the component
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)
}
}
})
}

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!")}