You might expect PowerShell ConvertTo-Json
produce a JSON representation of a ‘POD’ that can be parsed (in particular, by ConvertFrom-Json
) into a POD object that equals to the previously serialised one. However, this is not true for many cases, the most surprising among which are double
.
Note that those objects aren’t really PODs in PowerShell (.NET), but such metaphor is appropriate.
Numerical data (double
)
This is the most astonishing to me, and is the reason why I wrote this blog entry. Let’s focus on the case of double
s. You might expect ConvertTo-Json
use the R (round-trip) format so that when the string is parsed, it float-point-number-equals (i.e., ==
) the original value.
The sensible deduction above fails, surprisingly due to that R doesn’t really round-trip on x64. For those too lazy to click on the link, use G17 (for double
) or G9 (for float
). This seems to be a bug in .NET and has been fixed in a future (or current?) version of it.
Guid
and Uri
They are converted into string
s, and when converted back, the type information is lost.
@{ 'Uri' = [uri]::new('https://geelaw.blog/');
'Guid' = [guid]::Parse('00000000-0000-0000-c000-000000000046')
} | ConvertTo-Json -Compress;
# {"Guid":"00000000-0000-0000-c000-000000000046","Uri":"https://geelaw.blog/"}
This is of minor problem, as people normally expect GUIDs and URIs to be serialised as strings in JSON.
Exercise. Do you feel the GUID above familiar?
DateTime
and friends
The JSON cmdlets uses a special format to represent a DateTime
as a string
. For example,
[psobject]@{ 'value' =
[datetime]::new(2000, 1, 1, 0, 0, 0, [System.DateTimeKind]::Utc)
} | ConvertTo-Json -Compress;
# {"value":"\/Date(946684800000)\/"}
[psobject]@{ 'value' = '/Date(946684800000)/' } | ConvertTo-Json -Compress;
# {"value":"/Date(946684800000)/"}
Note that when interpreted as plain JSON, value is the string /Date(946684800000)/. However, if you try serialise that string into JSON, ConvertTo-Json
will not escape the (forward) slash. The cmdlets take advantage of this knowledge to keep type information within their little 2-cmdlet world.
Fatal is that the value itself doesn’t round-trip. The problem occurs at the point of conversion to JSON. If you try changing Utc to Local in the example above, you get the same result even if your time-zone is currently not aligned with UTC. ConvertFrom-Json
always treats the string as a UTC DateTime
, but ConvertTo-Json
forgets to convert the value to UTC when serialising it.
Please enable JavaScript to view the comments powered by Disqus.