+Define timeago_justnow for "Just now"
+Define timeago_lessthan for "Less than %1 %2"
+Define timeago_halfminute for "Half a minute"
+Define timeago_lessthan_minute for "Less than a minute"
+Define timeago_about_1hour for "About 1 hour"
+Define timeago_long_ago for "A long time ago"
+Define timeago_future for "A long time in the future"
+Function Pluralize Global Integer iCount String sUnit Returns String
+ If (iCount=1) Function_Return ((String(iCount))+" "+sUnit)
+ Else Function_Return ((String(iCount))+" "+sUnit+"s")
+Function TimeSpanInWords Global TimeSpan tsDescribe Returns String
+ Move (SpanTotalSeconds(tsDescribe)) to iTotalSeconds
+ If (iTotalSeconds<60) Begin
+ If (iTotalSeconds<=2) Function_Return timeago_justnow
+ If (iTotalSeconds<5) Function_Return (SFormat(timeago_lessthan,5,"seconds"))
+ If (iTotalSeconds<10) Function_Return (SFormat(timeago_lessthan,10,"seconds"))
+ If (iTotalSeconds<20) Function_Return (SFormat(timeago_lessthan,20,"seconds"))
+ If (iTotalSeconds<40) Function_Return timeago_halfminute
+ If (iTotalSeconds<60) Function_Return timeago_lessthan_minute
+ Move (SpanTotalDays(tsDescribe)) to iTotalDays
+ If (iTotalDays<1) Begin
+ Move (DateSetSecond(ts30Secs,30)) to ts30Secs
+ Move (tsDescribe-ts30Secs) to tsDescribe
+ Move (SpanTotalMinutes(tsDescribe)) to iTotalMinutes
+ If (iTotalMinutes<48) Function_Return ("About "+(Pluralize( iTotalMinutes, "minute")))
+ If (iTotalMinutes<90) Function_Return "About an hour"
+ Move ((iTotalMinutes+30)/60) to iTotalHours
+ Function_Return ("About "+(Pluralize( iTotalHours, "hour")))
+ If ((SpanHours(tsDescribe))>14) Move (iTotalDays+1) to iTotalDays
+ Move ((iTotalDays+10)/30) to iMonths
+ Function_Return ("About "+(Pluralize( iTotalDays, "day")))
+ Move (SpanTotalDays(tsDescribe)) to iTotalDays
+ Move (CurrentDateTime()) to dtTemp
+ Move (DateSetDay(dtTemp,01)) to dtTemp
+ Move (DateSetMonth(dtTemp,01)) to dtTemp
+ Move (iYears-(DateGetYear(dtTemp))) to iYears
+ Move ((Date(dtTemp))+iTotalDays) to dtTemp
+ Move (iYears+(DateGetYear(dtTemp))) to iYears
+ Move (DateGetMonth(dtTemp)) to iMonths
+ If ((DateGetDay(dtTemp)) > 17) Move (iMonths+1) to iMonths
+ Move (iMonths-1) to iMonths
+ Move (iYears+(iMonths/12)) to iYears
+ Move (Mod(iMonths,12)) to iMonths
+ If (iYears=0) Function_Return ("About "+(Pluralize( iMonths, "month")))
+ Move ("About "+(Pluralize( iYears, "year"))) to sReturn
+ If (iMonths>2) Append sReturn " and " iMonths " months"
+ Function_Return sReturn
+Function TimeBetweenInWords Global DateTime dtFrom DateTime dtUpto Returns String
+ If (dtFrom > dtUpto) Begin
+ If ((Date(dtFrom)) = "") Function_Return ""
+ If ((Date(dtUpto)) = "") Function_Return ""
+ If ((DateGetYear(dtFrom)) = 1753) Function_Return ""
+ If ((DateGetYear(dtUpto)) = 1753) Function_Return ""
+ Move (dtUpto-dtFrom) to tsDiff
+ Function_Return (TimeSpanInWords(tsDiff))
+Function TimeAgo_WithPassedNow Global DateTime dtNow DateTime dtCompare Returns String
+ If (dtCompare > dtNow) Move "from now" to sDirection
+ Else Move "ago" to sDirection
+ If ((Date(dtCompare)) = "") Function_Return ""
+ If ((DateGetYear(dtCompare)) = 1753) Function_Return ""
+ If ((DateGetYear(dtCompare)) < 1801) Function_Return timeago_long_ago
+ If ((DateGetYear(dtCompare)) > 2100) Function_Return timeago_future
+ Move (TimeBetweenInWords(dtCompare, dtNow )) to sReturn
+ If (sReturn<>timeago_justnow) Move (sReturn + " " + sDirection) to sReturn
+ Function_Return sReturn
+Function TimeAgo Global DateTime dtCompare Returns String
+ Move (CurrentDateTime()) to dtNow
+ Function_Return (TimeAgo_WithPassedNow(dtNow,dtCompare))