A Timestamp Library for storing dates/times as strings

Hello.

I swear I haven’t seen it here, so I post it, this is a little set of routines I have made, that I am particularily happy with, for several purposes: For storing dates and querying databasees for dates less than or greater than, and it blends well with regular scripts, because with it, you can store dates as text. (It contains conversion handlers between AS Date objects and timestamp.

There is an example handler that uses the TimeStampLib below.


# Ver 2.1 Reinforced other handlers.
# Ver 2. After suggestions by StefanK
# TimeStampLib
# Timestamps are good for a lot of things.
# one thing is for querying and getting dates from
# a database events database.
# Another thing is for storing dates in scripts that
# may work without recompiling.

script TimeStampLib
	
	to timestampcompare(aTimeStamp, anotherTimeStamp)
		considering numeric strings
			if aTimeStamp as text < anotherTimeStamp then
				return -1
			else if aTimeStamp = anotherTimeStamp then
				return 0
			else
				return 1
			end if
		end considering
	end timestampcompare
	
	to defineTimeStamp(YR, mnth, dy, hr, min, sec)
		return ("" & YR & "." & mnth & "." & dy & " " & hr & ":" & min & ":" & sec)
	end defineTimeStamp
	
	to makeTimeStamp from anASDate
		tell (anASDate)
			# yyyy.mm.dd hh:mm:ss
			return ((((year of it as text) & "." & ((month of it as integer) as text) & "." & ¬
				day of it as text) & " " & hours of it as text) & ":" & minutes of it as text) & ":" & ¬
				seconds of it as text
		end tell
	end makeTimeStamp
	
	# Thanks to StefanK Minutes and seconds, or the lack thereof
	# is optional.
	to makeASDate from aTimeStamp -- format y.m.d H:M:S
		local TID, datePortion, timePortion, YR, MT, dy, l, hrs, min, sec, probe, cur_date
		set {TID, text item delimiters} to {text item delimiters, space}
		set {datePortion, timePortion} to text items of aTimeStamp
		set text item delimiters to "."
		try
			set {YR, MT, dy} to text items of datePortion
		on error
			set text item delimiters to TID
			error "makeAsDate: The date isn't anywhere near valid (y.m.d)" number 4000
		end try
		set text item delimiters to ":"
		tell (text items of timePortion)
			set l to length of it
			if l is 3 then
				set {hrs, min, sec} to it
			else if l is 2 then
				set {hrs, min} to it
				set sec to 0
			else
				set hrs to it
				set {min, sec} to {0, 0}
			end if
		end tell
		set text item delimiters to TID
		try
			set probe to YR + MT + dy + hrs + min + sec
		on error
			error "makeAsDate: The date isn't anywhere near valid numbers only! (y.m.d h(:min:sec))" number 4000
		end try
		tell (current date) to set {day, year, its month, day, its hours, its minutes, its seconds, cur_date} to {1, YR, MT, dy, hrs, min, sec, it}
		return cur_date
	end makeASDate
	
	to splitInTwo for aTimeStamp
		local tids, theList
		tell (a reference to AppleScript's text item delimiters)
			set {tids, its contents} to {its contents, " "}
			set theList to text items of aTimeStamp
			set its contents to tids
			return theList
		end tell
	end splitInTwo
	
	to ymdTriple from aSplitTimeStamp
		local tids, theList, probe
		tell (a reference to AppleScript's text item delimiters)
			set {tids, its contents} to {its contents, "."}
			set theList to text items of aSplitTimeStamp
			set its contents to tids
		end tell
		if lenght of theList is 3 then
			tell (theList)
				try
					set probe to (item 1 of it) + (item 2 of it) + (item 3 of it)
					return {item 1 of it, item 2 of it, item 3 of it}
				on error
					error "ymdTriple: There is no date consisting of (y.m.d) numbers here" number 4000
				end try
				# year, month, day
			end tell
		else
			error "ymdTriple: The string that should contain 3  is bad." number 4001
		end if
	end ymdTriple
	
	to hmsTriple from aSplitTimeStamp
		local tids, theList, probe
		tell (a reference to AppleScript's text item delimiters)
			set {tids, its contents} to {its contents, ":"}
			set theList to text items of aSplitTimeStamp
			set its contents to tids
		end tell
		if length of theList is 2 then
			tell (theList)
				try
					set probe to (item 1 of it) + (item 2 of it)
					return {item 1 of it, item 2 of it, 0}
				on error
					error "hmsTriple: There is an invalid number here." number 4000
				end try
				
				# hours, minutes, seconds
			end tell
		else if length of theList is 3 then
			tell (theList)
				try
					set probe to (item 1 of it) + (item 2 of it) + (item 3 of it)
					return {item 1 of it, item 2 of it, item 3 of it}
				on error
					error "hmsTriple: There is an invalid number here." number 4000
				end try
				
				# hours, minutes, seconds
			end tell
		else
			error "hmsTriple: The string containing 3 or 2 numbers is bad." number 4001
		end if
	end hmsTriple
	
end script

Here is an example, not wired up with the library.

to getVernalEquinox for aTimeStamp
	
	set vernalEquinoxes to reverse of ¬
		{¬
			"2010.3.20 17:32", ¬
			"2011.3.20 23:21", ¬
			"2012.3.20 05:14", ¬
			"2013.3.20 11:02", ¬
			"2014.3.20 16:57", ¬
			"2015.3.20 22:45", ¬
			"2016.3.20 04:30", ¬
			"2017.3.20 10:28", ¬
			"2018.3.20 16:15", ¬
			"2019.3.20 21:58", ¬
			"2020.3.20 03:50"}
	
	set found to false
	repeat with aVernalEquinox in vernalEquinoxes
		tell (aVernalEquinox)
			if my timestampcompare(it, aTimeStamp) < 0 then
				set vernaEquinoxTimeStamp to it
				set found to true
				exit repeat
			end if
		end tell
	end repeat
	
	if not found then error "Too new data, but probably something utterly wrong!" number 6999
	return vernalEquinoxTimestamp
end getVernalEquinox

Hello.

I added a missing handler, that I have stolen from Nigel Garvey: set_date_long, but with the name changed to _set_date_long, as to avoid confusion with that handler if you use it somehwhere else, from a dateLib for instance. (It is much easier to work with script libraries, if they are independent units.)

this might be faster and easier to create an AS date from a given text string with a specific format


to makeASDate from aTimeStamp -- format y.m.d H:M:S
	set {TID, text item delimiters} to {text item delimiters, space}
	set {datePortion, timePortion} to text items of aTimeStamp
	set text item delimiters to "."
	set {yr, mt, dy} to text items of datePortion
	set text item delimiters to ":"
	set {hrs, min, sec} to text items of timePortion
	set text item delimiters to TID
	tell (current date) to set {day, year, its month, day, its hours, its minutes, its seconds, cur_date} to {1, yr, mt, dy, hrs, min, sec, it}
	return cur_date
end makeASDate


PS: I love ASObjC Runner


makeASDate from "2013.05.12 12:13:17" for "yyyy.MM.dd HH:mm:ss"

to makeASDate from aTimeStamp for stringFormat
	tell application "ASObjC Runner"
		return convert string aTimeStamp format stringFormat
	end tell
end makeASDate

Hello.

I’ll come back with a cross-breed between your first script and mine, since not every timestamp needs to have seconds in them. (For robustness when reading in data from external sources.)

I guess that is why I made the handler so cumbersome, and I have been too lazy to rewrite it, but it shall be done, -soon. Thanks Stefan! :slight_smile:

(I like AsObjC runner too.)

Hello.

I have updated the script library above with StefanK’s suggestions (looting his code), and blended in some ideas of my own, making for a hopefully robust handler.

Hello.

Reinforced ymdTriple and hmsTriple as well with robustness, regarding invalid data.