PnP Core SDK inside .net core console application, how the date & time format and time zone will be handled for adding and updating Dates Values

john john Pter 320 Reputation points
2024-10-01T18:40:55.73+00:00

I have a sharepoint site with a timezone of UTC+3.

I have 2 hosting servers:-

  1. One with UTC+3.

26BjeW1M

  1. And the second with UTC+1.

m5h39CDs

I created 2 SharePoint lists:-

  1. SourceD
  2. DestinationD

I have this console application where i am trying to understand how the Dates & times timezone and format will be retrieved and set. The console application will do these main actions:-

  1. Retrieve the list item from SourceD list
  2. Show the "D" value using Write-Line
  3. Add a new item inside DestinationD list and show the list item's "D" value.
namespace ConsoleApp4
{
    internal class Program
    {
        static async Task Main(string[] args)
        {
            var tenantId = "**";
            var clientId = "**";
            var certificatePath = @"c:\CERT\***.pfx";
            var certificatePassword = "****";

            // Initialize a new service collection
            var serviceCollection = new ServiceCollection();

            // Load the certificate
            var certificate = new X509Certificate2(certificatePath, certificatePassword, X509KeyStorageFlags.Exportable);

            // Configure logging
            serviceCollection.AddLogging(builder =>
            {
                builder.AddConsole();
            });

            // Add and configure PnP Core SDK
            serviceCollection.AddPnPCore(options =>
            {
                options.PnPContext.GraphFirst = true; // Set true if you prefer to use Graph over CSOM when possible
                                                      // options.HttpRequests.UserAgent = "ISV|Contoso|ProductX";
                options.Sites.Add("SiteToWorkWith", new PnPCoreSiteOptions
                {
                    SiteUrl = "https://**.sharepoint.com/sites/PPM",
                    AuthenticationProvider = new X509CertificateAuthenticationProvider(clientId, tenantId, certificate)
                });
            });

            // Build the service provider
            var serviceProvider = serviceCollection.BuildServiceProvider();

            // Use the service provider to get the IPnPContextFactory instance
            var pnpContextFactory = serviceProvider.GetRequiredService<IPnPContextFactory>();

            // Now you can use the IPnPContextFactory to get a PnPContext and perform operations
            var context = await pnpContextFactory.CreateAsync("SiteToWorkWith");

            var destinationList = context.Web.Lists.GetByTitle("DestinationD", p => p.Title,
                                                                                               p => p.Fields.QueryProperties(
                                                                                               p => p.InternalName,
                                                                                               p => p.FieldTypeKind,
                                                                                               p => p.TypeAsString,
                                                                                               p => p.Title
                                                                                               ));
            var sourceList = context.Web.Lists.GetByTitle("SourceD", p => p.Title,
                                                                 p => p.Fields.QueryProperties(p => p.InternalName,
                                                                                               p => p.FieldTypeKind,
                                                                                               p => p.TypeAsString,
                                                                                               p => p.Title));

            // Build a query that only returns these fields for the Work Orders
            string viewXml = @"<View Scope='RecursiveAll'>
                    <ViewFields>
                      <FieldRef Name='Title' />
                      <FieldRef Name='Created' />
                      <FieldRef Name='FileLeafRef' />
                        <FieldRef Name='D' />
                        <FieldRef Name='Modified' />
                      
                    </ViewFields>
                                        <Query>
                    </Query>
                   <RowLimit Paged='TRUE'>5000</RowLimit>
                   </View>";

            // Load all the needed data using paged requests
            bool paging = true;
            string nextPage = null;
            while (paging)
            {
                var output = await sourceList.LoadListDataAsStreamAsync(new RenderListDataOptions()
                {
                    ViewXml = viewXml,
                    RenderOptions = RenderListDataOptionsFlags.ListData,
                    Paging = nextPage ?? null,
                }).ConfigureAwait(false);

                if (output.ContainsKey("NextHref"))
                {
                    nextPage = output["NextHref"].ToString().Substring(1);
                }
                else
                {
                    paging = false;
                }
            }

       var sourceitems = sourceList.Items.AsRequested()
       .Select(wo =>
       {

           var createdStr = wo["Created"] != null ? wo["Created"].ToString() : null;
           var modifiedStr = wo["Modified"] != null ? wo["Modified"].ToString() : null;
           var dStr = wo["D"] != null ? wo["D"].ToString() : null;

           return new
           {
               c = createdStr,
               m = modifiedStr,
               dStr = dStr
           };
       }).ToList();


            foreach (var item in sourceitems)
            {
                Console.WriteLine(item.dStr);
                Console.WriteLine(DateTime.Parse(item.dStr.ToString()).ToString("yyyy-MM-ddTHH:mm:ssZ"));
                Dictionary<string, object> logitem = new Dictionary<string, object>() {
                    { "Title", DateTime.Now },{"D",item.dStr}
                    };

                var newlogitem = await destinationList.Items.AddAsync(logitem);
                Console.WriteLine(logitem["D"]);
            }

            Console.ReadLine();

            context.Dispose();

        }


    }

I added a column of type Date/Time named "D" inside both lists. Then i added a list item inside the SourceD with this value:-

lGCiMQ39

Where the console application behave as follow:-

  1. On the hosting server with UTC+3, it showed the Date & Time retrieved as follow (08/10/2024 14:30):-

6gFoFzBM and it added a new list item inside the Destination list as follow:-

B6K2fIzu

  1. On the hosting server with UTC+1, it showed the Date & Time retrieved as follow (08/10/2024 13:40) which is one hour behind the sharepoint site and which matches the local server time zone:-

CiDxWYrk

and it raised this error when it tried to add the new item, that it can not find a field named "D":-

VC0e6c8t

So i have those questions:-

  1. So seems the PnP Core SDK will not show the date/times using the SharePoint site timezone and format , but rather the hosting server timezone.. But if this was the case then how adding the new items worked well, i thought it will send the date/time in UTC+3 and sharepoint will assume this is in UTC format.. but PnP core SDK was smart enough to retrieve the Date/Time in local setting but send it to sharepoint after converting ti to UTC.. was this the case?
  2. Also why i got an error when i tried to save the list item on the second hosting server , that it can not find a field with internal name = "D"?

Any advice please? Thanks

SharePoint Development
SharePoint Development
SharePoint: A group of Microsoft Products and technologies used for sharing and managing content, knowledge, and applications.Development: The process of researching, productizing, and refining new or existing technologies.
2,968 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Xyza Xue_MSFT 24,716 Reputation points Microsoft Vendor
    2024-10-02T02:38:28.1233333+00:00

    Hi @john john Pter ,

    The PnP Core SDK retrieves and sets the date and time values based on the hosting server's timezone, not the SharePoint site timezone. When adding new items, the PnP Core SDK retrieves the date and time in the local setting and sends it to SharePoint after converting it to UTC. This is why adding new items worked well. As for the error when trying to save the list item on the second hosting server, it was likely due to the field internal name being incorrect. It is important to ensure that the internal name of the field is correct.


    If the answer is helpful, please click "Accept as Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.t when trying to save list items.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.