Буферы протокола: я должен использовать int64 или fixed64 для представления значения .NET DateTime? - PullRequest
7 голосов
/ 08 мая 2009

Мне нужно сериализовать значение .NET DateTime в сообщении буфера протокола.

Мой план - использовать DateTime.ToBinary (), а затем передать в сообщение 64-битное возвращаемое значение. Но я не уверен, что выбрать в качестве типа данных буфера протокола для представления этого.

Полагаю, меня смущает вопрос , когда следует использовать типы данных fixed64 (или sfixed64).

Я предполагаю, что в этом сценарии я бы использовал подписанные типы, поскольку значения, возвращаемые DateTime.ToBinary (), могут быть как отрицательными, так и положительными.

Ответы [ 3 ]

9 голосов
/ 08 мая 2009

Ну, вы определенно хотите, чтобы либо int64, либо sfixed64 справились с подписываемым значением.

Только что выполнив быстрый тест, DateTime.Now.ToBinary() кодируется в 10 байтов с использованием int64, тогда как sfixed64 всегда будет использовать 8 байтов. По сути, кодирование переменной длины отлично подходит для небольших чисел, но становится больше, чем кодирование фиксированной длины для больших чисел. (Это тот же тип компромисса, что и при использовании UTF-8 вместо UTF-16 - символы ASCII можно кодировать в UTF-8 одним байтом, но позже кодовые точки в конечном итоге кодируются как 2, а затем 3 байта, тогда как UTF -16 всегда использует 2 байта для символов в BMP.)

Я предполагаю, что DateTime.ToBinary() значения могут быть достаточно большими (не зная деталей того, что именно они делают), поэтому sfixed64 более уместно.

Имеет ли это смысл?

4 голосов
/ 08 мая 2009

В protobuf-net , я использую подход с градуированной шкалой (и действительно, он обрабатывает все это для вас, если вы просто используете DateTime) - эквивалентный .proto выглядит примерно так:

message DateTime {
  optional sint64 value = 1; // the offset (in units of the selected scale)
                             // from 1970/01/01
  optional TimeSpanScale scale = 2 [default = DAYS]; // the scale of the
                                                     // timespan
  enum TimeSpanScale {
    DAYS = 0;
    HOURS = 1;
    MINUTES = 2;
    SECONDS = 3;
    MILLISECONDS = 4;

    MINMAX = 15; // dubious
  }
}

т.е. если DateTime можно выразить в целых днях, я просто отправляю количество дней с 1970 года и т. д. плюс небольшой маркер к шкале. Это означает, что даты могут быть отправлены немного более эффективно, но на самом деле это не намного дороже для других масштабов.

Лично я бы не использовал ToBinary() - я бы явно использовал смещение известного масштаба из известной эпохи (такой как эпоха unix). Это делает его более переносимым между платформами. Но если вы отправляете (например) только смещение в миллисекунду, то фиксированная шкала обычно будет более эффективной, чем шкала с переменной длиной. Нужны ли вам подписанные или неподписанные, зависит от того, нужны ли вам даты до вашей эпохи; -p

0 голосов
/ 08 мая 2009

Вы должны использовать 64-битное число со знаком не потому, что DateTime может быть отрицательным, а потому, что метод ToBinary возвращает Int64, то есть 64-битное число со знаком.

...