After some experimentation with changing my computer’s time zone, it appears that, while Numbers still displays my original dates in the GUI, the dates it returns to AppleScript are what the local date/times would be if those in the table were GMT. (I this is accidental rather than deliberate.) So as Yvan says, the proper correction is to transpose the returned date to GMT, not just to zap its time. The ‘time to GMT’ function is probably not suitable here, as it returns the computer’s time zone offset at the time the script’s run, which may not be right for the date under examination.
The following’s a bit Heath Robinson, but it works. Someone with a better knowledge of shell script functions than my own may be able to come up something better. The line at the bottom calls the process. Your script has to provide the date from Numbers.
(* Convert an ISO-format date string to an AppleScript date. *)
on isotToDate(isot)
set n to (text 1 thru 8 of isot) as integer
set ASDate to (current date)
tell ASDate to set {day, year, its month, day} to {1, n div 10000, n mod 10000 div 100, n mod 100}
if ((count isot) > 8) then
set n to (text 10 thru 15 of isot) as integer
set ASDate's time to n div 10000 * hours + n mod 10000 div 100 * minutes + n mod 100
end if
return ASDate
end isotToDate
(* Transpose an AppleScript date/time from the given time zone to GMT. *)
on TZtoGMT(TZDate, TZ)
-- The difference between TZDate when it's local and the GMT date we want is usually
-- the same as the difference between the local date when TZDate is GMT and TZDate itself .
set GMTDate to TZDate - (GMTtoTZ(TZDate, TZ) - TZDate)
-- . but not around the time the clocks go forward. If the GMT obtained doesn't reciprocate to TZDate,
-- shift to a nearby local date where the above DOES work, get a new GMT, unshift it by the same amount.
set testDate to GMTtoTZ(GMTDate, TZ)
if (testDate is not TZDate) then
if (GMTDate > testDate) then -- "Clocks forward" is towards GMT.
set shift to GMTDate - testDate
else -- "Clocks forward" is away from GMT.
set shift to -days
end if
set nearbyDate to TZDate + shift
set GMTDate to nearbyDate - (GMTtoTZ(nearbyDate, TZ) - nearbyDate) - shift
end if
return GMTDate
end TZtoGMT
(* Transpose an AppleScript date/time from GMT to the given time zone. *)
on GMTtoTZ(GMTDate, TZ)
-- Subtract date "Thursday 1 January 1970 00:00:00" from the GMT date. Result in seconds, as text.
copy GMTDate to date19700101
tell date19700101 to set {year, its month, day, time} to {1970, 1, 1, 0}
set eraTime to (GMTDate - date19700101)
if (eraTime > 99999999) then
set eraTime to (eraTime div 100000000 as text) & text 2 thru 9 of (100000000 + eraTime mod 100000000 as integer as text)
else if (eraTime < -99999999) then
set eraTime to (eraTime div 100000000 as text) & text 3 thru 10 of (-100000000 + eraTime mod 100000000 as integer as text)
else
set eraTime to eraTime as text
end if
return isotToDate(do shell script ("TZ='" & TZ & "' /bin/date -r " & eraTime & " +%Y%m%dT%H%M%S"))
end GMTtoTZ
set myTimeZone to (do shell script ("/usr/bin/perl -le 'print( readlink(\"/etc/localtime\") =~m{zoneinfo/(.*)} )' ")) -- Perl code by Mark J. Reed.
TZtoGMT(dateReturnedByNumbers, myTimeZone)
Edit: Yvan’s pointed out to me privately that my original method for converting the era time to text in the GMTtoTZ() handler didn’t work on systems which use commas for decimal points. I’ve now rewritten that section to split large “E” numbers arithmetically rather than textually, which incidentally makes it more efficient.