Your prescription for increased productivity and profitability
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.
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.
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)
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
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)
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.
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:
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:
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.
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?
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")
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.
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.