The first part is easy... string, integer,... that's not the problem.

The second part, is it a date or not depends on the date format(s) you expect (or allow).

But for the first part, you can use this approach:

/// Return values
/// 0=empty, 1=string, 2=integer, 3=float/radix-10, 4=float/radix-2, 5=object
ClassMethod ValType(var) 
{
  if var="" quit 0
  if $isobject(var) quit 5
  quit $select($length(var)>254:1, 1:$translate($ascii($listbuild(var),2),1245678,1122334))
}

Of course, hardcore people would use just one line

ClassMethod ValType(var) { q $s(var="":0, $isobject(var):5, $l(var)>254:1, 1:$tr($a($lb(var),2),1245678,1122334)) }

Just to bring things in the right light

I'm a retired person but one needs some level of activity, that's the reason, why I'm here, do give answers and comments (and if the old customers need "a kind of prolonged help", I'm there too).
In early and mid seventies I programmed some so called "desktop computer", learned Cobol, IBM/360 assembler, Algol60 and Pascal as the preferred language on the university. Then, end of 1977 I met M (DEC's V4B).
Until the nineties thre were no IDEs, the first one I used was Serenji (from GeorgeJames) for MSM and Cache's Studio (with a lovely meat-chopper as the compiler icon). And there were no GitHub.
Anyway, we had great projects and great programms and fun.

The above means, I for myself do not need anything, neither Atelier nor VS-Code not even Studio but in case, I want to edit a class or routine, I prefer Studio.
During my active times, Studio was a great editor (and still it is!), sometimes I had more then one Studio open (at the same time, of course) to different Servers or different namespaces that's the reason why I requested the feature (server defined colors) some decades ago. The light red was the connection into, say a productio system, the green was into  a test namespace and blue, for example was the developmet system. A short glimpse at the display, if I saw red, my brain said, "keep fingers from keyboard", if I saw blue then my brain was ready for switch off... 

But I know several people working since decades with Studio only (and with the line editor before - I hope you know ^% and remember it?). Those people are (roughly) between 50 and 60 years old, worked (and still work) with whatever brand of M-Language (DTM, MSM, ISM, GT-M, Cache etc.) and never had contact to "modern" languages like java, C++, javascript, etc.
That's in my opinion the reason, why Atelier not so widespread as it deserved to be.

De facto, we have a two class society of M-programers

a) the young ones,
- they know everything about the current IDEs (Visual Studio, VS-Code, Eclipse, etc.
- they try to master (more or less) the M-World but
- their heart beats for languages as Java, Javascript, C++, Angular, Scala, etc.
- can't live without Git, GitHub, Bitbucket etc.
- they do not understand the essence/character of M-language (especially Cache/Iris)
- and think, MongoDB is the only NoSql-DB
- work few months (or one or two years) for a company, then change
- in the new company start over with another environment (Java, Angular, whatever)
- many are, I use to say, single-threaded: one project at time only
- etc.

b) and the old ones
- they grew up with the M-language
- they understand the power of M as a unity (language and database)
- most of them never used Git (and similar sites) for version control
- some of them never used a version control at all!
- most of them work with Windows (but this has historical reason)
- a few years before retirement there's no incentive to change to new IDEs

The real problem is not which IDE is in use, the real problem is to get people for M-programming, who then use an IDE. There are, I think, more old(er) then young M-Programer. I know for companies, they search for M-Programers but have dufficulties to find one.
That said, at the end of the day, you have to raise interesse for M-Language and M-Database. So you will need another means and not just a new IDE.
Maybe I'm wrong, but it's like comparing the M-Language and M-Database with a dinner by a start chef.
Nobody asks for the IDE they was in use, nobody asks for the pots and stoves they was in use.
After you leave the restaurant, the only thing that remains is, was the dinner good, were you satisfied.
Same goes the M-Language, does it can all things I need, will I be happy with it.
And yes, my answer is a big yes, definitive.

In my opinion the very first question is the support.
a) Studio
- it's installed (and updated) with Cache/IRIS
- if I have a question, there is WRC
b) VS-Code
- it's not installed with Cache/IRIS
- so I have to care about the installation
- where to get the suitable files (and updates)
- and I have to care about the "how to" install it
- in a case of a problem, who am I contacting?
1) the WRC? They will say, it's not our product
2) the community? Are they always (24/7) there?

The current situation with VS-Code and the COS-plugin (my very private opinion) is
1) it is assumed, that one is an experienced user of VS-Code
2) there are no installinstuctions and user manuals

ad 1):
assume, one day ISC says "VS-Code with COS plugin exists, so we can drop Studio". What should happen to all those COS-programers, how should they master VS-Code? Most of them have never ever heard about VS-Code? Keep in mind, not everybody grew up with mother's breast in one hand and an App in another !

ad 2):
yes, there are some YouTube videos. On all videos I saw, VC-Code was already installed

Do not get me wrong, I'm not again VS-Code (the truth is, I would like to use it on my Linux) and I'm not for keeping Studio until eternity (because there is no Studio for Linux).
But currently, Studio has some advantage (again, for me):
- it's installed
- I can have (and yes, I have) several connections
- I can give each connection a different (background) color
- I have the WRC (but I never had a Studio issue)

You are wondering about a SLOW production server and a FAST development machine?

I show you, how to turn your machines (production or development or both) into  a SLOW and FAST systems  by using your own measurement method.

ClassMethod Unclean()
{
   s p=##class(digi.packet).%OpenId("packet||5237")
   d ..runme4()
} 

ClassMethod Clean()
{
   d ..runme4()
}

Login to either of your systems and try the abowe methods in a terminal session. On my local system (of course, with an own persistent class)  the one method is 12 times faster then the other.

Maybe you have an "Unclean" situation on your development system...

Also, sometime it is worth to put a line like

do $system.OBJ.ShowObjects()

as a first line into the runme4() method

Why do you do make things such complicated?  You neither need  %ListOfDataTypes nor  %ZEN.proxyObject. If I see correctly, at the end of the query you have a characterstream, filled with JSON. Right? So just create this stream on-the-fly!

set json = ##class(%Stream.TmpCharacter).%New(), del=""

  &sql(declare ... )
  &sql(open queryONLWK01)
        
  do json.Write("[")
     for  {
        &sql(fetch queryONLWK01)
        quit:SQLCODE
        do json.Write(del_"{")
        do json.Write("""articlenumber"":" _ articlenumber _ ",") // (*)
        do json.Write("""amount"":" _ amount)
        do json.Write("}")
        set del=","
     }
     do json.WriteLine("]")

(*) if articlenumber is an alphanumeric value then you should do something like this

    do json.Write("""Aarticlenumber"":"_$$json(article)_",")

 where $$json(x) could be something like this ($zconvert() has  no JSON-mode in Cache-2013)
    

json(val) {
   for c="\","/","""",$c(8),$c(9),$c(10),$c(12),$c(13) set val=$replace(val,c,"\"_$tr(c,$c(8,9,10,12,13),"btnfr"))
   for  quit:'$locate(val,"[:cntrl:]",0,j,v)  set $e(val,j-1)="\u"_$e($zh($a(v)+65536),2,5)
   quit """"_$zcvt(val,"O","UTF8")_""""
}

OK, I installed VSCode together with the objectscript extension on my Linux. Now, I would like to play a little bit with this IDE, merlely for an VSCode beginner it's somewhat difficult. According to https://openexchange.intersystems.com/package/VSCode-ObjectScript there is a  settings file, ".vscode/settings.json",  to make a connection to my  iris server...  I located a file  ".config/Code/User/settings.json". After entering the connection info -this works now. Question, how or where can I enter a second (or even more) Cache/Iris servers?  Next, created a short test routine and saved, but it's not compiled. How to compile it?

I have never used VSCode before, I work since beginning with the Cache-Studio (this means some 20 years or so) and other twenty years before with other editors. Is there somewhere a short tutorial or some other info? It seems, I will need some time to catch this "modern" stuff ;-)

Thank you.
 

You could try this way:

Class My.Table2 Extends %Persistent
{

Property Name As %String;

Property Age As %Numeric;

Property City As %String;

Property Phone As %String;

ClassMethod Test()
{
    // This is your Data-Object...
    set data=[]
    do data.%Push({"Name":"Joe", "Age":44, "City":"Boston", "Phone":"1-234-4567"})
    do data.%Push({"Name":"Ron", "Age":48, "City":"Dallas", "Phone":"1-234-5678"})
    do data.%Push({"Name":"Eve", "Age":40, "City":"Miami",  "Phone":"1-234-4567"})
    
    do data.%Push($lb("Tommy", 50, "New York", "1-345-6789"))
    do data.%Push($lb("Alexa", 35, "Portland", "1-567-8901"))

    // Now insert all the above data into your table...
    if 'data.%Size() quit
    
    set cnt=0, size=data.%Size()
    while $i(cnt)<=size {
        set rowData=data.%Get(cnt-1)
        &sql(
            INSERT INTO My.Table2 (Name,Age,City,Phone)
            VALUES (My.Table2_DataProvider(:rowData), :row(2), :row(3), :row(4))
        )
    }
} 

ClassMethod DataProvider(rowData) As %String [ PublicList = row, SqlProc ]
{
    kill row
    if $isobject(rowData) {
        set it=rowData.%GetIterator()
        while it.%GetNext(,.val) { set row($i(row))=val } 

    } else {
        for i=1:1:$ll(rowData) { set row(i)=$lg(rowData,i) }
    }
    quit row(1)
}

Storage Default
{
<Data name="Table2DefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Name</Value>
</Value>
<Value name="3">
<Value>Age</Value>
</Value>
<Value name="4">
<Value>City</Value>
</Value>
<Value name="5">
<Value>Phone</Value>
</Value>
</Data>
<DataLocation>^My.Table2D</DataLocation>
<DefaultData>Table2DefaultData</DefaultData>
<IdLocation>^My.Table2D</IdLocation>
<IndexLocation>^My.Table2I</IndexLocation>
<StreamLocation>^My.Table2S</StreamLocation>
<Type>%Library.CacheStorage</Type>
} }

Create your data for insert and then

INSERT into yourtable (Prop1, Prop2, ...)

VALUES (sqlProcForTheFirstValue(), :localVarForOtherValues(2), :localVatForOtherValues(3),...)

see the above example.

Take care of the sequence of INSERT names and row(i) values.

Sorry, but it's not clear to me what you want to achieve.

If you want to provide data if somebody connected to your server,  then use the DC.Upload class (see below).

If somebody has data for you and you want to programatically download this data, use the DC.Download class (see below).

The examples below does not handle the case, where the (Cache/IRIS)Server needs an user authentication (my IRIS  System > Security Management > Web Applications is set to "Unauthenticated")

Server side (Upload)

/// Upload (i.e. provide) data to a remote party
Class DC.Upload Extends %CSP.Page
{
ClassMethod OnPage() As %Status
{
   if %request.Data("myData")]"" {
      do %request.Data("myData").OutputToDevice()
      do %request.Data("myData").%Close() }
   else {
      write "<html><head></head><body>",!
      write "Please provide a correct Password and ReportId<br>",!
      write "</body></html>",!
   }
   quit $$$OK
}

ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
{
   if ..chkPsw(), ..chkRpt(.file) {
      set data=##class(%FileBinaryStream).%New()
      set size=##class(%File).GetFileSize(file)
      set name=##class(%File).GetFilename(file)
      do data.LinkToFile(file)
      set %response.ContentType="application/pdf"
      do %response.SetHeader("Content-Disposition","attachment;filename="_name)
      do %response.SetHeader("Content-Length",size)
      set time=$h-1
      set %response.Expires=$zd(time,11)_", "_$zd(time,2)_" 00:00:00 GMT"
      set %request.Data("myData")=data
 
      } else {
         set %request.Data("myData")=""
      }
  
      quit $$$OK
}

ClassMethod chkPsw()
{
   set psw=$g(%request.Data("pswd",1))
   if psw]"" quit 1
   quit 0
}

ClassMethod chkRpt(name)
{
   set rpt=$g(%request.Data("rpt",1))
   if rpt]"" {
      set name="/tmp/outfiles/74LS13.pdf"
      quit 1
   }
   quit 0
} 

}

Client side (download)

/// Download (i.e. get) data from remote server
/// 
Class DC.Download Extends %RegisteredObject
{
ClassMethod GetFile(psw, rpt, saveTo = "/tmp/inpfiles/")
{
   set http=##class(%Net.HttpRequest).%New()
   set http.Server="localhost"
   set http.Port=52773
   do http.SetParam("pswd",psw)
   do http.SetParam("rpt",rpt)

   if http.Get("/csp/user/DC.Upload.cls") {
      set file=$piece($g(http.HttpResponse.Headers("CONTENT-DISPOSITION")),"=",2)
      set del=$select($zversion(1)=2:"\", 1:"/")
      set file=saveTo_$s($e(saveTo,*)=del:"",1:del)_$s(file="":"noname.dat",1:file)
      
      open file:"nwu":0
      if $t {
         use file
         do http.HttpResponse.Data.OutputToDevice()
         close file
         quit 1

      } else {
        quit "0,Can't open "_file
      }

   } else {
       quit "0,"_http.HttpResponse.StatusLine
   }
} 
}


Create a temp table with all properties  you need, store it in a Cachte/IRIS-Temp unde $J of the running job (it could be, your applcation runs in several instances at the same time) an use it in your INSERT / UPDATE.

This is your Table

Class My.Table1 Extends %Persistent
{
Property Name As %String;
Property Age As %Numeric;

ClassMethod Test()
{
  d ##class(My.Temp).%DeleteId($j)
  s tmp=##class(My.Temp).%New()
  s tmp.TempID=$j, tmp.Name="Paul", tmp.Age=69
  d tmp.%Save()
  // or popolate the My.Temp via INSERT...  

  &sql(INSERT INTO My.Table1 (Name,Age)
       SELECT Name,Age FROM My.Temp WHERE TempID=$j
      )
}
}

and this is the Temporary Table

Class My.Temp Extends %Persistent
{
  Parameter DEFAULTGLOBAL = "^CacheTemp.TempTable"; Property TempID As %Integer;
  Property Name As %String;
  Property Age As %Numeric;

  Index main On TempID [ IdKey ];

}

Do I understand you right, you want to get the Value of a VALUELIST as a return value of a method? If yes, then the answer is yes.

Class Some.Class

{

Property Status As %String  (VALUELIST = ",1,2,3,4"); 

Property Rating As %String(VALUELIST = ",Bad,Good,Excellent");

/// For the Status property only
ClassMethod StatusValues() As %String [ CodeMode = objectgenerator ]
{
 for i=%class.Properties.Count():-1:0 if i,%class.Properties.GetAt(i).Name="Status" quit

 set val=$select(i:%class.Properties.GetAt(i).Parameters.GetAt("VALUELIST"), 1:"")

 do %code.WriteLine($c(9)_"quit """_val_"""")
} 

/// For all properties with a VALUELIST parameter

ClassMethod Values(prop) [ CodeMode = objectgenerator ]
{
 set sel=""
 for i=1:1:%class.Properties.Count() {
     set val=%class.Properties.GetAt(i).Parameters.GetAt("VALUELIST")
     set:val]"" sel=sel_""""_%class.Properties.GetAt(i).Name_""":"""_val_""", "
 }
 do %code.WriteLine($c(9)_"quit $case(prop,"_sel_":"""")")
}

}

And a few examples...

Write ##class(Some.Class).StatusValues()  ==> ,1,2,3

Write ##class(Some.Class).Values("Status") ==> ,1,2,3

Write ##class(Some.Class).Values("Rating") ==> Bad,Good,Excellent

Write ##class(Some.Class).Values("OtherProperty") ==>

not a built-in, but you can easily create one
 

ClassMethod ParamList() [ CodeMode = objectgenerator ] As %List
{
set params=""
for i=1:1:%class.Parameters.Count() set params=params_$lb(%class.Parameters.GetAt(i).Name)
do %code.WriteLine($c(9)_"quit """_params_"""")
} 

ClassMethod ParamString() As %String
{
quit $listtostring(..ParamList())
}

$listbuild() and all other functions, like $length(), $char() etc.  are  (I call them) basic  functions of COS and have nothing to do with objects. The language of Cache (and of course IRIS )  handles data as  raw (basic) data and not as objects, like some other (but not all) languages.

For example, in JavaScript you can do

 var  text="Some text";
 alert("'" + text + "' has "+text.length + " characters");
 alert("'Some text' has " + "Some text".length + " characters");

because both, a (text)variable and a (text)string have an (object)property name 'length'.

Beside the raw data type COS also has object data type and most of the standard COS functions will accept an object property as argument, for example:

Class Test.Class Extends %RegisteredObject
{
Property Data as %String;
}

set text="Some text"
set obj = ##class(Test.Class).%New()
set obj.Data = "Some text";
write $length(text),!
write $length(obj.Data),!
$lb(data1, data2, data3, ... dataN) is built as a string of item1 item2 item3 ... itemN

itemN:= <len> <type> <dataN>

assuming, you are on a little-endian CPU and

l1 = $length(data)
l2 = l1 + 1 // for type byte
l3 = l2 + 1 // for the length itself

then the length is as follows

if l1<=253 then len: <l3>
elseif l1<=65534 len:= <0> <l2-lowbyte> <l2-highbyte>
else len:= <0> <0> <0> <l2-lowbyte-loworderword> ... <l2-highbyte-highorderword>

And don't forget,
$lb(123) is not the same as $lb(1230/10), hence we have a $ls() function!