googleapis / google-api-dotnet-client

Google APIs Client Library for .NET
https://developers.google.com/api-client-library/dotnet
Apache License 2.0
1.36k stars 525 forks source link

Call to EventDateTime.DateTimeDateTimeOffset will result in an error in the underlying API #2580

Closed MrDust001 closed 12 months ago

MrDust001 commented 1 year ago

Hi, i am expierencing the error below. Hope you can check whats going on here, thank you in advance. regards, Mark

Environment details

Steps to reproduce

using System;
using System.Globalization;
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 Newtonsoft.Json.Linq;
using static System.Net.Mime.MediaTypeNames;

namespace MyApp 
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Google Calendar!");

            //Normal Connection method NEVER MIND
            //_____________________________________________________________

            string[] Scopes = { CalendarService.Scope.CalendarEvents };
            string ApplicationName = "MyApp";

            UserCredential credential;

            using (var stream =
                new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + @"\credentials.json", FileMode.Open, FileAccess.Read))
            {
                string credPath = "token.json";
                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.FromStream(stream).Secrets,
                    Scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(credPath, true)).Result;
            }

            // Create Google Calendar API service.
            var service = new CalendarService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = ApplicationName,
            });

            // Define parameters of request.
            EventsResource.ListRequest request = service.Events.List("primary");
            request.TimeMin = DateTime.Now;
            request.TimeMax = DateTime.Now.AddDays(1);
            request.ShowDeleted = false;
            request.SingleEvents = true;
            request.MaxResults = 1000;
            request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;

            //End NEVER MIND----------------------------------------------------------

            // Check events.
            Events events = request.Execute();

            if (events.Items != null && events.Items.Count > 0)
            {
                foreach (var eventItem in events.Items)
                {
                    string s = eventItem.Start.DateTimeRaw;

                    if (s != null)
                    {

                        //Parsing exact
                        DateTimeOffset offset = DateTimeOffset.ParseExact(eventItem.Start.DateTimeRaw, "yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
                        Console.WriteLine(offset.ToString());
                        //returns valid time i.e. 29.10.2023 12:00:00 +01:00
                        Console.ReadLine();
                        //ERROR
                        //Any Instance of eventItem.Start.DateTimeDateTimeOffset will throw an error inside the google API
                        DateTimeOffset? dto = eventItem.Start.DateTimeDateTimeOffset;
                        //eventItem.Start.DateTimeDateTimeOffset.HasValue will throw the same error to

                        ///System.FormatException HResult = 0x80131537
                        //Message = String '2023-10-29T12:00:00+01:00' was not recognized as a valid DateTime.
                         //Quelle = System.Private.CoreLib
                        //Stapelüberwachung:
                        //bei System.DateTimeParse.ParseExact(ReadOnlySpan`1 s, ReadOnlySpan`1 format, DateTimeFormatInfo dtfi, DateTimeStyles style, TimeSpan & offset)
                        // bei System.DateTimeOffset.ParseExact(String input, String format, IFormatProvider formatProvider, DateTimeStyles styles)
                        // bei Google.Apis.Util.Utilities.GetDateTimeOffsetFromString(String raw)
                        // bei MyApp.Program.Main(String[] args) in Zeile71

                    }

                }

            }

            }
    }
}

Exception Details: Source: System.Private.CoreLib Message: String '2023-10-29T12:00:00+01:00' was not recognized as a valid DateTime. Stack-Trace: at System.DateTimeParse.ParseExact(ReadOnlySpan1 s, ReadOnlySpan1 format, DateTimeFormatInfo dtfi, DateTimeStyles style, TimeSpan& offset) at System.DateTimeOffset.ParseExact(String input, String format, IFormatProvider formatProvider, DateTimeStyles styles) at Google.Apis.Util.Utilities.GetDateTimeOffsetFromString(String raw) at MyApp.Program.Main(String[] args) in C:\Users\Mark\source\repos\ConsoleApp4\ConsoleApp4\Program.cs: Zeile77

jskeet commented 1 year ago

I'll look into this on Monday. I would expect the JSON representation to be always in UTC, but I'll have to check.

MrDust001 commented 1 year ago

Ok thanks!

jskeet commented 1 year ago

Okay, looking at the Discovery doc, I'd expect this to be in UTC. The field is described like this:

    "dateTime": {
     "description": "The time, as a combined date-time value (formatted according to RFC3339). A time zone offset is required unless a time zone is explicitly specified in timeZone.",
     "format": "date-time",
     "type": "string"
    },

The Discovery documentation for date-time says:

An RFC3339 timestamp in UTC time. This in the format of yyyy-MM-ddTHH:mm:ss.SSSZ. The milliseconds portion (".SSS") is optional. Defined in the JSON Schema spec.

That's what the DateTimeOffset property is expecting. We've recently seen another related issue for "google-datetime", in terms of precision - so it's entirely possible that this documentation is incorrect. I'll try to reproduce, then ask internally as to whether this is a Calendar service bug, or a documentation bug. We may need to change the generator to handle "google-datetime" and "date-time" differently (they currently generate calls to the same method) which will delay things a bit, but I'll dig into it.

jskeet commented 1 year ago

Right - I've reproduced the problem, and will file a bug internally to find out what's going on.

MrDust001 commented 1 year ago

Allright, i will keep using the "obsolete" DateTime property for now in my application. Events should default to the calenders Timezone as no other timezone value is given. The only workaround at the moment would be to parse exact with "yyyy-MM-dd'T'HH:mm:sszzz" in my case. Hope you can find out whats going on soon!

jskeet commented 1 year ago

Internal bug: b/308380258

(As an aside, I'll probably want to try to clear up the DateTime-based request properties as well at some point, so you'd specify TimeMinDateTimeOffset instead of TimeMin... but that'll happen a lot later.)

The only workaround at the moment would be to parse exact with "yyyy-MM-dd'T'HH:mm:sszzz" in my case.

I think that would actually be a better workaround for now, to be honest. The DateTime handling is problematic in a variety of ways... and fundamentally what's being represented here is a DateTimeOffset.

MrDust001 commented 1 year ago

Ok i see your point. I'll change my code accordingly. Please let me know - based on your findings - if the format definition will change in future ( yyyy-MM-ddTHH:mm:ss.SSSZ or yyyy-MM-dd'T'HH:mm:sszzz).

jskeet commented 1 year ago

My expectation is that we'll change the documentation to indicate that:

I'll keep this issue up to date.

MrDust001 commented 1 year ago

Allright, thank you!

jskeet commented 1 year ago

This is more complicated than expected - there are fields in the Storage API with a format of "date-time" (e.g. Object.customTime) which apparently do have to be in UTC. In other words, services aren't always handling the data in the same way. Sigh...

MrDust001 commented 1 year ago

Oh yes it is always the same....seemed to be an easy fix in the beginning and turned out to be half of a nightmare afterwards. But i understand that handling different input formats can be tricky. I guess you'll find a fix anyway it will just take more time than expected.

jskeet commented 12 months ago

This should be fixed in version 1.64.0.3171.