Creating JSON of DateTime using Introspection

I’m using introspection per below to get JSON of a DateTime property. But the resulting JSON.ToString fails on the SQLDateTime property - possibly due to not correctly escaping the colon characters in the time code. Yet the same code works correctly on Date properties which include the same SQLDateTIme string property. I see similar problems reported on StackOverflow and have tried “double quoting” strings - but no success.

The JSON.toString fails with code 11 - Unrecognized Object: 2009-03-01 08:45:19

Here’s the snippet of code from within get_JSON, based I think on some of Kem’s work. o is object, IsMarked can be ignored, pi is propertyInfo, pt is typeInfo

[code]If pt.name = “Date” And IsMarked Then //date is a class, and prepended with j_

Dim d As date = pi.value(o).DateValue
If d <> Nil Then
js.value(n) = get_json(d, False, compact) //get all properties for date
End If

Elseif pt.name = “DateTime” And isMarked Then

Dim d As dateTime = pi.value(o).DateTimeValue
If d <> Nil Then
js.value(n) = get_json(d, False, compact) //get all properties for date
End If[/code]

Is it still the same issue that was reported in ?

Can you post the code in get_json?

[code]Public Shared Function get_JSON(o as Object, onlyPrefixed as boolean, compact as boolean) as JSONItem
//runs through all the j_ properties for this record and returns the appropriate JSONItem and sub-items.

//each jsonItem created herein is added as a child to top via top.value( pi.name ) = pi.value
//except arrays, where each element in the array is added via an .append

if o = nil then return nil

dim js as new JSONItem
js.Compact = compact

dim ti as Introspection.TypeInfo = Introspection.GetType(o)

for each pi as Introspection.PropertyInfo in ti.GetProperties
//this works for non-array properties - and string values - but not others - need to test for different types of property.
//use typeInfo

//test
'If IsMarkedJSON(pi, True) Then
'If pi.name = "j_dupes" Then Break
'End If

dim pt as Introspection.TypeInfo = pi.PropertyType
dim n as string = replace( pi.name, kPrefix, "")
Dim key As String = pt.FullName

Dim isMarked As Boolean = IsMarkedJSON(pi, onlyPrefixed)

If  pt.isprimitive And IsMarked Then //only create values if needed
  js.value(n) = get_JSON_primitive(o, pi)
  
Elseif pt.IsEnum And IsMarked Then
  js.value(n) = pi.Value(o)
  
elseif pt.IsClass then
  
  If pt.name = "Date" And IsMarked Then //date is a class, and prepended with j_
    
    Dim d As date = pi.value(o).DateValue
    If d <> Nil Then
      js.value(n) = get_json(d, False, compact) //get all properties for date
    End If
    
  Elseif pt.name = "DateTime" And isMarked Then
    
    Dim d As dateTime = pi.value(o).DateTimeValue
    If d <> Nil Then
      js.value(n) = get_json(d, False, compact) //get all properties for date
    End If
    
    
  Elseif pt.name = "jsonDictionary" And IsMarked Then
    
    //get all the dictionary key and values
    //this gets the properties for dictionary - BinCount and Count - but doesn't get the key/value pairs
    Dim di As jsonDictionary = pi.value(o)
    If di = Nil Then Continue //empty dictionary
    di.setProp_values //this sets properties based on keys and values
    
    If di <> Nil Then
      js.value(n) = get_json(di, onlyPrefixed, compact)  //this gets the properties for dictionary which should now include j_keys and j_values
    End If
    
  Elseif diClasses.haskey(key) Then  //only if the class is registered
    
    js.value(n) = get_json(pi.Value(o), onlyPrefixed, compact)
    
  End If
  
  
Elseif pt.IsArray And IsMarked  Then
  //each array is addressed at this level
  //only arrays of primitives or json classes are addressed at the next level
  
  js.value(n) = get_JSON_array( o, pi, onlyPrefixed, compact)
  
  
Elseif IsMarked Then
  Break
end

next

return js

End Function
[/code]

I see no problem using sqlDataTime as value for the jsonItem
And I never got any problem reading JSON with sqlDateTime
But maybe I misunderstood your problem

I am trying to save the whole class in JSON using introspection, rather than just the SQLDateTime - I might just revert to that if problems continue.

with some creativity I’ve tested a really simple case and am not having issues with this code (I had to comment out the handling of a few bits I didnt have code for and implement a couple missing methods)

But this works about as I’d expect

Dim d As datetime = DateTime.Now

Dim j As JSONItem = get_JSON(d, False, False)

Dim s As String = j.ToString

and I get

{
  "Day":16,
  "DayOfWeek":3,
  "DayOfYear":168,
  "Hour":16,
  "IsDaylightSavingsTime":true,
  "Minute":45,
  "Month":6,
  "Nanosecond":491469860,
  "Second":49,
  "SecondsFrom1970":1592347549.491469860076904,
  "SQLDate":"2020-06-16",
  "SQLDateTime":"2020-06-16 16:45:49",
  "WeekOfYear":25,
  "Year":2020
}

The error you have above almost makes it seem like the string “2009-03-01 08:45:19” was saved as the name of the object instead of as a property of it

Except that it doesn’t include data from the TimeZone property…

I had to comment out certain portions of code and that may have been a victim of that

EDIT : nope I see why
The code folliwing

elseif pt.IsClass then

doesnt have a specific case to handle the TimeZone type so it skips doing anything with it

I dont know what diClasses dictionary holds so I had commented that out
if that had timezone then that would explain why mine had no TZ data

Calling this (note I HAVE commented some bit out and added an unconditional else for class types at line 72)

Public Shared Function get_JSON(o as Object, onlyPrefixed as boolean, compact as boolean) as JSONItem
  Const kPrefix = ""
  
  //runs through all the j_ properties for this record and returns the appropriate JSONItem and sub-items.
  
  //each jsonItem created herein is added as a child to top via top.value( pi.name ) = pi.value
  //except arrays, where each element in the array is added via an .append
  
  If o = Nil Then 
    Return Nil
  End If
  
  Dim js As New JSONItem
  js.Compact = compact
  
  Dim ti As Introspection.TypeInfo = Introspection.GetType(o)
  
  Dim props() As Introspection.PropertyInfo = ti.GetProperties
  
  For Each pi As Introspection.PropertyInfo In props
    //this works for non-array properties - and string values - but not others  - need to test for different types of property.
    //use typeInfo
    
    //test
    'If IsMarkedJSON(pi, True) Then
    'If pi.name = "j_dupes" Then Break
    'End If
    
    Dim pt As Introspection.TypeInfo = pi.PropertyType
    Dim n As String = Replace( pi.name, kPrefix, "")
    Dim key As String = pt.FullName
    
    Dim isMarked As Boolean = IsMarkedJSON(pi, onlyPrefixed)
    
    If  pt.isprimitive And IsMarked Then //only create values if needed
      js.value(n) = get_JSON_primitive(o, pi)
      
    Elseif pt.IsEnum And IsMarked Then
      js.value(n) = pi.Value(o)
      
    elseif pt.IsClass then
      
      If pt.name = "Date" And IsMarked Then //date is a class, and prepended with j_
        
        Dim d As date = pi.value(o).DateValue
        If d <> Nil Then
          js.value(n) = get_json(d, False, compact) //get all properties for date
        End If
        
      Elseif pt.name = "DateTime" And isMarked Then
        
        Dim d As dateTime = pi.value(o).DateTimeValue
        If d <> Nil Then
          js.value(n) = get_json(d, False, compact) //get all properties for date
        End If
        
        
      Elseif pt.name = "jsonDictionary" And IsMarked Then
        
        Break
        // //get all the dictionary key and values
        // //this gets the properties for dictionary - BinCount and Count - but doesn't get the key/value pairs
        // Dim di As jsonDictionary = pi.value(o)
        // If di = Nil Then Continue //empty dictionary
        // di.setProp_values //this sets properties based on keys and values
        // 
        // If di <> Nil Then
        // js.value(n) = get_json(di, onlyPrefixed, compact)  //this gets the properties for dictionary which should now include j_keys and j_values
        // End If
        
        // Elseif diClasses.haskey(key) Then  //only if the class is registered
      Else
        js.value(n) = get_json(pi.Value(o), onlyPrefixed, compact)
        
      End If
      
      
    Elseif pt.IsArray And IsMarked  Then
      //each array is addressed at this level
      //only arrays of primitives or json classes are addressed at the next level
      
      Break
      'js.value(n) = get_JSON_array( o, pi, onlyPrefixed, compact)
      
      
    Elseif IsMarked Then
      Break
    end
    
    
  next
  
  return js
  
  
  
End Function

with

Dim d As datetime = DateTime.Now

Dim j As JSONItem = get_JSON(d, False, False)

Dim s As String = j.ToString

break

I get

{
  "Day":17,
  "DayOfWeek":4,
  "DayOfYear":169,
  "Hour":13,
  "IsDaylightSavingsTime":true,
  "Minute":34,
  "Month":6,
  "Nanosecond":856222152,
  "Second":49,
  "SecondsFrom1970":1592422489.856222152709961,
  "SQLDate":"2020-06-17",
  "SQLDateTime":"2020-06-17 13:34:49",
  "Timezone":{
    "Abbreviation":"America\\/Edmonton",
    "SecondsFromGMT":-21600
  },
  "WeekOfYear":25,
  "Year":2020
}

which now includes the TZ

Thanks Norman, that helped focus the mind a bit.
It appears the problem was not with DateTime per-se but an array of dateTimes.