Skip to content

Commit 39663c3

Browse files
authored
fix: Outlook calendar display event date time (#615)
* quick fix: list calendar for users without groups access * fix: share time in context. and default timezone to OBOT_USER_TIMEZONE not now.location() * fix: convert start/end time in the output to users timezone * fix: show all day event as all-day, convert time of regular event to user's timezone * fix: time after merge from main * fix: show all day event in get * fix: display user's timzeone time in printEvent * fix: update print event
1 parent 6e32a15 commit 39663c3

File tree

3 files changed

+104
-19
lines changed

3 files changed

+104
-19
lines changed

microsoft365/outlook/calendar/main.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,18 @@ func main() {
2727
os.Exit(1)
2828
}
2929
case "listEventsToday":
30-
now := time.Now()
31-
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
32-
end := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location())
30+
timezone := os.Getenv("OBOT_USER_TIMEZONE")
31+
if timezone == "" {
32+
timezone = "UTC" // default fallback
33+
}
34+
loc, err := time.LoadLocation(timezone)
35+
if err != nil {
36+
fmt.Println("Error loading location: %s. Error: %s", timezone, err)
37+
os.Exit(1)
38+
}
39+
now := time.Now().In(loc)
40+
start := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, loc)
41+
end := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, loc)
3342
if err := commands.ListEvents(context.Background(), start, end); err != nil {
3443
fmt.Println(err)
3544
os.Exit(1)

microsoft365/outlook/calendar/pkg/printers/events.go

+91-16
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package printers
33
import (
44
"context"
55
"fmt"
6-
"github.com/obot-platform/tools/microsoft365/outlook/calendar/pkg/graph"
7-
"github.com/obot-platform/tools/microsoft365/outlook/calendar/pkg/util"
86
"github.com/jaytaylor/html2text"
97
msgraphsdkgo "github.com/microsoftgraph/msgraph-sdk-go"
108
"github.com/microsoftgraph/msgraph-sdk-go/models"
9+
"github.com/obot-platform/tools/microsoft365/outlook/calendar/pkg/graph"
10+
"github.com/obot-platform/tools/microsoft365/outlook/calendar/pkg/util"
11+
"os"
1112
"strings"
13+
"time"
1214
)
1315

1416
func EventToString(ctx context.Context, client *msgraphsdkgo.GraphServiceClient, calendar graph.CalendarInfo, event models.Eventable) string {
@@ -27,32 +29,52 @@ func EventToString(ctx context.Context, client *msgraphsdkgo.GraphServiceClient,
2729
var sb strings.Builder
2830
sb.WriteString("Subject: " + util.Deref(event.GetSubject()) + "\n")
2931
sb.WriteString(" ID: " + util.Deref(event.GetId()) + "\n")
30-
startTZ, endTZ := EventDisplayTimeZone(event)
31-
sb.WriteString(" Start: " + util.Deref(event.GetStart().GetDateTime()) + startTZ + "\n")
32-
sb.WriteString(" End: " + util.Deref(event.GetEnd().GetDateTime()) + endTZ + "\n")
32+
33+
isAllDay := util.Deref(event.GetIsAllDay())
34+
if isAllDay {
35+
sb.WriteString(" Time: All Day Event\n")
36+
} else {
37+
startTimeConverted, startTZDisplay, endTimeConverted, endTZDisplay := convertEventTimesToUserTimezone(event)
38+
sb.WriteString(" Start Time: " + startTimeConverted + " " + startTZDisplay + "\n")
39+
sb.WriteString(" End Time: " + endTimeConverted + " " + endTZDisplay + "\n")
40+
}
41+
42+
isRecurring := "No"
43+
if event.GetSeriesMasterId() != nil {
44+
isRecurring = "Yes"
45+
}
46+
sb.WriteString(" Recurring: " + isRecurring + "\n")
47+
3348
sb.WriteString(" In calendar: " + calendarName + " (ID " + calendar.ID + ")\n")
3449
if calendar.Calendar.GetOwner() != nil {
35-
fmt.Printf(" Owner: %s (%s)\n", util.Deref(calendar.Calendar.GetOwner().GetName()), util.Deref(calendar.Calendar.GetOwner().GetAddress()))
36-
fmt.Printf(" Owner Type: %s\n", string(calendar.Owner))
50+
sb.WriteString(" Owner: " + util.Deref(calendar.Calendar.GetOwner().GetName()) + " (" + util.Deref(calendar.Calendar.GetOwner().GetAddress()) + ")\n")
51+
sb.WriteString(" Owner Type: " + string(calendar.Owner) + "\n")
3752
}
3853
return sb.String()
3954
}
4055

4156
func PrintEvent(event models.Eventable, detailed bool) {
4257
fmt.Printf("Subject: %s\n", util.Deref(event.GetSubject()))
4358
fmt.Printf(" ID: %s\n", util.Deref(event.GetId()))
44-
startTZ, endTZ := EventDisplayTimeZone(event)
45-
fmt.Printf(" Start: %s%s\n", util.Deref(event.GetStart().GetDateTime()), startTZ)
46-
fmt.Printf(" End: %s%s\n", util.Deref(event.GetEnd().GetDateTime()), endTZ)
59+
60+
isAllDay := util.Deref(event.GetIsAllDay())
61+
if isAllDay {
62+
fmt.Printf(" Time: All Day Event\n")
63+
} else {
64+
startTimeConverted, startTZDisplay, endTimeConverted, endTZDisplay := convertEventTimesToUserTimezone(event)
65+
66+
fmt.Printf(" Start Time: %s %s\n", startTimeConverted, startTZDisplay)
67+
fmt.Printf(" End Time: %s %s\n", endTimeConverted, endTZDisplay)
68+
}
69+
70+
if event.GetSeriesMasterId() != nil {
71+
fmt.Printf(" Recurring: Yes\n")
72+
} else {
73+
fmt.Printf(" Recurring: No\n")
74+
}
4775

4876
if detailed {
4977
fmt.Printf(" Location: %s\n", util.Deref(event.GetLocation().GetDisplayName()))
50-
fmt.Printf(" Is All Day: %t\n", util.Deref(event.GetIsAllDay()))
51-
isRecurring := false
52-
if event.GetSeriesMasterId() != nil {
53-
isRecurring = true
54-
}
55-
fmt.Printf(" Is Recurring: %t\n", isRecurring)
5678
fmt.Printf(" Is Cancelled: %t\n", util.Deref(event.GetIsCancelled()))
5779
fmt.Printf(" Is Online Meeting: %t\n", util.Deref(event.GetIsOnlineMeeting()))
5880
fmt.Printf(" Response Status: %s\n", event.GetResponseStatus().GetResponse().String())
@@ -102,3 +124,56 @@ func EventDisplayTimeZone(event models.Eventable) (string, string) {
102124
}
103125
return startTZ, endTZ
104126
}
127+
128+
// convertTimeStringToUserTimezone converts a time string from source timezone to user timezone
129+
func convertTimeStringToUserTimezone(timeStr, sourceTZ, userTZ string) (string, string) {
130+
// If it's empty or no conversion is needed
131+
if timeStr == "" || userTZ == sourceTZ {
132+
return timeStr, sourceTZ
133+
}
134+
135+
layout := "2006-01-02T15:04:05.0000000" // a hardcoded layout for parsing the time string
136+
137+
// Load source location
138+
srcLoc, err := time.LoadLocation(sourceTZ)
139+
if err != nil {
140+
fmt.Printf("Error loading source timezone: %s, error: %s\n", sourceTZ, err)
141+
return timeStr, sourceTZ
142+
}
143+
144+
// Parse the time string *in* the source location
145+
t, err := time.ParseInLocation(layout, timeStr, srcLoc)
146+
if err != nil {
147+
fmt.Printf("Error parsing time string: %s\n", err)
148+
return timeStr, sourceTZ
149+
}
150+
151+
// Load user location
152+
userLoc, err := time.LoadLocation(userTZ)
153+
if err != nil {
154+
fmt.Printf("Error loading user timezone: %s, error: %s\n", userTZ, err)
155+
return timeStr, sourceTZ
156+
}
157+
158+
// Convert to user's timezone
159+
t = t.In(userLoc)
160+
return t.Format(layout), userTZ
161+
}
162+
163+
// convertEventTimesToUserTimezone converts both start and end times of an event to the user's timezone
164+
func convertEventTimesToUserTimezone(event models.Eventable) (start, startTZ, end, endTZ string) {
165+
userTZ := os.Getenv("OBOT_USER_TIMEZONE")
166+
if userTZ == "" {
167+
userTZ = "UTC"
168+
}
169+
170+
startTime := util.Deref(event.GetStart().GetDateTime())
171+
startTZSource := util.Deref(event.GetStart().GetTimeZone())
172+
start, startTZ = convertTimeStringToUserTimezone(startTime, startTZSource, userTZ)
173+
174+
endTime := util.Deref(event.GetEnd().GetDateTime())
175+
endTZSource := util.Deref(event.GetEnd().GetTimeZone())
176+
end, endTZ = convertTimeStringToUserTimezone(endTime, endTZSource, userTZ)
177+
178+
return start, startTZ, end, endTZ
179+
}

microsoft365/outlook/calendar/tool.gpt

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ Param: response: The response to the invitation. Possible values are "accept", "
129129
---
130130
Name: Outlook Calendar Context
131131
Type: context
132+
Share Context: ../../../time
132133

133134
#!sys.echo
134135

0 commit comments

Comments
 (0)