The above should work, so the question is, what is the content of pData. Do you can share a sample with us?

Also, you can write the above somewhat shorter too and you can access all the properties either via propertyname or via the %Get() method.

I assume, you have a string like this:

set pData="{""Name"":""Joe"", ""Age"":50}"

the you can do this

set object={}.%FromJSON(pData)
write object.Name // Joe
write object.%Get("Name") // Joe
write pData // {"Name":"Joe", "Age":50}

Now we have the year 2020 (but I will discard this year from my life because of Covid-19) but our loved COS wasn't in this year nor in  the very past years invented.

COS (better, the predecessor, M ) has more then 50 years under his belt, it was created in the late sixties - in a time, where RAM was rare, expensive and therefore it was measured in units of kilobyte!

If I recall correctly, at end of the seventies, we had some customers on a PDP-11/34 with less then 64KB of memory, one or two 2kb partitions and some "big" partitions with 4KB or 6KB, the rest was for disk buffers (512 byte each) and DEC's V4b (which acted as OS, database and language interpreter).

Hence the ability of COS for excessive abbreviations and if you get an old routine, written by an old school programmer (like me) then you will see there (mostly) abbreviated commands,  postconditions and (local-/globalvariable, label and routine) names, consisting just a few letters (one to three, maybe four).

Unfortunately, this (abbreviated commands, short names) happens to me in this days too - you know, old habits never die.

There is a wonderful (and at the same time a horrific) example of such a routine: one letter names, everything abbreviated:
https://stackoverflow.com/questions/4151554/need-mumps-sample-code/4430996

clock ;; a digital clock from
;; https://stackoverflow.com/questions/4151554/need-mumps-sample-code/4430996
;;
Q N R,Q,C,D,E,W,B,G,H,S,T,U,V,F,L,P,N,J,A S N=$G(N),Q='N,F=Q+Q,P=F+F,W=$L($T(Q))
 S W=$E(W,Q),S='N_+N,W=W-F*S,L=$G(L),R=$C(Q_F_P),R(F)=$C(F+Q_F),R(P)=$C(W-F) W #
 S T=$E($T(Q+F),F,W\S)_$C(W+S+F) X T S B=$P(T,$C(P_P),F),C=B\(W*W),D=B-(C*W*W)\W
 F G=S-Q:F:S+F+Q S E=B-(C*W*W+(D*W)),H=$E($T(Q),G),@H=$S(@H<S:'Q,Q:N)_@H,T=C_D_E
 F A=Q:Q:W\S S J=$E(T,A),C(F)=$S(J>(F+Q)&(J<(S-F)):Q,Q:+N),C(P)=$S(J#F:Q,Q:+N) D
 .S C(Q)=$S(J<(S-F):+N,Q:Q),C(F+Q)=$S(J>Q&(J<(S-F))&(J'=(P+'L))&(J'=(P)):Q,Q:+N)
 .S H('L)=L F  S H(N?.E)=$O(C(H('$G(N)))) Q:H('+L)=L  S F(A,H('L))=C(H(W[(W\S)))
 F U=Q:Q:P W !,R F V=Q:Q:P+F W $S(F(V,U):'Q,Q:$C(P_(W\S))) W:'(V#F) $C('N_F_F+F)
 W !!,R(F)_C_R(P)_D_R(P)_E_R(F) X $RE($E($T(Q),Q+F,P+Q))_R(P)_'N W # G:N=L Q+F Q

It's not only tricky to read but has an attractive form too

First, I think, you should check the above method...
You use the date variable two times

set date = $piece(...)
return date_" "...


I'm pretty shure, if the time in Vienna (Europe) is 00:30:00 then the coresponding UTC time is 23:30:00 previous day (standard time). But you never change the date variable!
As a timestamp:
2020-08-31T00:30:00+01:00 (Vienna, 31. August)
2020-08-30Z23:30:00 (UTC,  30.August)

Second (but this is just my very privete view), checking time(stamp) format should be done BEFORE calling the ConvertW3CToTimestampUTC() method and not in the method itself.

The holy trinity of programming is:
1) accept data (data input)
2) check the data
3) if the data is OK use it, else back to input (or return an error)

If you accpet data without checking, it means, every time, you intend to use those data, you have to check them again and again (as above), wich is not very efficient.

All ISC products (Ensemble, Cache, IRIS...) have an callin and callout interface via dll/so.  As a starting point, read this

https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.UI...

and this

https://cedocs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?K...

You will also need some experience in C/C++ or Delphi or in other language, where you can compile *.dll (Win) or *.so (Linux) files.

See the functions $zf(-3), $zf(-4), $zf(-5) and $zf(-6)

Create a FindLab() method in your ListLabCenter class, something like:

Method FindLab(start = 0, LabId = "", Center = "", Code = "")

{    set nc1=LabId="", nc2=Center="", nc3=Code=""

     for i=start+1:1:..Labs.Count() {

         set tmp=..Labs.GetAt(i)

         if tmp.LabId=LabId!nc1, tmp.Center=Center!nc2, tmp.Code=Code!nc3 return i

}

   quit 0

}

Then use it as follows:

write obj.FindLab(0,"A08829848","A088298480003","") to find a specific Lab

or 

set  center=0
for  { set center = obj.FindLab(center,,"A088298480003")
       quit:'center
       /* do something with center *./
}

to find all LabCenter objects where Center = "A088298480003"

ISO 8601 time format is either yyyy-mm-ddZhh:mm:ss (UTC time) or yyyy-mm-ddThh:mm:ss+TZ (local time)
where TZ is the time zone.

If both times are UTC time, then just compare.
If the times are local times and both times are in the same TZ then just compare
in elsecase either convert both times to UTC or one of the times to the TZ of the another time.
Then just compare.

The compare function is just a $select(), nothing more:

t1, t2 are the times, then

if $select(t1]t2:"t1 later", t1=t2:"equal", 1:"t1 is earlier")

or more general:

set result=$select(t1]t2:1, t1=t2:0, 1:-1)
if result>0 write "t1 is later then t2"
if result>=0 write "t1 is later or equal to t2"
...

I assume,  your JSON is generated by converting a dynamic object to string, i.e.: 

do obj.%ToJSON()

In elsecase, it's created manually an there you could put as many quotes as you like around the numbers.

For the first case, just make a function which converts the numbers into string, see below:

test ;test for stringify
   set a={},a.Name="John",a.Age=47,a.xx="ab:1234",a.City="Boston",a.Year=2020
   set a."Arr"=[11,22,"aa","bb"]
   set a."Obj"={"aa":"bb"}

   write a.%ToJSON(),!
   write $$stringify(a).%ToJSON(),!
   quit

stringify(x)
{
   set y=x.%GetIterator()
   while y.%GetNext(.i,.v) {
     set t=x.%GetTypeOf(i)
     if t="number" { d x.%Set(i,v,"string") } elseif t="array"!(t="object") { do stringify(v) }
   }
   quit x
}

The output  is then:

do ^test
{"Name":"John","Age":47,"xx":"ab:1234","City":"Boston","Year":2020,"Arr":[11,22,"aa","bb"],"Obj":{"aa":"bb"}}
{"Name":"John","Age":"47","xx":"ab:1234","City":"Boston","Year":"2020","Arr":["11","22","aa","bb"],"Obj":{"aa":"bb"}}

Maybe you want to use TO_DATE(...)  but if you want to use TO_CHAR() then you have to supply a correct argument, which is in this case a $HOROLOG value

SELECT TO_CHAR(0,'mm/dd/yyyy') ---01/12/1840

SELECT TO_CHAR(65575,'mm/dd/yyyy') ---15/07/2020

TO_CHAR(): A string function that converts a date, timestamp, or number to a formatted character string.

TO_DATE(): A date function that converts a formatted string to a date.

As always, it depends on ...
In this case on the definition of the date column.

a) if the date column is defined as %Date (i.e.: Property DateOfBirth As %Date) then the STORED value is just a number like 65567, because dates are stored in $Horolog format). 

b) if the date column is defined (for whatever reason) as %String (i.e.: Property DateOfBirth As %String) then the stored value is (as the type says) a string, and you can use the pattern operator to check the format.So the first question is, how is your date column defined?