5 Replies Latest reply on Jul 13, 2017 1:18 PM by Rick Davin

    Timezone in AF SDK




      We have a data ingestion service built using AF SDK, writing values directly to PI Data Archive. The Interface machine (where the AF SDK based ingestion service is running) is in different Time Zone than the PI Data Archive Time Zone.


      Interface Machine Time Zone:

      PI Data Archive Machine Time Zone:


      The data source is sending data in Interface Machine Time Zone (UTC +01:00). Below is snippet of AF SDK code,


      1. Connection to PI Server

      vPIServer = PIServers(QA_PI_SERVER)


      2. Prepare the AF Values collections

      Dim vTagValue As AFValue

      Dim vTagValuesList As List(Of AFValue) = New List(Of AFValue)

      Dim vDateTime As DateTime = Nothing


      vDateTime = CType(''Local Time stamp From Interface Machine', DateTime)


      vTagValue = New AFValue()

      vTagValue.PIPoint = "pi point object'

      vTagValue.Timestamp = New Time.AFTime(vDateTime)

      vTagValue.Value = 10.5




      3. Make UpdateValues call to write data to Data Archive


         vTagWriteErrors = vPIServer.UpdateValues(vTagValuesList, Data.AFUpdateOption.Insert, Data.AFBufferOption.Buffer)

         Console.WriteLine(Now.ToString() & ", Processed " & vTagValuesList.Count & " of Events into PI")

      Catch Ex As Exception

          Console.WriteLine(Now.ToString() & ", Exception while Writing to PI Data Archive: " & Ex.StackTrace)

      End Try


      No exception or errors showing. Also when checking the data in PI SMT from Interface Machine ( Archive Editor with 'Use Client Timezone' setting' ), No values showing up means no values recorded into PI Data Archive.


      Also checked the PI Data Archive Message Log, nothing logged there.


      seems like needs to pass the Timezone information in AF SDK code as PI Data Archive is rejecting UpdateValues call, because of considering as future data. any thoughts ?


      - Thanks, Mukesh

        • Re: Timezone in AF SDK

          Hi Mukeshkumar,

          Could you try using UTC time? because UTC time should be the same even they are in different time zone.



          • Re: Timezone in AF SDK
            Rick Davin

            These lines of code:


            Dim vDateTime As DateTime = Nothing


            vDateTime = CType(''Local Time stamp From Interface Machine', DateTime)


            are problematic.  First off, a DateTime is a structure and really cannot be set to Nothing.  In c#, trying to set it to null creates a compile error.  VB.NET is more forgiving and could not set the vDateTime to NOthing but instead should set it to DateTime.MinValue which is 1/1/0001.


            The second line has a typo using a single quote to end the string.  On closer examination, it has 2 single quotes together at the start of the string to give the illusion of a double quote.  From the image of the interface machine, there was no clean time stamp.  There were scattered pieces of a Date, a Time, and a Time zone.  So I'm really curious about what value you were passing for 'Local Time stamp From Interface Machine' . Can you show us that string?  Can you also show us the Kind property of vDateTime after you assigned its value?


            Why not just be direct with it?  Not just to set it to Now, but use the faster and more direct UtcNow?


            Dim vDateTime as DateTime = DateTime.UtcNow


            But even beyond that why not just skip DateTime and go right to AFTime:


            vTagValue.Timestamp = AFTime.Now


            AFTime.Now calls DateTime.UtcNow under the hood.

            1 of 1 people found this helpful
            • Re: Timezone in AF SDK
              Rick Davin

              Hi Mukeshkumar,


              My earlier suggestion was to just directly use AFTime.Now or DateTime.UtcNow and avoid time strings.  It's still the best, most direct way.


              If you insist on using time strings, I would recommend using the AFTime(String) constructor.  Internally it may call DateTime.Parse() or DateTime.TryParse().  The important thing to remember with AFTime(String) constructor is that if a time string does not contain any timezone information, then the input string will be treated as Local to the client app.


              Granted you could use DateTime.Parse() or DateTime.TryParse() yourself, but it does not have the same rule of treating the input string as Local.  In that case, the resulting DateTime object would have Kind=Unspecified.  If you insist on using time strings and setting them to be DateTime objects first, you should definitely use DateTime.Parse() or DateTime.TryParse() instead of CType().  Then most importantly, since this would have been a Local time string now considered Unspecified, you should immediately call DateTime.SpecifyKind to switch the Kind to Local.  Example:


              Dim vDateTime As DateTime = DateTime.SpecifyKind(DateTime.Parse(input_time_string), DateTimeKind.Local)


              It helps to understand the AFTime(DateTime) constructor.  If the input Kind=Local, then it is correctly honored as Local.  Otherwise (meaning Kind=Utc OR Unspecified), then the DateTime is considered to be UTC.


              You know your code fails because the client time string is considered in the future on the PI Data Archive.  But there is a reasoning of why that happens based on the above.


              1. You create a DateTime object by converting a time string via CType.  The resulting DateTime object will have Kind=Unspecified.  This would be true even if you used DateTime.Parse.
              2. You create an AFTime based on that DateTime with Kind=Unspecified.  Based on AFTime constructor rules, that time is considered to be UTC.


              Hence your code is inputting a Local time string, saying it is Unspecified instead of Local, which sets that local time to be Utc, which now erroneously appears to be a future date.  Suggestions for improvement in order of preference:


              1. Use AFTime.Now to get the current client time
              2. Use DateTime.UtcNow to get the current client time
              3. Use New AFTime(String) to convert local time string to AFTime.
              4. Use DateTime.Parse or DateTime.TryParse to convert local time string to DateTime AND immediately wrap that inside a DateTime.SpecifyKind.