ASP.NET Core 3.1调用Google Calendar API遇System.FormatException求助
问题解决:Google Calendar API返回时间触发System.FormatException
问题原因
Google Calendar API返回的事件时间格式为带时区偏移的ISO 8601字符串(如2023-12-01T10:00:00+05:30),旧版本Google.Apis库反序列化EventDateTime对象时,访问DateTime属性会尝试将带偏移的时间转换为本地DateTime,触发格式解析异常。同时创建事件时未明确指定时区,API会根据用户日历时区返回带偏移的时间,进一步加剧解析问题。
解决方案
1. 优先使用DateTimeOffset属性替代DateTime
直接访问EventDateTime的DateTimeOffset属性,它原生支持带时区偏移的时间格式,避免解析异常:
// 获取返回事件的开始时间 var startTime = eventRequest.Start.DateTimeOffset; // 获取返回事件的结束时间 var endTime = eventRequest.End.DateTimeOffset;
2. 创建事件时明确指定时区
创建EventDateTime时同时设置DateTimeOffset和TimeZone,确保API返回的时间格式稳定且可正确解析:
var @event = new Event { Summary = "Akila", Location = "Sri Lanka", Description = "Hello", Start = new EventDateTime() { // 斯里兰卡时区为UTC+5:30 DateTimeOffset = new DateTimeOffset(2023, 12, 1, 9, 0, 0, TimeSpan.FromHours(5.5)), TimeZone = "Asia/Colombo" }, End = new EventDateTime() { DateTimeOffset = new DateTimeOffset(2023, 12, 1, 10, 0, 0, TimeSpan.FromHours(5.5)), TimeZone = "Asia/Colombo" }, };
3. 升级Google.Apis相关NuGet包
使用兼容ASP.NET Core 3.1的最新稳定版Google.Apis库,修复旧版本的序列化/反序列化bug:
- 升级
Google.Apis.Calendar到v1.60.0及以上 - 升级
Google.Apis.Auth到对应兼容版本
4. 修复异步调用死锁问题(额外优化)
原代码中使用.Result同步等待异步授权操作,可能导致死锁,改为await:
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, new FileDataStore(credPath, true));
修改后的完整代码示例
using Google.Apis.Auth.OAuth2; using Google.Apis.Calendar.v3; using Google.Apis.Calendar.v3.Data; using Google.Apis.Services; using Google.Apis.Util.Store; using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Google_Calendar.Helper { public class GoogleCalendarHelper { protected GoogleCalendarHelper() { } [Obsolete] public static async Task<Event> CreateGoogleCalendar(GoogleCalender request) { try { string[] Scopes = { CalendarService.Scope.Calendar }; string ApplicationName = "Google Calendar"; UserCredential credential; using (var stream = new FileStream(Path.Combine(Directory.GetCurrentDirectory(), "Cre", "cre.json"), FileMode.Open, FileAccess.Read)) { string credPath = "token.json"; // 替换.Result为await,避免死锁 credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, new FileDataStore(credPath, true)); } var services = new CalendarService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = ApplicationName, }); var @event = new Event { Summary = "Akila", Location = "Sri Lanka", Description = "Hello", Start = new EventDateTime() { DateTimeOffset = new DateTimeOffset(2023, 12, 1, 9, 0, 0, TimeSpan.FromHours(5.5)), TimeZone = "Asia/Colombo" }, End = new EventDateTime() { DateTimeOffset = new DateTimeOffset(2023, 12, 1, 10, 0, 0, TimeSpan.FromHours(5.5)), TimeZone = "Asia/Colombo" }, }; var eventRequest = await services.Events.Insert(@event, "primary").ExecuteAsync(); // 后续使用时优先访问DateTimeOffset而非DateTime // var start = eventRequest.Start.DateTimeOffset; return eventRequest; } catch(Exception ex) { throw new Exception(ex.Message); } } } }
内容的提问来源于stack exchange,提问作者Akila
相关产品推荐
相关产品推荐

