protobuf
protobuf copied to clipboard
[Python] Enhancement request: Timestamp from datetime on one line
The google.protobuf.Timestamp
well-known type is very much appreciated, but I've found myself often needing to be able to convert a Python datetime
into a Timestamp
within an expression (especially in list comprehensions). Of course it is easy to knock up a function to do this:
def timestamp_from_datetime(dt):
ts = Timestamp()
ts.FromDatetime(dt)
return ts
But it seems a bit annoying to have to do this. Would it be possible to add a facility to do this directly into Timestamp
? A constructor or static method would be ideal, but even just return self
in FromDatetime()
would do (then we could write the above as Timestamp().FromDatetime(dt)
). The same problem applies to Duration
from timedelta
, although I personally have not used that class.
By the way, I realised that the only time I come across this is as part of building a larger protobuf object. Getting datetime
objects to work directly in their constructor would be even better, for my use case at least:
my_protobuf = MyProtobufMessage(
int_field=3, # fine
list_of_strings=["foo", "bar"], # fine
timestamp=datetime.utcnow(), # error
)
Also it took me a while to find where to import Timestamp from. It was not in the docs. from google.protobuf.timestamp_pb2 import Timestamp
Thank you @seperman. I really wish the documentation was stronger.
I don't like the API consequences of return self
from instance-scope FromDatetime
; I've filed issue 5344 asking for a proper class-scope method so that the developer experience can be my_timestamp_message = timestamp_pb2.Timestamp.FromDatetime(my_datetime)
.
@nathanielmanistaatgoogle Thanks. Actually I agree with you; I said a static method, like you're suggesting "would be ideal" (class methods and static methods only differ in their implementation, not their use, in Python). The return self
thing was just something that "would do" in case Googlers thought it would be easier.
I've also found Timestamp
a pain to work with. If you're using Python 3.7+ and willing to try another plugin then you can check out https://github.com/danielgtaylor/python-betterproto. It just uses Python's timezone-aware datetime.datetime
object. For example, given this proto:
syntax = "proto3";
import "google/protobuf/timestamp.proto";
message Test {
google.protobuf.Timestamp ts = 1;
}
You get this generated outout:
# Generated by the protocol buffer compiler. DO NOT EDIT!
# sources: example.proto
# plugin: python-betterproto
from dataclasses import dataclass
from datetime import datetime
import betterproto
@dataclass
class Test(betterproto.Message):
ts: datetime = betterproto.message_field(1)
Now you can just use it like any normal Python date/time object:
>>> t = Test()
>>> t.ts
datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
>>> t.ts.isoformat()
'1970-01-01T00:00:00+00:00'
>>> from datetime import datetime, timezone
>>> datetime.now(tz=timezone.utc) - t.ts
datetime.timedelta(days=18200, seconds=19110, microseconds=1012)
You can compare against betterproto.DATETIME_ZERO
to see whether it has been modified from the default.
Closing since this to be addressed now per Timestamp.FromDateTime. Feel free to reopen if this still needs further action.
I don't think that solves it (it also looks like documentation for C#), the issue here is that there's no factory/alternate constructor for creating a Timestamp
from a datetime
in a single line, a la:
ts = Timestamp.MakeFromDatetime(dt)
Currently you have to do what OP wrote:
def timestamp_from_datetime(dt):
ts = Timestamp()
ts.FromDatetime(dt)
return ts
It's probably the case that this should've been an alternate constructor from way back when, and now either there has to be an oddly different and worse name for it, or compatibility has to break. I sympathize with you all :sweat_smile:, seems tricky.
@zhangskz camgunz is correct, and I can't reopen the issue (because if a repo owner closes an issue then only a repo owner can reopen it).
or compatibility has to break
To be honest, I think it should just return self. I can't imagine anyone is asserting that FromDatetime
returns a NoneType
@rollo-b2c2 The "compatibility ... break" you've quoted was referring to adding a feature to the constructor. Although, even for that, your point still holds – surely no one is asserting that passing a datetime
to the protobuf Timestamp
constructor should raise an exception!
We triage inactive PRs and issues in order to make it easier to find active work. If this issue should remain active or becomes active again, please add a comment.
This issue is labeled inactive
because the last activity was over 90 days ago.
I'll keep it open; why not?