Работа с датами и временем

Последнее обновление: 24.11.2022

Работа с датами и временем, а также временными интервалами имеет свои особенности, поскольку для типов DateTime, TimeSpan и DateTimeOffset в Protobuf нет примтивных типов, которые напрямую конвертируются в типы .NET. Поэтому Protobuf предоставляет дополнительные расширения:

Тип C#

Тип Protobuf

DateTimeOffset

google.protobuf.Timestamp

DateTime

google.protobuf.Timestamp

TimeSpan

google.protobuf.Duration

Рассмотрим применение этих типов на примере. Допустим, клиент посылает серверу свое имя, и сервис в ответ посылает клиенту приглашение на некоторое мероприятие, а также дату мероприятия и его длительность.

Для описания сообщений и сервиса определим следующий файл proto:

syntax = "proto3";

option csharp_namespace = "GrpcServiceApp";

// импортируем нужные пакеты
import "google/protobuf/duration.proto"; 
import "google/protobuf/timestamp.proto";

package metanit;

message Request{
	string name = 1;
}

message Response{
	string invitation = 1;
	google.protobuf.Timestamp start = 2;
    google.protobuf.Duration duration = 3;
}

service Inviter{
  rpc Invite (Request) returns (Response);
}

Сообщение Request в свойстве name будет содержать имя клиента. Сообщение Response в свойстве invitation хранит текст приглашения. Свойство start представляет начало мероприятия, а свойство duration - его длительность.

При этом дата и время представляет тип google.protobuf.Timestamp, для использования которого импортируется пакет "google/protobuf/timestamp.proto"

Аналогично длительность мероприятия представляет тип google.protobuf.Duration, для которого импортируется пакет "google/protobuf/duration.proto"

Сервис Inviter с помощью метода invite получает сообщение Request и отправляет сообщение Response.

В проекте сервера определим следующий класс сервиса:

using Google.Protobuf.WellKnownTypes; // пространство имен для Timestamp и Duration
using Grpc.Core;

namespace GrpcServiceApp.Services
{
    public class InviterService : Inviter.InviterBase
    {
        public override Task<Response> Invite(Request request, ServerCallContext context)
        {
            // начало мероприятия - условно следующий день 
            var eventDateTime = DateTime.UtcNow.AddDays(1);
            // длительность мероприятия - условно 2 часа
            var eventDuration = TimeSpan.FromHours(2);
            // отправляем ответ
            return Task.FromResult(new Response
            {
                Invitation = $"{request.Name}, приглашаем вас посетить мероприятие",
                Start = Timestamp.FromDateTime(eventDateTime),
                Duration = Duration.FromTimeSpan(eventDuration)
            });
        }
    }
}

В данном случае для краткости сервис просто отправляет простейшее приглашение, в качестве даты мероприятия устанавливается завтрашняя дата, а в качестве длительности мероприятия - 2 часа.

Следует отметить, что сгенерированные свойства в классе C# в реальности не представляют стандартные типы DateTimeOffset, DateTime и TimeSpan, а используют классы Timestamp и Duration из пространства имен Google.Protobuf.WellKnownTypes. Однако эти классы предоставляют методы для преобразования из стандартных типов DateTimeOffset, DateTime и TimeSpan:

Start = Timestamp.FromDateTime(eventDateTime),
Duration = Duration.FromTimeSpan(eventDuration)

Для отправки сервису сообщений в проекте клиента определим следующий код:

using Grpc.Net.Client;
using GrpcClientApp;

// создаем канал для обмена сообщениями с сервером
// параметр - адрес сервера gRPC
using var channel = GrpcChannel.ForAddress("https://localhost:7229");

// создаем клиент
var client = new Inviter.InviterClient(channel);

// посылаем имя и получаем приглашение на мероприятие
var response = await client.InviteAsync(new Request { Name = "Tom" });
var eventInvitation = response.Invitation;
var eventDateTime = response.Start.ToDateTime();
var eventDuration = response.Duration.ToTimeSpan();
// выводим данные на консоль
Console.WriteLine(eventInvitation);
Console.WriteLine($"Начало: {eventDateTime.ToString("dd.MM HH:mm")}   Длительность: {eventDuration.TotalHours} часа");

На стороне клиента мы получаем данные также в виде объектов Timestamp и Duration. Но эти типы также предоставляют методы для обратного преобразования - в типы DateTimeOffset, DateTime и TimeSpan:

var eventDateTime = response.Start.ToDateTime();
var eventDuration = response.Duration.ToTimeSpan();

Запустим сервис, а затем клиент, и клиент получит дату и время и продолжительность мероприятия

Tom, приглашаем вас посетить мероприятие
Начало: 25.11 18:13   Длительность: 2 часа
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850