that worked great until the days started getting darker and I didn’t want to continually change the formatting manually
so added a API call to get the days sunset/sunrise details (using jsonhelper to parse the return)
from http://api.sunrise-sunset.org
that returns the time info as UTC,
so in trying to do a conversion to local time, it gets kinda messy
am wondering if thee is a better way
it is my first attempt at writing a AppleScript so am sure there are other built in routines that I am missing
thanks
Darrin
set morningEarly to "Morning Early"
set morningLate to "Morning Late"
set afternoonEarly to "Afternoon Early"
set afternoonLate to "Afternoon Late"
set eveningEarly to "Evening Early"
set eveningLate to "Evening Late"
-- get current days details from API
tell application "JSON Helper"
set dayDetails to fetch JSON from "http://api.sunrise-sunset.org/json?lat=47.6768927&lng=-122.2059833&formatted=1"
set sunrise to sunrise of results of dayDetails as string
set sunset to sunset of results of dayDetails as string
log words of sunrise
set sunriseH to word 1 of sunrise
set sunriseM to word 2 of sunrise
if (word 4 of sunrise = "PM") then
set sunriseH to sunriseH + 12
end if
set sunriseH to sunriseH - 8
set sunriseToday to (sunriseH + sunriseM / 100)
log words of sunset
set sunsetH to word 1 of sunset
set sunsetM to word 2 of sunset
if (word 4 of sunset = "PM") then
set sunsetH to sunsetH + 12
end if
set sunsetH to sunsetH + 4
set sunsetToday to (sunsetH + sunsetM / 100)
end tell
-- get current hour
set h to hours of (current date)
set m to minutes of (current date)
set rightnow to (h + m / 100)
if (rightnow ≥ sunriseToday - 1 and rightnow < sunriseToday + 1) then
set periodOfDay to morningEarly
else if (rightnow ≥ sunriseToday + 1 and rightnow < 12) then
set periodOfDay to morningLate
else if (rightnow ≥ 12 and rightnow < 13) then
set periodOfDay to afternoonEarly
else if (rightnow ≥ 13 and rightnow < sunsetToday - 2) then
set periodOfDay to afternoonLate
else if (rightnow ≥ sunsetToday - 2 and rightnow < sunsetToday) then
set periodOfDay to eveningEarly
else if (rightnow ≥ sunsetToday or rightnow < sunriseToday - 1) then
set periodOfDay to eveningLate
end if
on getImageRight(folderName)
tell application "Finder"
return some file of folder ("Pictures:Wallpapers:right:Time of Day:" & folderName) of home as text
end tell
end getImageRight
on getImageLeft(folderName)
tell application "Finder"
return some file of folder ("Pictures:Wallpapers:left:Time of Day:" & folderName) of home as text
end tell
end getImageLeft
log periodOfDay
tell application "Finder"
try
set mainDisplayPicture to my getImageRight(periodOfDay)
tell application "System Events"
set theDesktops to a reference to every desktop
log (count theDesktops)
if ((count theDesktops) > 1) then
repeat with x from 2 to (count theDesktops)
set secondaryDisplayPicture to my getImageLeft(periodOfDay)
set picture of item x of the theDesktops to secondaryDisplayPicture
end repeat
end if
end tell
set desktop picture to mainDisplayPicture
end try
end tell
I would make a few changes so that it would be easier to adjust to user’s needs.
set morningEarly to "Morning Early"
set morningLate to "Morning Late"
set afternoonEarly to "Afternoon Early"
set afternoonLate to "Afternoon Late"
set eveningEarly to "Evening Early"
set eveningLate to "Evening Late"
set lat to 43.578 # was 47.6768927 # ADDED
set lng to 7.0545 # was -122.2059833 # ADDED
-- get current days details from API
tell application "JSON Helper"
set dayDetails to fetch JSON from "http://api.sunrise-sunset.org/json?lat=" & lat & "&lng=" & lng & "&formatted=1" # EDITED
# to be continued
I think this works in El Capitan or later. It assumes that the computer’s set up for the same time zone as the coordinates used:
use AppleScript version "2.5" -- Mac OS 10.11 (El Capitan) or later.
use framework "Foundation"
set morningEarly to "Morning Early"
set morningLate to "Morning Late"
set afternoonEarly to "Afternoon Early"
set afternoonLate to "Afternoon Late"
set eveningEarly to "Evening Early"
set eveningLate to "Evening Late"
set |⌘| to current application
-- Fetch and convert the JSONData and extract the sunset and sunrise strings (UTC times).
set downloadURL to |⌘|'s class "NSURL"'s URLWithString:("http://api.sunrise-sunset.org/json?lat=47.6768927&lng=-122.2059833&formatted=1")
set JSONData to |⌘|'s class "NSData"'s dataWithContentsOfURL:(downloadURL)
set dataAsDictionary to |⌘|'s class "NSJSONSerialization"'s JSONObjectWithData:(JSONData) options:(0) |error|:(missing value)
set sunsetTimeString to dataAsDictionary's valueForKeyPath:("results.sunset")
set sunriseTimeString to dataAsDictionary's valueForKeyPath:("results.sunrise")
-- Append the strings to the current UTC date.
set rightNow to |⌘|'s class "NSDate"'s |date|()
set UTCBaseDateString to rightNow's |description|()'s substringWithRange:({0, 11})
set sunsetDateString to (UTCBaseDateString's stringByAppendingString:(sunsetTimeString))'s stringByAppendingString:(" +0000")
set sunriseDateString to (UTCBaseDateString's stringByAppendingString:(sunriseTimeString))'s stringByAppendingString:(" +0000")
-- Create new UTC dates from the results and coerce to AppleScript dates. The results should be in the local time.
set dateFormatter to |⌘|'s class "NSDateFormatter"'s new()
tell dateFormatter to setDateFormat:("yyyy-MM-dd hh:mm:ss a z")
set sunset to (dateFormatter's dateFromString:(sunsetDateString)) as date
set sunrise to (dateFormatter's dateFromString:(sunriseDateString)) as date
-- Get the times in hours as reals.
set sunsetToday to (sunset's time) / hours
set sunriseToday to (sunrise's time) / hours
-- get current hour
set rightNow to ((rightNow as date)'s time) / hours
if (rightNow ≥ sunsetToday or rightNow < sunriseToday - 1) then
set periodOfDay to eveningLate
else if (rightNow < sunriseToday + 1) then
set periodOfDay to morningEarly
else if (rightNow < 12) then
set periodOfDay to morningLate
else if (rightNow < 13) then
set periodOfDay to afternoonEarly
else if (rightNow < sunsetToday - 2) then
set periodOfDay to afternoonLate
else
set periodOfDay to eveningEarly
end if
-- Rest of script here.
Edits: Original longitude correctly restored! " +0000" now properly in the sunrise and sunset date strings instead of the formatter string used to turn them into NSDates.
Edit: If it has to work in Yosemite as well, you could try replacing this section .
-- Create new UTC dates from the results and coerce to AppleScript dates. The results should be in the local time.
set dateFormatter to |⌘|'s class "NSDateFormatter"'s new()
tell dateFormatter to setDateFormat:("yyyy-MM-dd hh:mm:ss a z")
set sunset to (dateFormatter's dateFromString:(sunsetDateString)) as date
set sunrise to (dateFormatter's dateFromString:(sunriseDateString)) as date
-- Get the times in hours as reals.
set sunsetToday to (sunset's time) / hours
set sunriseToday to (sunrise's time) / hours
-- get current hour
set rightNow to ((rightNow as date)'s time) / hours
. with this:
-- Create new UTC dates from the results.
set dateFormatter to |⌘|'s class "NSDateFormatter"'s new()
tell dateFormatter to setDateFormat:("yyyy-MM-dd hh:mm:ss a z")
set sunsetDate to dateFormatter's dateFromString:(sunsetDateString)
set sunriseDate to dateFormatter's dateFromString:(sunriseDateString)
-- Get the local times in hours as reals.
set localCalendar to |⌘|'s class "NSCalendar"'s currentCalendar()
set HMFlags to (|⌘|'s NSHourCalendarUnit as integer) + (|⌘|'s NSMinuteCalendarUnit as integer)
tell (localCalendar's components:(HMFlags) fromDate:(sunsetDate)) to set sunsetToday to (its hour()) + (its minute()) / 60
tell (localCalendar's components:(HMFlags) fromDate:(sunriseDate)) to set sunriseToday to (its hour()) + (its minute()) / 60
tell (localCalendar's components:(HMFlags) fromDate:(rightNow)) to set rightNow to (its hour()) + (its minute()) / 60
Also, of course, change this .
use AppleScript version "2.5" -- Mac OS 10.11 (El Capitan) or later.
. to this .
use AppleScript version "2.4" -- Mac OS 10.10 (Yosemite) or later.
You could modify it to run under 10.10 (or 10.9 in a library) by modifying the latter parts something like this:
tell dateFormatter to setDateFormat:("yyyy-MM-dd hh:mm:ss a +0000")
set sunset to dateFormatter's dateFromString:(sunsetDateString)
set sunrise to dateFormatter's dateFromString:(sunriseDateString)
set rightNow to current application's NSDate's |date|()
set middayToday to current application's NSCalendar's currentCalendar()'s dateBySettingHour:12 minute:0 |second|:0 ofDate:rightNow options:0
set hoursAfterSunrise to (rightNow's timeIntervalSinceDate:sunrise) / hours
set hoursBeforeSunset to (sunset's timeIntervalSinceDate:rightNow) / hours
set hoursAfterMidday to (rightNow's timeIntervalSinceDate:middayToday) / hours
if (hoursBeforeSunset < 0 or hoursAfterSunrise < -1) then
set periodOfDay to eveningLate
else if (hoursAfterSunrise < 1) then
set periodOfDay to morningEarly
else if (hoursAfterMidday < 0) then
set periodOfDay to morningLate
else if (hoursAfterMidday < 1) then
set periodOfDay to afternoonEarly
else if (hoursBeforeSunset < 2) then
set periodOfDay to afternoonLate
else
set periodOfDay to eveningEarly
end if
Phew, Shane! Talking about turning the problem inside out!
I make it:
if (hoursBeforeSunset <= 0 or hoursAfterSunrise < -1) then
set periodOfDay to eveningLate
else if (hoursAfterSunrise < 1) then
set periodOfDay to morningEarly
else if (hoursAfterMidday < 0) then
set periodOfDay to morningLate
else if (hoursAfterMidday < 1) then
set periodOfDay to afternoonEarly
else if (hoursBeforeSunset > 2) then
set periodOfDay to afternoonLate
else
set periodOfDay to eveningEarly
end if
The times returned from the Web site are the UTC times for the local sunrise and sunset at the given coordinates. darrisden’s original script uses those times and he was asking how to convert them to local time. My version(s) and Shane’s variation transpose them to the time zone of the computer running the scripts. That’s the idea, anyway…
Looking through the code I posted, I see I restored the wrong longitude after testing with my own. I’ve now restored the original. Does it give you less worrying results now?
set lat to 43.578 # was 47.6768927 # ADDED
set lng to 7.0545 # was -122.2059833 # ADDED
-- get current days details from API
set |⌘| to current application
-- Fetch and convert the JSONData and extract the sunset and sunrise strings (UTC times).
set downloadURL to |⌘|'s class "NSURL"'s URLWithString:("http://api.sunrise-sunset.org/json?lat=" & lat & "&lng=" & lng & "&formatted=1")
The values returned have one hour offset from the correct ones - those which I may find in numerous web pages.
My understanding is that there is a problem with the time to GMT value which here is 3600 but I have no idea of which instruction must be edited to take that in account except using brute force to add one to : hoursBeforeSunset, hoursAfterSunrise and hoursAfterMidday
Looking in an alternate site I found slightly different values for lat and lng
set lat to 43.58056
set lng to 7.05389
You take the local date, drop its time component then concatenate it the returned sunsetTimeString and sunriseTimeString.
For you Englishman it’s OK
For me it’s wrong.
My understanding is that the correct scheme would be :
extract the values from the site:
sunsetTimeString = 3:57:37 PM*)
(*sunriseTimeString = 6:54:39 AM
calculate the localDate whose day is 12, month is 12, year is 2016
You get 2016-12-12 and append the strings getting :
2016-12-12 3:57:37 PM
2016-12-12 6:54:39 AM
For me it would be 2016-12-12 1:00:00
then add it the sunsetTime or the sunriseTime
so it would give
2016-12-12 4:57:37 PM
2016-12-12 7:54:39 AM
I guess that Shane which doesn’t live with a time to GMT equal to 0000 will be able to test what I describe easily.
According to my tests and Shane’s book, the descriptions of NSDates are always in GMT/UCT:
use framework "Foundation"
set now to current application's class "NSDate"'s |date|()
now's |description|() as text
--> "2016-12-12 18:45:53 +0000"
-- OK. GMT's in force anyway at the moment where I am, so:
set aBSTDate to date "Saturday 1 July 2017 at 00:00:00" -- A date in British Summer Time.
set aBSTNSDate to current application's class "NSDate"'s dateWithTimeInterval:(0.0) sinceDate:(aBSTDate)
set BSTNSDateDescription to aBSTNSDate's |description|() as text
--> "2017-06-30 23:00:00 +0000" -- Result in GMT.
It’s on that understanding that I used a |date|() description as the basis for the UCT sunrise and sunset dates. At the moment, I don’t know why you’re getting something different.
Edit: After a quick walk round the block, it’s occurred to me that the " +0000" should be in the date strings used to create the sunrise and sunset dates, not in the format string. It does make a difference. I’ll change it above.
It clearly make the difference between what is in the AppleScript dateString - here 20 as the hours value, and what is in the NSDate as string - here 19.
What I have found is that the times returned by api.sunrise-sunset.org don’t make any allowance for GMT offset. So in my case, depending on the time of day it will return the values for yesterday rather than today.
One more try. This should work for 10.10 and above, or 10.9 in a script library:
use AppleScript version "2.3"
use framework "Foundation"
set morningEarly to "Morning Early"
set morningLate to "Morning Late"
set afternoonEarly to "Afternoon Early"
set afternoonLate to "Afternoon Late"
set eveningEarly to "Evening Early"
set eveningLate to "Evening Late"
-- Fetch and convert the JSONData and extract the sunset and sunrise strings (ISO8601 format).
set downloadURL to current application's class "NSURL"'s URLWithString:("http://api.sunrise-sunset.org/json?lat=-37.814&lng=144.96332&formatted=0") -- change lat and lng to suit
set JSONData to current application's NSData's dataWithContentsOfURL:(downloadURL)
set dataAsDictionary to current application's NSJSONSerialization's JSONObjectWithData:(JSONData) options:(0) |error|:(missing value)
set sunsetTimeString to dataAsDictionary's valueForKeyPath:("results.sunset")
set sunriseTimeString to dataAsDictionary's valueForKeyPath:("results.sunrise")
set rightNow to current application's NSDate's |date|()
set theCal to current application's NSCalendar's currentCalendar()
-- make date formatter
set NSISO8601DateFormatter to current application's NSClassFromString("NSISO8601DateFormatter")
if NSISO8601DateFormatter is missing value then -- pre-10.12, so fall back to normal formatter
set dateFormatter to current application's NSDateFormatter's new()
dateFormatter's setLocale:(current application's NSLocale's localeWithLocaleIdentifier:"en_US_POSIX")
dateFormatter's setDateFormat:("yyyy-MM-dd'T'HH:mm:ssZZZZZ")
dateFormatter's setTimeZone:(current application's NSTimeZone's timeZoneForSecondsFromGMT:0)
else -- running 10.12
set dateFormatter to NSISO8601DateFormatter's new()
end if
-- convert date strings to dates
set sunset to dateFormatter's dateFromString:(sunsetTimeString)
set sunrise to dateFormatter's dateFromString:(sunriseTimeString)
-- calculate approximate current-day values if necessary
if (theCal's isDateInToday:sunset) as boolean is false then set sunset to sunset's dateByAddingTimeInterval:days
if (theCal's isDateInToday:sunrise) as boolean is false then set sunrise to sunrise's dateByAddingTimeInterval:days
set middayToday to theCal's dateBySettingHour:12 minute:0 |second|:0 ofDate:rightNow options:0
set hoursAfterSunrise to (rightNow's timeIntervalSinceDate:sunrise) / hours
set hoursBeforeSunset to (sunset's timeIntervalSinceDate:rightNow) / hours
set hoursAfterMidday to (rightNow's timeIntervalSinceDate:middayToday) / hours
if (hoursBeforeSunset ≤ 0 or hoursAfterSunrise < -1) then
set periodOfDay to eveningLate
else if (hoursAfterSunrise < 1) then
set periodOfDay to morningEarly
else if (hoursAfterMidday < 0) then
set periodOfDay to morningLate
else if (hoursAfterMidday < 1) then
set periodOfDay to afternoonEarly
else if (hoursBeforeSunset > 2) then
set periodOfDay to afternoonLate
else
set periodOfDay to eveningEarly
end if
-- Rest of script here.
But if you’re a way off GMT and the equator, the fact that the sunrise and sunset values returned might be for a different day makes them potentially pretty inaccurate.
I made a little change - already described - to make adjustments to latitude and longitude easier.
Doing that I discovered an interesting difference. Nigel’ and the original poster use “formatted=1” at the end of the instruction defining downloadURL.
You use “formatted=0”.
When I simply pasted the instructions borrowed from the ‘old’ versions :
set lat to 43.58056 # was 47.6768927 # ADDED
set lng to 7.05389 # was -122.2059833 # ADDED
-- get current days details from API
set |⌘| to current application
-- Fetch and convert the JSONData and extract the sunset and sunrise strings (UTC times).
set downloadURL to |⌘|'s class "NSURL"'s URLWithString:("http://api.sunrise-sunset.org/json?lat=" & lat & "&lng=" & lng & "&formatted=1")
The strings grabbed from the web were:
(sunsetTimeString = 3:57:48 PM)
(sunriseTimeString = 6:55:25 AM)
With your setting (formatted=0) they are :
(sunsetTimeString = 2016-12-13T15:57:48+00:00)
(sunriseTimeString = 2016-12-13T06:55:25+00:00)
so the trickery used by Nigel to build date-time strings is no longer needed.
If I understand well, it’s your use of NSISO8601DateFormatter which makes the difference.
I will have to make tests under 10.10 or 10.11 because I am wondering what would be the impact of localeWithLocaleIdentifier:“en_US_POSIX” on my system running in French.
Under 10.11 there is no visible change. The script works exactly well as it does under 10.12.1.