/* HowLongInstant.ahk by Jack Dunning http://www.computoredge.com/AutoHotkey/Free_AutoHotkey_Scripts_and_Apps_for_Learning_and_Generating_Ideas.html#HowLong This script is a modified version of the HowLongYearsMonthsDays.ahk script. It works by selecting a section of text which includes the start and stop date as the first and last date in the selection. The Hotkey conbination CTRL+ALT+WIN+h activates the parsing, reformatting and calculating. The script consists of five parts: 1. The Standard Clipboard Routine to capture selected text. 2. The RegEx for identifying and capturing the target dates. 3. The DateConvert() function in the DateStampConvert.ahk script formats the parsed dates in the standard TimeDate stamp (YYYYMMDD). 4. The HowLong() function found in the HowLongYearsMonthsDays.ahk script calculates the timespan by running using the two timedate sstamps as parameters. 5. Instantly displays the results in a MsgBox. Note: Uses the Case/Switch command in the MonthConvert() function to evaluate non-English month names. */ ^!#h:: OldClipboard := ClipboardAll Clipboard := "" Send, ^c ;copies selected text ClipWait 0 If ErrorLevel { MsgBox, No Text Selected! Return } StartingPos := 1 ; Two-date parsing (first and last dates in selection) RegExMatch(Clipboard , "sx)(\b[[:alpha:]]+.?\s\d\d?,?\s\d?\d?\d\d |\b\d\d?[-\s]?[[:alpha:]]+[-\s]?\d\d\d?\d? |\d\d?[-/]\d\d?[-/]\d\d\d?\d?) .*(\b[[:alpha:]]+.?\s\d\d?,?\s\d?\d?\d\d |\b\d\d?[-\s]?[[:alpha:]]+[-\s]?\d\d\d?\d? |\b\d\d?[-/]\d\d?[-/]\d\d\d?\d?)" , OutputVar, StartingPos) ; Convert two dates to DateTime stamp DateStamp1 := DateConvert(OutputVar1) DateStamp2 := DateConvert(OutputVar2) ; Calculate timespan in years, month, and days HowLong(DateStamp1,DateStamp2) ; MsgBox, , TimeSpan Calculation ; , Years %Years%`rMonths %Months%`rDays %Days% %Past% ; Display dates, datetime stamp, and timespan MsgBox,,Date Match, % OutputVar1 . "`r" . DateStamp1 . "`r" . OutputVar2 . "`r" . DateStamp2 . "`rYears:`t" Format("{:6}",Years) . "`rMonths:`t" Format("{:6}",Months) . "`rDays:`t" Format("{:6}",Days) . " " . Past Clipboard := OldClipboard Return ; DateConvert() Function DateConvert(DateFormat) { ; MsgBox %DateFormat% ; Regular Expression to identify US date format with alphabetic month Octob 10 2018 If (RegExMatch(DateFormat, "^([[:alpha:]]+).*?(\d\d?).*?(\d\d\d?\d?)$" , Date)) { ; Convert alphabetic month to numeric month NewMonth := MonthConvert(Date1) If NewMonth = "Not found!" { MsgBox Not a valid date! Return } Else Return MakeStamp(Date3,NewMonth,Date2) } ; European date formats 1 October 2018 Else If (RegExMatch(DateFormat, "(\d\d?).*?([[:alpha:]]+).*?(\d\d\d?\d?)", Date)) { ; Convert alphabetic month to numeric month ; MsgBox in euro %DateFormat% => %DateTemp% NewMonth := MonthConvert(Date2) If NewMonth = "Not found!" { MsgBox Not a valid date! } Else Return MakeStamp(Date3,NewMonth,Date1) } Else If (RegExMatch(DateFormat, "^(\d\d?).*?(\d\d?).*?(\d\d\d?\d?)$" , Date)) { If (Date1 > 12) Return MakeStamp(Date3,Date2,Date1) ; 10-13-18 Else If (Date2 > 12) Return MakeStamp(Date3,Date1,Date2) ; 13-10-2018 Else { ; ambiguous date format MsgBox, 4,, US date format? (press Yes)`rEuropean date format? (press No) IfMsgBox Yes Return MakeStamp(Date3,Date1,Date2) ; 10-1-18 else Return MakeStamp(Date3,Date2,Date1) ; 1-10-18 } } Else MsgBox %DateFormat% No date found! } ; This function uses the Switch/Case command statement to convert text months into numbers. MonthConvert(month) { ; MsgBox % SubStr(month,1,3) Switch SubStr(month,1,3) { Case "jan","ene","jän","gen":Return "01" Case "feb","fév","fev": Return "02" Case "mar","mär": Return "03" Case "apr","abr","avr": Return "04" Case "may","mai","mag": Return "05" Case "jun","jui","gui": If (SubStr(month,1,4) = "juil") Return "07" Else Return "06" Case "jul","lug": Return "07" Case "aug","ago","aoû","aou","ag": Return "08" Case "sep","set": Return "09" Case "oct","okt","ott": Return "10" Case "nov": Return "11" Case "dec","dic","dez","déc": Return "12" } } ; This function is a little arbitrary since it cuts off at year 1940 before jumping to the 2000's YearCheck(ByRef Year) { If Year > 40 Year := "19" . Year Else Year := "20" . Year } MakeStamp(Year,Month,Day) { ; if two-digit year, convert to four-digit year If StrLen(Year) = 2 YearCheck(Year) ; concatenate DateTime Stamp DateStamp := Year . Format("{:02}", Month) . Format("{:02}", Day) ; MsgBox %DateStamp% ; Check for valid date If DateStamp is not Date { MsgBox Invalid date! %DateStamp% %DateFormat% } Else Return DateStamp } HowLong(FromDay,ToDay) { Global Years,Months,Days,Past Past := "" ; Trim any time component from the input dates FromDay := SubStr(FromDay,1,8) ToDay := SubStr(ToDay,1,8) ; For proper date order before calculation /* If (ToDay <= FromDay) { Years := 0, Months := 0, Days := 0 MsgBox, Start date after end date! Return } */ If (ToDay = FromDay) { Years := 0, Months := 0, Days := 0 Return } If (ToDay < FromDay) { Temp := Today ToDay := FromDay FromDay := Temp Past := "Ago" } /* The function no longer requires this Leap Year test since when needed AutoHotkey now calculates the length of the previous month in the target year. I've left this commented-out code in here for people looking for a different approach to identifying a Leap Year but it does not run in this script. ; Test for Stop date Leap Year. Invalid date calc returns blank. Feb29 := SubStr(ToDay,1,4) . "0229" Feb29 += 1, days ; Test for Leap Year If (Feb29 != "") Feb := 29 Else Feb := 28 */ ; Calculate years Years := % SubStr(ToDay,5,4) - SubStr(FromDay,5,4) < 0 ? SubStr(ToDay,1,4)-SubStr(FromDay,1,4)-1 : SubStr(ToDay,1,4)-SubStr(FromDay,1,4) ; Remove years from the calculation FromYears := Substr(FromDay,1,4)+years . SubStr(FromDay,5,4) /* Calculate the number of months between the Start date (Years removed) and the Stop date. If the day of the month in the Start date is greater than the day of the month in the Stop date, then add 11 or 12 months to the calculation depending upon the comparison between month days. */ If (Substr(FromYears,5,2) <= Substr(ToDay,5,2)) and (Substr(FromYears,7,2) <= Substr(ToDay,7,2)) Months := Substr(ToDay,5,2) - Substr(FromYears,5,2) Else If (Substr(FromYears,5,2) < Substr(ToDay,5,2)) and (Substr(FromYears,7,2) > Substr(ToDay,7,2)) Months := Substr(ToDay,5,2) - Substr(FromYears,5,2) - 1 Else If (Substr(FromYears,5,2) > Substr(ToDay,5,2)) and (Substr(FromYears,7,2) <= Substr(ToDay,7,2)) Months := Substr(ToDay,5,2) - Substr(FromYears,5,2) +12 Else If (Substr(FromYears,5,2) >= Substr(ToDay,5,2)) and (Substr(FromYears,7,2) > Substr(ToDay,7,2)) Months := Substr(ToDay,5,2) - Substr(FromYears,5,2) +11 ; If the start day of the month is less than the stop day of the month use the same month ; Otherwise use the previous month, (If Jan "01" use Dec "12") If (Substr(FromYears,7,2) <= Substr(ToDay,7,2)) FromMonth := Substr(ToDay,1,4) . SubStr(ToDay,5,2) . Substr(FromDay,7,2) Else If Substr(ToDay,5,2) = "01" FromMonth := Substr(ToDay,1,4)-1 . "12" . Substr(FromDay,7,2) Else FromMonth := Substr(ToDay,1,4) . Format("{:02}", SubStr(ToDay,5,2)-1) . Substr(FromDay,7,2) ; FromMonth := Substr(ToDay,1,4) . Substr("0" . SubStr(ToDay,5,2)-1,-1) . Substr(FromDay,7,2) ; "The Format("{:02}", SubStr(ToDay,5,2)-1)" function replaces the original "Substr("0" . SubStr(ToDay,5,2)-1,-1)" ; function found in the line of code above. Both serve the same purpose, although the original function ; uses sleight of hand to pad single digit months with a zero (0). ; Adjust for previous months with less days than target day Date1 := Substr(FromMonth,1,6) . "01" Date2 := Substr(ToDay,1,6) . "01" Date2 -= Date1, Days If (Date2 < Substr(FromDay,7,2)) and (Date2 != 0) FromMonth := Substr(FromMonth,1,6) . Date2 ; Calculate remaining days. This operation (EnvSub) changes the value of the original ; ToDay variable, but, since this completes the function, we don't need to save ToDay ; in its original form. Days := ToDay Days -= %FromMonth% , d }