首页 > 解决方案 > 如何使用 protobuf-net 将 C# 日期时间转换为 Python 日期时间?

问题描述

我已经使用它的消息结构的原型文件(struct_pb2.py)序列化了一个 C#DateTime.Now对象数组,并在 Python 中打开了该文件。protobuf-net

// The struct definition in C#

    [ProtoContract]
    public struct struct_tick
    {
        [ProtoMember(1)]
        public uint[] arr_currentIndex;

        [ProtoMember(2)]
        public string[] arr_currentType;

        [ProtoMember(3)]
        public DateTime[] arr_currentTime;   // <- for DateTime.Now objects

        public struct_tick(byte size_index, byte size_type, byte size_time)
        {
            arr_currentIndex = new uint[size_index];
            arr_currentType = new string[size_type];
            arr_currentTime = new DateTime[size_time];
        }
    }
syntax = "proto3";

import "google/protobuf/timestamp.proto";

message struct_tick 
{
  repeated uint32 arr_currentIndex  = 1;
  repeated string arr_currentType   = 2;
  repeated google.protobuf.Timestamp arr_currentTime = 3;
}

它在 Python 中打开得很好,但是如何正确地将 C# datetime 对象转换为 Python datetime 对象?让我感到困惑的是文件的日期时间数组中显示的内容。

>>> struct = struct_pb2.struct_tick()
>>> with open(filename, "rb") as f:
>>>     struct.ParseFromString(f.read())

>>> lst_time = [ time for time in struct.arr_currentTime]
>>> lst_time[:5]
[seconds: 1573571465
nanos: 335624000
, seconds: 1573571465
nanos: 335624000
, seconds: 1573571465
nanos: 335624000
, seconds: 1573571465
nanos: 335624000
, seconds: 1573571465
nanos: 335624000
]

>>> lst_time[-5:]
[seconds: 1573571465
nanos: 337636000
, seconds: 1573571465
nanos: 337636000
, seconds: 1573571465
nanos: 337636000
, seconds: 1573571465
nanos: 337636000
, seconds: 1573571465
nanos: 337636000
]

当我在 C# 中读取同一个文件时,第一个 datetime 对象代表 21:59:39.7450630,最后一个对象代表 23:38:50.3848014,这意味着有将近 2 小时的间隔。但是 Python 中显示的内容完全不同。

是不是因为我DateTime在序列化的google.protobuf.Timestamp时候用的,反序列化的时候用的?如何正确转换它们?

添加

这是接收数据并将其写入其结构中的数组的回调函数:


static void Handler_Real(string szCode)
{
    string code          = REAL_TR.GetData("Out", "sym");
    string currentType   = REAL_TR.GetData("Out", "cg");
    DateTime currentTime = DateTime.Now;

    if (dic_codeToTRstructCounter[code] == arraySize)
    {
        dic_codeToTRstructCounter[code] = 0;

        using (var fileStream = new FileStream(dic_codeToTRfilename[code], FileMode.Append))
        {
            Serializer.Serialize(fileStream, dic_codeToTRstruct[code]);
        }
    }

    dic_codeToTRstruct[code].arr_currentIndex[dic_codeToTRstructCounter[code]]  = dic_codeToTRCounter[code];
    dic_codeToTRstruct[code].arr_currentType[dic_codeToTRstructCounter[code]]   = currentType;
    dic_codeToTRstruct[code].arr_currentTime[dic_codeToTRstructCounter[code]]   = currentTime;

    dic_codeToTRstructCounter[code] += 1;
    dic_codeToTRCounter[code] += 1;
}

这就是我在 C# 中读取文件的方式,效果很好。

using (var fileStream = new FileStream("file.bin", FileMode.Open))
{
    struct_tick str = Serializer.Deserialize<struct_tick>(fileStream);

    for (int startNum = 0; startNum < str.arr_currentIndex.Length; startNum++)
    {
        string str_print = string.Format("{0}, {1}, {3}", str.arr_currentIndex[startNum],
                                                          str.arr_currentType[startNum],
                                                          str.arr_currentTime[startNum].ToString("HH:mm:ss.fffffff"));
        listBox1.Items.Add(str_print);
    }
}

这就是我在 Python 中读取相同文件的方式

def convert_TRtoArray(filename):
    struct = struct_pb2.struct_TR()
    with open(filename, "rb") as f:
        struct.ParseFromString(f.read())

    lst_currentIndex  = [  indexNum for indexNum in struct.arr_currentIndex  ]
    lst_currentType   = [  type for type  in struct.arr_currentType ]
    lst_currentTime   = [  time for time in struct.arr_currentTime ]

当我检查时lst_currentTime,虽然 C# 程序已经收到了 2 个小时的数据,但值与上面一样。

标签: c#pythondatetimeprotobuf-net

解决方案


在像 Protobuf 这样的二进制可序列化流中使用 DateTime 不是一个好习惯。最好将 DateTime 值转换为其他值,例如纪元时间甚至字符串,然后对纪元时间或字符串值使用序列化。否则,您将无法正确恢复该字段的内容。


推荐阅读