如何将带有DateTime的PSObject正确序列化为JSON?

时间:2014-09-10 14:19:27

标签: json powershell

假设我有一个PSObject,其中包含一个整数和一个我要序列化为JSON的日期,并且收件人能够对其进行反序列化。在Javascript中执行此操作,我得到以下JSON:

JSON.stringify({Date: new Date(), Number: 23})
"{"Date":"2014-09-10T14:11:27.092Z","Number":23}"

JSON.parse(JSON.stringify({Date: new Date(), Number: 23}))
>> Object {Date: "2014-09-10T14:13:28.950Z", Number: 23}

看起来非常标准的JSON,可以通过javascript正确解释。

但是,看来powershell的ConvertTo-JsonDateTime序列化如此不一致,以至于它甚至无法正确地来回转换。为了充分说明这一点:

PS C:\dev> $testObj = New-Object -TypeName PSobject -Property @{ Date = Get-Date; Number = 23; }
PS C:\dev> $testObj

Number Date
------ ----
    23 9/10/2014 9:52:14 AM

PS C:\dev\git\strawman> $testObj | ConvertTo-Json
{
    "Number":  23,
    "Date":  {
                 "value":  "\/Date(1410357134361)\/",
                 "DisplayHint":  2,
                 "DateTime":  "Wednesday, September 10, 2014 9:52:14 AM"
             }
}

PS C:\dev> $testObj | ConvertTo-Json | ConvertFrom-Json

Number Date
------ ----
    23 @{value=9/10/2014 1:52:14 PM; DisplayHint=2; DateTime=Wednesday, September 10, 2014 9:52:14 AM}

它不仅为日期属性生成的JSON根本无效,而且无法通过javascript正确解释,但是PowerShell的ConvertFrom-Json甚至无法正确解释它给它看起来相同的物体。

有没有办法正确地将PSObject DateTime序列化为有效的json,可以被收件人正确反序列化?

1 个答案:

答案 0 :(得分:2)

我最终快速编写了一个函数来将任何PSObject转换为可以转换为更干净的JSON的PSObject:

<#
.SYNOPSIS
    Creates a new PSObject where all properties of the original object that are not able to be
    properly serialized to JSON are converted to a value which can be properly converted to JSON.

    This includes the following types:
    *   DateTime

    This conducts a deep property search
.Example 
    Convert an custom PSObject to have parsable dates in Json

    $customObject = New-Object -TypeName PSobject -Property @{ Date = Get-Date; Number = 23; InnerDate = New-Object -TypeName PSObject -Property @{Date=Get-Date;} }

    ## BAD Json
    PS C:\dev> $customObject | ConvertTo-Json
    {
        "Date":  {
                     "value":  "\/Date(1410372629047)\/",
                     "DisplayHint":  2,
                     "DateTime":  "Wednesday, September 10, 2014 2:10:29 PM"
                 },
        "Number":  23,
        "InnerDate":  {
                          "Date":  {
                                       "value":  "\/Date(1410372629047)\/",
                                       "DisplayHint":  2,
                                       "DateTime":  "Wednesday, September 10, 2014 2:10:29 PM"
                                   }
                      }
    }

    ## Good Json
    PS C:\dev> $customObject | ConvertTo-JsonifiablePSObject | ConvertTo-Json
    {
        "Date":  "2014-09-10T14:10:29.0477785-04:00",
        "Number":  23,
        "InnerDate":  {
                          "Date":  "2014-09-10T14:10:29.0477785-04:00"
                      }
    }

#>
function ConvertTo-JsonifiablePSObject
{
    param
    (
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [PSObject]$Object
    )

    $newObjectProperties = @{}

    foreach ($property in $Object.psobject.properties)
    {
        $value = $property.Value

        if ($property.TypeNameOfValue -eq "System.Management.Automation.PSCustomObject")
        {
            $value = ConvertTo-JsonifiablePSObject -Object $property.Value
        }
        elseif ($property.TypeNameOfValue -eq "System.DateTime")
        {
            $value = $property.Value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK")
        }

        $newObjectProperties[$property.Name] = $value
    }

    return New-Object -TypeName PSObject -Property $newObjectProperties
}