Mercurial > lbo > hg > goe_bot
changeset 53:3cafb04ae4f7
Implement remaining date formats
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 10 Dec 2016 20:32:16 +0100 |
parents | 0a3d58b0cefa |
children | b56ef3fe4bff |
files | handler_remind.go |
diffstat | 1 files changed, 74 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/handler_remind.go Sat Dec 10 18:12:04 2016 +0100 +++ b/handler_remind.go Sat Dec 10 20:32:16 2016 +0100 @@ -15,59 +15,96 @@ var ( hhmmRE = regexp.MustCompile(`(\d{1,2}):(\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)(:..)?`) + dateOfWeekRE = regexp.MustCompile(`(Mo|Di|Mi|Do|Fr|Sa|So) (\d{1,2}):(\d\d)(:..)?`) + + dayOfWeekOff = map[string]time.Weekday{ + "So": time.Sunday, + "Mo": time.Monday, + "Di": time.Tuesday, + "Mi": time.Wednesday, + "Do": time.Thursday, + "Fr": time.Friday, + "Sa": time.Saturday, + } ) -func parseReminderString(s string) time.Time { +// Parses a time, and returns a UTC time (respecting the value of flagLocalOffset) +// Returns the parsed time (t.IsZero() if parsing was unsuccessful), and the index of the first non-time +// character in the string +func parseReminderString(s string) (time.Time, int) { now := time.Now() - log.Println(s) - if m := hhmmRE.FindStringSubmatch(s); len(m) >= 3 { - log.Println(m) - h, err1 := strconv.ParseInt(m[1], 10, 32) - m, err2 := strconv.ParseInt(m[2], 10, 32) + if m := dateRE.FindStringSubmatch(s); len(m) >= 6 { + y, _ := strconv.ParseInt(m[1], 10, 32) + 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) + + t := time.Date(int(y), time.Month(M), int(d), int(h), int(m), 0, 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) + + if weekday, ok := dayOfWeekOff[m[1]]; ok { + today := now.Weekday() + // Any point in the day of the reminder. Useful for not having to do week/month/year switch calculations. + var pointInTargetDay time.Time - if err1 == nil && err2 == nil { - 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) + // today's weekday means "in a week". + // If target is in same week, add difference + if today < weekday { + pointInTargetDay = now.Add(time.Duration(weekday-today) * 24 * time.Hour) + } else { // If target is next week, add time to end-of-week plus time to target plus 1 (Sat-to-Sun) + 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] + } 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) - if alert > timeOfDay { // later today - return midnight.Add(alert) - } else { // that time tomorrow - return midnight.Add(24*time.Hour + alert) - } - } else { - return time.Unix(0, 0) + 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) + + if alert > timeOfDay { // later today + return midnight.Add(alert), hhmmRE.FindStringIndex(s)[1] + } else { // that time tomorrow + return midnight.Add(24*time.Hour + alert), hhmmRE.FindStringIndex(s)[1] } } else if m := durRE.FindStringSubmatch(s); len(m) >= 3 { - log.Println(m) - dur, err := strconv.ParseInt(m[1], 10, 32) - - if err != nil { - return time.Unix(0, 0) - } + dur, _ := strconv.ParseInt(m[1], 10, 32) + var t time.Time if m[2] == "s" { - return now.Add(time.Duration(dur) * time.Second) + t = now.Add(time.Duration(dur) * time.Second) } else if m[2] == "m" { - return now.Add(time.Duration(dur) * time.Minute) + t = now.Add(time.Duration(dur) * time.Minute) } else if m[2] == "h" { - return now.Add(time.Duration(dur) * time.Hour) + t = now.Add(time.Duration(dur) * time.Hour) } else if m[2] == "d" { - return now.Add(time.Duration(dur) * 24 * time.Hour) + t = now.Add(time.Duration(dur) * 24 * time.Hour) } else { - return time.Unix(0, 0) + t = time.Unix(0, 0) } + + return t, durRE.FindStringIndex(s)[1] } // rest is not implemented yet - return time.Unix(0, 0) + return time.Unix(0, 0), 0 } // Handler for /remind messages @@ -76,17 +113,9 @@ func reminderHandler(ctx context.Context, msg message) (replyContent, error) { // TODO: This doesn't work with multi-part formats like dateRE or dateOfWeekRE! // first part is time - parts := strings.SplitN(msg.Text, " ", 2) + alertTime, restStart := parseReminderString(strings.Trim(msg.Text, " ")) - if len(parts) < 2 { - log.Println("Not enough parts in message:", msg.Text) - return replyContent{text: "Tut mir leid, ich verstehe das Format nicht. Bitte benutze +XX{s,m,h,d} oder hh:mm. Zum Beispiel: +23m oder 14:45"}, - nil - } - - alertTime := parseReminderString(parts[0]) - - if alertTime.IsZero() { + if restStart == 0 || alertTime.IsZero() { return replyContent{text: "Tut mir leid, ich verstehe das Format nicht. Bitte benutze +XX{s,m,h,d} oder hh:mm. Zum Beispiel: +23m oder 14:45"}, nil } @@ -99,7 +128,7 @@ } r := reminder{ - Text: parts[1], + Text: strings.Trim(msg.Text[restStart:], " "), Owner: msg.From.First_Name + " " + msg.From.Last_Name, Due: alertTime, ChatID: msg.Chat.ID,