Script Purpose The script below uses an App called Pashua to display a custom dialog box that returns multiple inputs. These inputs are then used to create a new Calendar event.

enter image description here

The Issue The issue I am experiencing is that the date is returned in YYYY-MM-DD format. When the date is entered in MM/DD/YYYY format, the event is created with no problem.

How do I convert the date properly?

These are the lines of code that need help:

            set sDate to (sDate of theResult)
            --- Returns: 2018-12-12

            set sTime to (sTime of theResult)
            --- Returns: 10:00 AM

            set eDate to (eDate of theResult)
            --- Returns: 2018-12-12

            set eTime to (eTime of theResult)
            --- Returns: 11:00 AM

            set eStart to date of (sDate & space & sTime)
            --- Error: Can’t get date of 2018-12-12 10:00 AM

            set eEnd to date of (eDate & space & eTime)
            --- Error: Can’t get date of 2018-12-12 11:00 AM

This is the error that appears:

enter image description here

Entire Code:

 -- Get the path to the folder containing this script
 tell application "Finder"
set thisFolder to (container of (path to me)) as string
if "Pashua:Pashua.app:" exists then
    -- Looks like the Pashua disk image is mounted. Run from there.
    set customLocation to "⁨/Users/dnaab/Applications/"
    -- Search for Pashua in the standard locations
    set customLocation to "/Users/dnaab/Applications/"
end if
 end tell

    set thePath to alias (thisFolder & "Pashua.scpt")
    set pashuaBinding to load script thePath

tell pashuaBinding
    -- Display the dialog

        set pashuaLocation to getPashuaPath(customLocation)
        set dialogConfiguration to my getDialogConfiguration(pashuaLocation)
        set theResult to showDialog(dialogConfiguration, customLocation)

        -- Display the result. The record keys ("... of theResult") are defined in the
        -- dialog configuration string.
        if {} = theResult then
            display alert "Empty return value" message "It looks like Pashua had some problems using the window configuration." as warning
        else if cb of theResult is not "1" then

            set eCalendar to "Calendar"

            set eSummary to (eSummary of theResult)

            set eURL to (eURL of theResult)

            set eDescription to (eDescription of theResult)

            set sDate to (sDate of theResult)

            set sTime to (sTime of theResult)

            set eDate to (eDate of theResult)

            set eTime to (eTime of theResult)

            set sDate to date of (sDate & space & sTime)

            set eDate to date of (eDate & space & eTime)

            display dialog sDate buttons {"Cancel"} default button 1

            tell application "Calendar"
                tell calendar eCalendar
                    make new event with properties {summary:eSummary, start date:eStart, end date:eDate, url:eURL}
                end tell
            end tell
            -- The cancelbutton (named "cb" in the config string) was pressed

            display dialog "The dialog was closed without submitting the values"

        end if
    on error errorMessage
        display alert "An error occurred" message errorMessage as warning
    end try
end tell

 on error errStr number errorNumber
display dialog errStr
 end try

 -- Returns the configuration string for an example dialog
 on getDialogConfiguration(pashuaLocation)

if pashuaLocation is not "" then
    set img to "img.type = image
          img.x = 250
          img.y = 260
          img.maxwidth = 60
          img.tooltip = This is an element of type “image”
          img.path = /Applications/Calendar.app/Contents/Resources/App.icns"
    set img to ""
end if

return "

 # Set window title
 *.title = New iCal Event

 # Event Summary
 eSummary.type = textfield
 eSummary.label = Event Summary
 eSummary.default = Calendar
 eSummary.width = 310
 eSummary.x = 1
 eSummary.y = 310

 # Add Start Date
 sDate.type = date
 sDate.label = Event Start Date
 sDate.default = today
 sDate.textual = 1
 sDate.x = 1
 sDate.y = 255

 # Add Start Time
 sTime.type = date
 sTime.label = Event Start Time
 sTime.default = today
 sTime.time = 1
 sTime.date = 0
 sTime.textual = 1
 sTime.width =70
 sTime.x = 110
 sTime.y = 255

 # Add End Date
 eDate.type = date
 eDate.label = Event Start Date
 eDate.default = today
 eDate.textual = 1
 eDate.x = 1
 eDate.y = 200

 # Add End Time
 eTime.type = textfield
 eTime.label = Event End Time
 eTime.width = 70
 eTime.x = 110
 eTime.y = 200

 # Add Calendar
 eURL.type = textfield
 eURL.label = URL
 eURL.default = message://
 eURL.width = 310
 eURL.x = 1
 eURL.y = 150

 # Description
 eDescription.type = textbox
 eDescription.label = Description
 eDescription.width = 310
 eDescription.x = 1
 eDescription.y =70

 # Add a cancel button with default label
 db.type = defaultbutton
 cb.type = cancelbutton
 end getDialogConfiguration
  • What code is returning the date in YYYY-MM-DD format? Please include the relevant code so we can test for ourselves. – user3439894 Dec 13 '18 at 2:27
  • I added the code in. – David Naab Dec 13 '18 at 2:38
  • wow, nice work, and now you just published it – Ruskes Dec 13 '18 at 4:27

AppleScript dates are notoriously picky about format. They take their cue from your own system date & time settings, so even if I got a script to work properly on my system utilising a specific date & time format, it would probably not work on your system unless you happened to have the same macOS settings.

Therefore, the best way to deal with AppleScript date objects is to create them from scratch using day, month, year and time components. That way, they work consistently across all systems, but, most importantly, allow you to manipulate them in your own script without unexpected errors.

Add the following handler to the bottom of your script. It will give you the means to create an AppleScript date object by supplying to it the day, month and year, and (optionally) the hour, minute and second components:

to makeASDate given year:y as integer ¬
    , month:m ¬
    , day:d as integer ¬
    , hours:h as integer : 0 ¬
    , minutes:min as integer : 0 ¬
    , seconds:s as integer : 0
    local y, m, d, h, min, s

    tell the (current date) to set ¬
        [ASDate, year, its month, day, time] to ¬
        [it, y, m, d, h * hours + min * minutes + s]

end makeASDate

To use it, simply call the handler like so:

makeASDate given year:2018, month:January, day:23
    --> date "Tuesday, 23 January 2018 at 00:00:00"


makeASDate given year:2018, month:1, day:23, hours:14, minutes:30, seconds:00
    --> date "Tuesday, 23 January 2018 at 14:30:00"

Now, your next task is to extract the year, month a day components from your variables in order to pass them to the makeASDate handler. The easiest way to do this is by splitting your date/time variables into words. For example, with your start date and time:

set [sy, sm, sd] to words of (sDate of theResult)
    --> {"2018", "12", "12"}

set [sh, smin, AMPM] to words of (sTime of theResult)
    --> {"10", "00", "AM"}
if AMPM = "PM" then set sh to sh + 12

and similarly with your end times. I've illustrated a quick test with your time variable to determine whether or not it is AM or PM, and changed the value of the hour component accordingly (the makeASDate handler uses the 24-hour clock). You'll have to do another test with your date variable to determine what format the date is in: dd/mm/yyyy or yyyy-mm-dd, which might be as easy as:

if (sDate of theResult) contains "-" then
    set [sy, sm, sd] to words of (sDate of theResult)
else if (sDate of theResult) contains "/" then
    set [sd, sm, sy] to words of (sDate of theResult)
end if

What @CJK said -- trying to cook up a date string is a losing battle because it depends on user settings, use the components instead -- except that their handler does not always work. If you run it on a day numbered more than the number of days in the month of the input, the result will be the month after the one you asked for. For example, if you ask for "month:2 day:15" on January 31, you'll get March 15, not February 15. There are three factors involved, none of which seem to be explicitly documented:

  1. AppleScript date objects are stored as an absolute point in time, not a set of components. (Well, mostly absolute: for historical reasons, they're relative to the current time zone.) Components are synthesized on demand from that point in time using the current calendar.

  2. Setting a component, such as set month of d to April, means it decomposes the date into components, changes the one component, and then composes them back into a point in time. What happens if one of the components is out of range is not specified, but in practice, an out-of-range day will wrap to some following month. Consider, continuing the example, set day of d to 41. April 41st is, logically, 11 days after the last day of April, April 30, so you get May 11.

  3. Even when using pattern-set syntax set {x, y} to {1, 2}, the assignments happen one at a time. (The documentation https://developer.apple.com/library/archive/documentation/AppleScript/Conceptual/AppleScriptLangGuide/reference/ASLR_cmds.html#//apple_ref/doc/uid/TP40000983-CH216-SW52 describes them as "simultaneous", since set {x, y} to {y, x} does in fact exchange x and y, but that isn't quite right: what really happens is that it evaluates all the expressions first, storing the results in implicit temporaries, then assigns the temporaries to the variables one at a time. All the evaluations happen before all the assignments, but the order is otherwise unspecified.)

So, say you run this on January 31, 2020:

makeASDate given year:2018, month:2, day:15

What happens is:

  1. set ASDate to (current date). ASDate is January 31, 2020 at whatever the current time is.
  2. set year of ASDate to 2018. ASDate is now January 31, 2018.
  3. set month of ASDate to 2. The components specify February 31, 2018, which doesn't exist, so it wraps: d is now March 3, 2018.
  4. set day of ASDate to 15. d is now March 15, 2018, not February 15 like you asked for.

There are two ways around this: one is to first set the day and month in that order to 1 first, then apply the input parameters. The other is to use a fixed date with low-numbered month and day, say "1/1/1904", instead of current date as the starting point. A corrected handler might look like this:

to makeASDate given year:y as integer ¬
    , month:m ¬
    , day:d as integer ¬
    , hours:h as integer : 0 ¬
    , minutes:min as integer : 0 ¬
    , seconds:s as integer : 0
    local y, m, d, h, min, s, p

    set p to "1/1/1904"
    tell the (date p) to set ¬
        {ASDate, year, its month, day, time} to ¬
        {it, y, m, d, h * hours + min * minutes + s}

end makeASDate

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .