Date objects with far-future or BC date values

The ‘year’ property of an AppleScript date object can only directly be set to an integer value in the range 0 to 32767, which is good enough for most of us! But using AppleScript’s date arithmetic, it’s possible to create functional date objects with year values way outside the nominal limits: from 285,424,781 BC at one end of the range to 285,428,684 AD at the other. (Actually, it’s possible to go right up to 536,870,911 before the system complains, but the times in the years after 285,428,684 increasingly become rounded to even-numbered seconds.)

By “functional date objects”, I mean date objects whose numeric and token values are all correct and which give the correct results in arithmetic operations. Date and time strings and coercions to text have to be ignored here as they may or may not be correct.

The method here is the simple one of starting from a date whose year can be set directly and adding or subtracting an appropriate amount. It makes use of the fact that the Gregorian cycle of leap years repeats every 400 years. This means that wherever one starts in the cycle, 400 years is 365 * 400 + 97 days ” or 1.26227808E+10 seconds. If we pick a start date that’s a multiple of 400 years from the target date, we don’t need to worry about how many leap days there are between the two. For an AD target year, the year of the start date is calculated as the target year mod 400. For a BC target year, the start date still needs to be an AD one and the calculation goes the other way:

on makeDate from inputDate for targetYear under theEra
	copy inputDate to startDate -- To preserve the passed date outside the handler.
	
	if (theEra is "AD") then
		set startDate's year to targetYear mod 400
		set targetDate to startDate + targetYear div 400 * 1.26227808E+10
	else
		set startDate's year to 401 - targetYear mod 400
		set targetDate to startDate - (targetYear div 400 + 1) * 1.26227808E+10
		-- Or: set targetDate to startDate - (result + targetYear) div 400 * 1.26227808E+10
	end if
	
	return targetDate
end makeDate

makeDate from (current date) for 285428684 under "AD"
result's {weekday, year, month, day, hours, minutes, seconds}

makeDate from (current date) for 44 under "BC"
result's {weekday, year, month, day, hours, minutes, seconds}
-- Note that with a "BC" input, the 'year' returned from the resulting date is the "astronomical" form,
-- that is, the negative of (BC year number - 1)