7

データベースに日時があり、Entity Frameworkを使用してデータベースから取得し、JSONAPIを介してDataContractJsonSerializerを介してデータを渡します。

日時フィールドの時刻は、DataContractJsonSerializerで処理されている間、サーバーのローカルタイムゾーンに従って調整されているように見えます。エポックで表現された時間は、予想される時間より1時間進んでいます。DateTime KindはUTCですが、以前はUndefinedであり、同じ問題が発生しました。

私のアプリケーションでは、タイムゾーン間を明示的に変換し、サーバーではなくクライアント側で変換したいと考えています。これはより理にかなっているためです。私の日時の値は整数のような単純な値でなければならないので、この暗黙の機能に驚いています。

ありがとう

4

1 に答える 1

5

DataContractJsonSerializerDateTime.KindがLocalORUnspecificedと等しい場合、タイムゾーン部分(+ zzzz)を出力します。この動作は、KindがUnspecifiedに等しい場合にのみタイムゾーン部分を出力するXmlSerializerとは異なります。

興味がある場合JsonWriterDelegatorは、次のメソッドが含まれているソースを確認してください。

 internal override void WriteDateTime(DateTime value) 
    {
        // ToUniversalTime() truncates dates to DateTime.MaxValue or DateTime.MinValue instead of throwing 
        // This will break round-tripping of these dates (see bug 9690 in CSD Developer Framework)
        if (value.Kind != DateTimeKind.Utc)
        {
            long tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks; 
            if ((tickCount > DateTime.MaxValue.Ticks) || (tickCount < DateTime.MinValue.Ticks))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.JsonDateTimeOutOfRange), new ArgumentOutOfRangeException("value")));
            } 
        }

        writer.WriteString(JsonGlobals.DateTimeStartGuardReader);
        writer.WriteValue((value.ToUniversalTime().Ticks - JsonGlobals.unixEpochTicks) / 10000); 

        switch (value.Kind) 
        { 
            case DateTimeKind.Unspecified:
            case DateTimeKind.Local: 
                // +"zzzz";
                TimeSpan ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime());
                if (ts.Ticks < 0)
                { 
                    writer.WriteString("-");
                } 
                else 
                {
                    writer.WriteString("+"); 
                }
                int hours = Math.Abs(ts.Hours);
                writer.WriteString((hours < 10) ? "0" + hours : hours.ToString(CultureInfo.InvariantCulture));
                int minutes = Math.Abs(ts.Minutes); 
                writer.WriteString((minutes < 10) ? "0" + minutes : minutes.ToString(CultureInfo.InvariantCulture));
                break; 
            case DateTimeKind.Utc: 
                break;
        } 
        writer.WriteString(JsonGlobals.DateTimeEndGuardReader);
    }

私は自分のマシンで次のテストを実行しました

var jsonSerializer = new DataContractJsonSerializer(typeof(DateTime));
var date = DateTime.UtcNow;
        Console.WriteLine("original date = " + date.ToString("s"));
        using (var stream = new MemoryStream())
        {
            jsonSerializer.WriteObject(stream, date);

            stream.Position = 0;
            var deserializedDate = (DateTime)jsonSerializer.ReadObject(stream);
            Console.WriteLine("deserialized date = " + deserializedDate.ToString("s"));

        }

これにより、期待される出力が生成されます。

original date = 2011-04-19T10:24:39
deserialized date = 2011-04-19T10:24:39

したがって、ある時点で、日付は未指定またはローカルである必要があります。

DBからプルした後、次の呼び出しによって種類をUnspecificからUtcに変換します

 entity.Date = DateTime.SpecifyKind(entity.Date, DateTimeKind.Utc);

SpecifyKindそして、私が持っているように、backの戻り値をオブジェクトに割り当てることを忘れないでください

于 2011-04-19T10:25:57.513 に答える