HAPPY NEW YEAR

With the New Year, thoughts may tend to turn to dates; that is, days of the calendar.

This post is designed for new users who may be struggling when it comes to working with AppleScript’s date object. But “those in the know” may also find some new information tucked away in the examples below.

NOTE: In some of the sample scripts we have used the line return character (¬) to shorten some extra long statements into two lines. Make sure you remove these characters and make the statement one line.

GETTING RESULTS

New to AppleScript? The AppleScript Editor allows you to see the result of a procedure in its Result window. For example, in the editor enter the following and run the script (Command+R)

current date

The result, a date object, will display in the Result window at the bottom.

To get the string value of the date object, coerce it to a string:

(current date) as string

Note: If you don’t put the parentheses around current date, the script compiler will gladly add them for you when you compile (Command+K).

How the date string is formatted depends on the settings for the computer’s System Preferences (in the Language & Region Panel). The way the date elements are arranged in the string may or may not be what is wanted for the purpose of the script. For this reason, the date object has a number of properties which can be used to format the string value for the date object. Try the following:

set dateObj to (current date)
set theMonth to month of dateObj

Similarly, you can get the weekday, date and year for the dateObject. For the second statement in the above, substitute each of the following and test.

set wDay to weekday of dateObj
set theDay to day of dateObj
set theYear to year of dateObj

The value returned for the month and weekday, although they appear to be strings (literal text), are constants. Notice there are no quotes around the month and weekday results. These constants can be coerced into strings as needed. Try the following:

set dateObj to (current date)
set monthStr to month of dateObj as string

Notice that the result (monthStr variable) is the name of the month now with quotation marks. Using this, we can put the results together (concatenate) to get today’s date in the format needed.

What’s the Date?

set dateObj to (current date)
set monthStr to month of dateObj as string
set theDay to day of dateObj
set theYear to year of dateObj
set dateStr to monthStr & " " & theDay & ", " & theYear
dateStr

On the other hand (depending on the settings for the computer’s System Preferences Language & Region Panel), the following may give you just what is needed for your date string:

set dayStr  to  date string of (current date)

Date Stamp

Suppose you want a script to show the date as numbers instead of text. The constants for month and weekday can now be coerced to a number. This is only possible in later versions of AppleScript (added in Panther).

set dateObj to (current date)
set theResult to month of dateObj as number

Instead of the name of the month, you now get the index of the month.

Prior to Panther, a script would have to repeat through a list of months to get the index of the month from the list:

set monthList to {January, February, March, April, May, June, July, August, September, October, November, December}
set dateObj to (current date)
set monthEnum to month of dateObj
repeat with i from 1 to length of monthList
   if item i of monthList = monthEnum then
       exit repeat
    end if
end repeat
i

(Don’t forget to place the variable i at the end to get the result for the month.)
Thank goodness for coercion. (You still might need to use the old repeat with/exit repeat/end repeat procedure if you are not sure the system that the script will be running on.)

Similarly the weekday can be returned as a number (in versions from Panther up):

set wDay to weekday of (current date) as number

Date Stamp

With the month constant returned as a number you might think you could use the following to create a date stamp in the format MMDDYYYY

set dateObj to (current date)
set theMonth to month of dateObj as number
set theDay to day of dateObj
set theYear to year of dateObj
set dateStamp to "" & theMonth & theDay & theYear
dateStamp

The problem is that the value for theDay and theMonth in the above can be one or two digits. To make sure that the value for the day and month is always a string having two digits (a zero for the first if less than 10), you could have the script test to see if the value for the day and month are less than 10 and add a zero as needed. The following, however, is a way this can be done with string concatenation. See how it works with the following simple test:

set theDay to 5
set dayStr to text -1 thru -2 of ("0" & theDay)

Now try the above with the value of 15 for the value of theDay.

Substituting this in the Date Stamp script above, the result will always have two digits for the day and the month.

set dateObj to (current date)
set theMonth to text -1 thru -2 of ("0" & (month of dateObj as number))
set theDay to text -1 thru -2 of ("0" & day of dateObj)
set theYear to year of dateObj
set dateStamp to "" & theMonth & theDay & theYear
dateStamp

On the other hand (depending on the settings in System Preferences in the computer’s Language & Region Panel), the following may give you just what you want for a dateStamp:

set shortDate to short date string of (current date)

FROM STRING TO DATE

Given a string in a format that it understands, AppleScript can convert a written (string) date into a date object.

set thisDay to date "January 1, 2019" 

Notice what the compiler does to your string when you compile. If you don’t provide a time, the default values for hour, minute, and second are added. The reason is so that the date object can return date and time results with one second accuracy. (See Time below.)

set dAnswer to "01/01/2019"
try
   set userEntry to display dialog ¬
"Enter your birthday as MM/DD/YYYY" default answer dAnswer
   set userDate to text returned of userEntry
   set bDay to date userDate
   set wDay to weekday of bDay
   display alert ("You were born on " & wDay)
on error errStr
   display alert ("Error: " & errStr)
end try

You may want to try this with different string formats to see what AppleScript considers to be a valid date string.

TIME

One big reason for converting a string date value to a date object is for calculating time and date differences.

Similar to constants for month and weekday, the date object has constants for properties dealing with time. These are all expressed as numerical values in seconds:

  • minutes is equal to 60
  • hours is equal to 3600
  • days is equal to 86400
  • and weeks is equal to 604800

This makes it possible to calculate time or day differences as in the following examples:

To see how many days are in the month of February for any given year, you can use:

Days in February

set theYear to 2019
set nextDay to date ("March 1 " & theYear)
set theDay to date ("February 1 " & theYear)
set daysBetween to (nextDay - theDay) div days
display alert ("There are " & daysBetween & ¬
 " days in February in " & theYear)

We can use date arithmetic to calculate the number of years, days, hours, minutes, or even seconds between two different dates.

How Old Are You?

set dAnswer to "01/01/2019"
try
   set userEntry to display dialog ¬
 "Enter your birthday as MM/DD/YYYY" default answer dAnswer
   set userDate to text returned of userEntry
   set bDay to date userDate
   set thisDay to (current date)
   set dateDif to (thisDay - bDay) div days
   display alert ("You are " & dateDif & " days old")
on error errStr
   display alert ("Error " & errStr)
end try

To break a date result down into hours, minutes, or seconds, you would need to provide the time. For example, to see how old you are in minutes try the following:

set thePrompt to ¬
"Enter your birth date and time as MM/DD/YYYY hh:mm:ss am/pm"
set dAnswer to "11/02/1970 12:30:00 pm"
try 
   set userEntry to display dialog thePrompt default answer dAnswer
   set userDate to text returned of userEntry
   set bDay to date userDate
   set thisDay to (current date)
   set dateDif to (thisDay - bDay) div minutes
   display alert ("You are " & dateDif & " minutes old")
on error errStr
   display alert ("Error " & errStr)
end try

You really didn’t want to know this, did you?

Old Files

A more practical application might be to go through a folder to get a count of files older than a number of days old. For this you can use the method comes before.

set numDays to 90 --number of days before file is considered old
set thePrompt to "Choose folder to sample"
set theFolder to choose folder with prompt thePrompt
set oldDate to (current date) - (numDays * days)
tell application "Finder"
   set theCounter to count of (files of folder theFolder whose modification ¬
date comes before oldDate)
end tell
display alert ("You have " & theCounter & " files in the folder older than " ¬
 & numDays & " days.")

To keep the script simple we did not trap for the user error when cancelling out of a choose dialog. Practice using try/on error/end try to trap this error. Be careful with this script as you could end up with a script that takes a while to run depending on number of files in the folder chosen.

And speaking of how long it takes to run a script, you might want to get the current date (and time) when you start a script to see how long it takes for the script to run. Try modifying the OldFiles script above to return not only how many files in the folder are “old” but also how long it takes for the script to run.

set beginDate to (current date)
set numDays to 90 --number of days before file is considered old
set thePrompt to "Choose folder to sample"
set theFolder to choose folder with prompt thePrompt
set oldDate to (current date) - (numDays * days)
tell application "Finder"
    set theCounter to count of (files of folder theFolder whose modification ¬
date comes before oldDate)
end tell
set endDate to (current date)
display alert ("You have " & theCounter & " files in the folder older ¬
than " & numDays & " days.") giving up after 3
set dateDif to endDate - beginDate
display alert ("It took " & dateDif & " seconds to parse this folder")

TIME IN A BOTTLE

If I could put time in a bottle… Notice that this blog post is still in the 2018 Blogs folder. Given time, it will make it to a new 2019 Blog folder.

ONWARD AND UPWARD

Now that you know how to see how old a file is, think of the many ways that you could use a script to manage files: move old files to the trash or to another folder, or just get a list of files that you need to examine. Sounds like a good topic for a future blog. Keep posted.

See you next week when there are no holidays…

Disclaimer:
Scripts provided are for demonstration and educational purposes. No representation is made as to their accuracy or completeness. Readers are advised to use the code at their own risk.