-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add TimeStampWithOffset #849
Add TimeStampWithOffset #849
Conversation
Codecov Report
@@ Coverage Diff @@
## master #849 +/- ##
==========================================
+ Coverage 84.03% 84.04% +0.01%
==========================================
Files 113 113
Lines 2893 2896 +3
==========================================
+ Hits 2431 2434 +3
Misses 462 462
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
src/JustSaying.Models/Message.cs
Outdated
TimeStamp = DateTime.UtcNow; | ||
Id = Guid.NewGuid(); | ||
TimeStampWithOffset = DateTimeOffset.Now; | ||
Id = Guid.NewGuid(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to put this into a local, and then reference from there. Otherwise you have the possibility of having, albeit slight in magnitude, probably just a few ticks, differences in the value of the time in the two properties.
Something like:
var now = DateTimeOffset.Now;
TimeStampWithOffset = now;
TimeStamp = now.UtcDateTime;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we perhaps call this something like UtcTimeStamp? Or TimeStampUtc?
That it has an offset is a .net implementation detail - the key bit is as you say, we are explicitly declaring it a UTC timestamp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, do we want to use DateTimeOffset.UtcNow? Or is this expected to be the servers time even if that's not in UTC?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we perhaps call this something like UtcTimeStamp? Or TimeStampUtc?
That it has an offset is a .net implementation detail - the key bit is as you say, we are explicitly declaring it a UTC timestamp.
Hmm I don't know - I think having an offset could be useful sometimes. It gives you some extra informaion (what was the offset where this message was sent) without any loss.
We also can't guarantee it won't be overridden with a different offset.
Note that as currently written, it won't (necessarily) be "UTC" (i.e. offset 0)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renaming it from TimeStamp
would be a breaking change.
I would agree that I'd prefer to just use UTC for both, rather than introduce two different ones that make assumptions about the time zone of the executing machine (which in prod for us will be UTC anyway).
I didn't bring that up initially though as I assumed there was offline conversation between Luke, Stu and Gareth that resulted in this PR using local times in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I had to choose I'd just have it as the UTC offset (so
+00:00
). It's still more informative and it's more-or-less explicit, it just lacks a non-zero offset value, which for for non-UI isn't really a problem IMHO.As "+01:00" in the UK in the summer is just an inference of UK local time to us, it could equally be the time in the Canary Islands. Without specifying the time zone's name you can't be 100% sure of what the offset is specifically referring to anyway.
Not sure I agree Martin. The point is it could tells you what time it was for a relevant party at the time the performed the action, which is extra info. I don't think the name of the timezone is important.
This is moot for us since as you say it will always be UTC and I'm happy to go either way, but local is my preference. @stuart-lang any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to be a bit careful about adding fields to this base class, and only do so when we have a really good reason, and scenarios that make it really worthwhile.
To add some more data, let's consider Australia's timezones. Our servers are located in ap-southeast-2
, which is in Sydney. Australia has three timezones, some of which apply DST, and others that do not, at different times of the year. Given that Menulog is available all over Australia, the local timezone that an order is placed in could be quite different to the timezone that the server that handled that request is in. In this case, using this new field for anything would be quite risky, as the local time could be either ahead or behind the server time - we would need to account for it in any usages of the field. There aren't really any 'safe' assumptions we can make about the relation of the offset time and the server time, if that makes sense, which makes me question its usefulness.
In the above scenario, if we did actually want to capture the local time where the order was placed, I think it would make more sense to be explicit and to use a LocalOrderPlacedAt
DateTimeOffset field on whichever messages that fulfill that flow, which would be populated from an incoming request.
I'm not flat out suggesting we don't do this, just that I think we need some solid scenarios and use cases to support its addition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The key reason for this field isn't to capture something about timezone, it's to ensure we have an unambiguous timestamp available on the message. For JE it is really moot whether we use Now
or UtcNow
because the servers are set to UTC anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The offset is only useful for caring about that specific message at that point in time. You can't use the offset to infer future things from it, as the offset may change during the life of the order, which again makes me wonder how useful it is to have a non-UTC value.
The only truly unambiguous way to represent the time zone is to use its name (e.g. Europe/London
in IANA format).
Sure you can say for a specific event that it happened at a wall-clock time of 09:52 to the user, but you can't rely on the offset to compute other timestamps relative to it (e.g. what is the wall-clock time an hour later), which is what makes me think you might as well just encode it as +00:00
to make it clear it's UTC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It potentially makes things easier like "find all the events that happened between 9 and 5 local time". I have a very weak opinion on this though. If the consensus is for UTC I'll do that. And it's 2 on 1 so far.
Be good to get your thougts on my comment below as well.
First thoughts from me; we need to be really careful about adding non-nullable property to the To be clear, something we are going to be encouraging more is for people to avoid contracts libraries, and have their own local definitions of message type, so it will be common for someone to publish a JustSaying 6 message, and expect it to fully deserialize with a JustSaying 7 message base class. |
That's a good point. And aside from the ability to deserialise, you have the scenario the sender doesn't have it on their schema and it deserialises ok but goes to its default value, with bugs on the consumer side ensuing. I'll change it to nullable. |
src/JustSaying.Models/Message.cs
Outdated
@@ -6,12 +6,14 @@ public abstract class Message | |||
{ | |||
protected Message() | |||
{ | |||
TimeStamp = DateTime.UtcNow; | |||
Id = Guid.NewGuid(); | |||
TimeStampWithOffset = DateTimeOffset.Now; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a problem here. If this is used as a base class on the receiving end and the publisher was using a version that didn't have the property, the ctor is going to set the value to Now and leave it like that.
I guess the publisher should set it if its null. And for those features that don't use the JS publisher, their local publishers will just need to do likewise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we could leave it null in the constructor, and populate it in the library before we send it? That way we keep the init out of the Models lib, and provides a possible extension point for what you were thinking of with other users possibly using a different 'base' TZ.
@@ -247,6 +247,12 @@ private IMessagePublisher GetPublisherForMessage(Message message) | |||
CancellationToken cancellationToken) | |||
{ | |||
attemptCount++; | |||
|
|||
if (message.TimeStampWithOffset == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should move the set of the existing TimeStamp property here as well, so that both are populated at the same time. Given the models package is being versioned as well, we can make that change safely.
It turns out that, by default, |
In a global system, it is far better to be explicit about timestamps and include the offset to remove any ambiguity.
Ideally we could switch
TimeStamp
to useDateTimeOffset
but this would be a breaking change which could have an impact on any message consumers that were expecting an offsetless datetime format.