From da8466ae0bb7d3a106457d9bb845d5b8fde5060b Mon Sep 17 00:00:00 2001 From: Abin Simon Date: Fri, 12 Jan 2024 17:55:27 +0530 Subject: [PATCH] Fix handling of recurring events with end date (#4997) Previously we were not accurately handling the end date of recurring events. This was because we treated end date to be start of the day instead of the end of day. --- #### Does this PR need a docs update or release note? - [ ] :white_check_mark: Yes, it's included - [ ] :clock1: Yes, but in a later PR - [x] :no_entry: No #### Type of change - [x] :sunflower: Feature - [ ] :bug: Bugfix - [ ] :world_map: Documentation - [ ] :robot: Supportability/Tests - [ ] :computer: CI/Deployment - [ ] :broom: Tech Debt/Cleanup #### Issue(s) * https://github.com/alcionai/corso/issues/3890 #### Test Plan - [ ] :muscle: Manual - [x] :zap: Unit test - [ ] :green_heart: E2E --- src/internal/converters/ics/ics.go | 18 ++++++++++---- src/internal/converters/ics/ics_test.go | 33 ++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/internal/converters/ics/ics.go b/src/internal/converters/ics/ics.go index 0682e36ef..ce67b8908 100644 --- a/src/internal/converters/ics/ics.go +++ b/src/internal/converters/ics/ics.go @@ -106,7 +106,6 @@ func getUTCTime(ts, tz string) (time.Time, error) { // https://www.rfc-editor.org/rfc/rfc5545#section-3.3.10 // https://learn.microsoft.com/en-us/graph/api/resources/patternedrecurrence?view=graph-rest-1.0 // Ref: https://github.com/closeio/sync-engine/pull/381/files -// FIXME: When we have daily repeating task the last one is not getting added (due to timezone differences) func getRecurrencePattern( ctx context.Context, recurrence models.PatternedRecurrenceable, @@ -175,10 +174,19 @@ func getRecurrencePattern( case models.ENDDATE_RECURRENCERANGETYPE: end := rrange.GetEndDate() if end != nil { - // NOTE: We convert just a date into date+time in a - // different timezone which will cause it to not be just - // a date anymore. - endTime, err := getUTCTime(end.String(), ptr.Val(rrange.GetRecurrenceTimeZone())) + parsedTime, err := dttm.ParseTime(end.String()) + if err != nil { + return "", clues.Wrap(err, "parsing recurrence end date") + } + + // end date is always computed as end of the day and + // so add 23 hours 59 minutes 59 seconds as seconds is + // the resolution we need + parsedTime = parsedTime.Add(24*time.Hour - 1*time.Second) + + endTime, err := getUTCTime( + parsedTime.Format(string(dttm.M365DateTimeTimeZone)), + ptr.Val(rrange.GetRecurrenceTimeZone())) if err != nil { return "", clues.WrapWC(ctx, err, "parsing end time") } diff --git a/src/internal/converters/ics/ics_test.go b/src/internal/converters/ics/ics_test.go index 066e6c09d..787132d0b 100644 --- a/src/internal/converters/ics/ics_test.go +++ b/src/internal/converters/ics/ics_test.go @@ -192,6 +192,37 @@ func (suite *ICSUnitSuite) TestGetRecurrencePattern() { expect: "FREQ=DAILY;INTERVAL=1", errCheck: require.NoError, }, + { + name: "daily with end date in different timezone", + recurrence: func() models.PatternedRecurrenceable { + rec := models.NewPatternedRecurrence() + pat := models.NewRecurrencePattern() + + typ, err := models.ParseRecurrencePatternType("daily") + require.NoError(suite.T(), err) + + pat.SetTypeEscaped(typ.(*models.RecurrencePatternType)) + pat.SetInterval(ptr.To(int32(1))) + + rng := models.NewRecurrenceRange() + + rrtype, err := models.ParseRecurrenceRangeType("endDate") + require.NoError(suite.T(), err) + + rng.SetTypeEscaped(rrtype.(*models.RecurrenceRangeType)) + + edate := serialization.NewDateOnly(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)) + rng.SetEndDate(edate) + rng.SetRecurrenceTimeZone(ptr.To("India Standard Time")) + + rec.SetPattern(pat) + rec.SetRangeEscaped(rng) + + return rec + }, + expect: "FREQ=DAILY;INTERVAL=1;UNTIL=20210101T182959Z", + errCheck: require.NoError, + }, { name: "weekly", recurrence: func() models.PatternedRecurrenceable { @@ -239,7 +270,7 @@ func (suite *ICSUnitSuite) TestGetRecurrencePattern() { return rec }, - expect: "FREQ=WEEKLY;INTERVAL=1;UNTIL=20210101T000000Z", + expect: "FREQ=WEEKLY;INTERVAL=1;UNTIL=20210101T235959Z", errCheck: require.NoError, }, {