changeset 67:775f65a3c897

Add second accuracy to reminder parsing
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 12 Dec 2016 20:51:05 +0100
parents bf69962d10a5
children e6a411adf464
files handler_remind.go
diffstat 1 files changed, 36 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/handler_remind.go	Mon Dec 12 20:42:32 2016 +0100
+++ b/handler_remind.go	Mon Dec 12 20:51:05 2016 +0100
@@ -13,10 +13,10 @@
 )
 
 var (
-	hhmmRE       = regexp.MustCompile(`(\d{1,2}):(\d\d)`)
+	hhmmRE       = regexp.MustCompile(`(\d{1,2}):(\d\d):?(\d\d)?`)
 	durRE        = regexp.MustCompile(`\+?(\d+)([smhd])`)
-	dateRE       = regexp.MustCompile(`(\d{4})-(\d\d)-(\d\d) (\d{1,2}):(\d\d)(:..)?`)
-	dateOfWeekRE = regexp.MustCompile(`(Mo|Di|Mi|Do|Fr|Sa|So) (\d{1,2}):(\d\d)(:..)?`)
+	dateRE       = regexp.MustCompile(`(\d{4})-(\d\d)-(\d\d) (\d{1,2}):(\d\d):?(\d\d)?`)
+	dateOfWeekRE = regexp.MustCompile(`(Mo|Di|Mi|Do|Fr|Sa|So) (\d{1,2}):(\d\d):?(\d\d)?`)
 
 	dayOfWeekOff = map[string]time.Weekday{
 		"So": time.Sunday,
@@ -40,14 +40,24 @@
 		M, _ := strconv.ParseInt(m[2], 10, 32)
 		d, _ := strconv.ParseInt(m[3], 10, 32)
 		h, _ := strconv.ParseInt(m[4], 10, 32)
-		m, _ := strconv.ParseInt(m[5], 10, 32)
+		min, _ := strconv.ParseInt(m[5], 10, 32)
+		sec := int64(0)
 
-		t := time.Date(int(y), time.Month(M), int(d), int(h), int(m), 0, 0, time.UTC)
+		if len(m) >= 7 {
+			sec, _ = strconv.ParseInt(m[6], 10, 32)
+		}
+
+		t := time.Date(int(y), time.Month(M), int(d), int(h), int(min), int(sec), 0, time.UTC)
 
 		return t.Add(-time.Duration(*flagLocalOffset) * time.Second), dateRE.FindStringIndex(s)[1]
 	} else if m := dateOfWeekRE.FindStringSubmatch(s); len(m) >= 4 {
 		h, _ := strconv.ParseInt(m[2], 10, 32)
 		min, _ := strconv.ParseInt(m[3], 10, 32)
+		sec := int64(0)
+
+		if len(m) >= 5 {
+			sec, _ = strconv.ParseInt(m[4], 10, 32)
+		}
 
 		if weekday, ok := dayOfWeekOff[m[1]]; ok {
 			today := now.Weekday()
@@ -62,21 +72,34 @@
 				diff := int(weekday) + int(time.Saturday-today) + 1
 				pointInTargetDay = now.Add(time.Duration(diff) * 24 * time.Hour)
 			}
-			return time.Date(pointInTargetDay.Year(), pointInTargetDay.Month(), pointInTargetDay.Day(), int(h), int(min), 0, 0, time.UTC).Add(-time.Duration(*flagLocalOffset) * time.Second), dateOfWeekRE.FindStringIndex(s)[1]
+			return time.Date(pointInTargetDay.Year(),
+				pointInTargetDay.Month(),
+				pointInTargetDay.Day(),
+				int(h),
+				int(min),
+				int(sec), 0, time.UTC).Add(-time.Duration(*flagLocalOffset) * time.Second), dateOfWeekRE.FindStringIndex(s)[1]
 		} else {
 			return time.Unix(0, 0), 0
 		}
 	} else if m := hhmmRE.FindStringSubmatch(s); len(m) >= 3 { // this has to come after dateRE and dateOfWeekRE, because it's a sub match
 		// Not checking errors as the regex should not let through any non-digits
 		h, _ := strconv.ParseInt(m[1], 10, 32)
-		m, _ := strconv.ParseInt(m[2], 10, 32)
+		min, _ := strconv.ParseInt(m[2], 10, 32)
+		sec := int64(0)
+
+		// seconds, too
+		if len(m) >= 4 {
+			sec, _ = strconv.ParseInt(m[3], 10, 32)
+		}
 
 		nowH, nowM, nowS := now.Clock()
 		timeOfDay := time.Duration(nowH)*time.Hour + time.Duration(nowM)*time.Minute + time.Duration(nowS)*time.Second
 		midnight := now.Add(-timeOfDay)
-		// duration since midnight of alert time
-		// timezone mucking-about because we're using UTC, but users are not
-		alert := time.Duration(h)*time.Hour + time.Duration(m)*time.Minute - (time.Duration(*flagLocalOffset) * time.Second)
+		// duration since midnight of alert time. Converting to UTC for database storage
+		alert := (time.Duration(h)*time.Hour +
+			time.Duration(min)*time.Minute +
+			time.Duration(sec)*time.Second -
+			(time.Duration(*flagLocalOffset) * time.Second))
 
 		if alert > timeOfDay { // later today
 			return midnight.Add(alert), hhmmRE.FindStringIndex(s)[1]
@@ -163,8 +186,9 @@
 
 	remaining := alertTime.Sub(now)
 	hours := uint64(remaining.Seconds()) / 3600
-	minutes := (uint64(remaining.Seconds()+1) % 3600) / 60
-	return replyContent{text: fmt.Sprintf("*⏰* Erinnerung #%d in %d:%02d", r.ReminderID, hours, minutes)}, nil
+	minutes := (uint64(remaining.Seconds()) % 3600) / 60
+	seconds := (uint64(remaining.Seconds()) % 60)
+	return replyContent{text: fmt.Sprintf("*⏰* Erinnerung #%d in %02d:%02d:%02d", r.ReminderID, hours, minutes, seconds)}, nil
 }
 
 func listReminders(ctx context.Context, chatID int64) (replyContent, error) {