You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 08:03:21