Skip to content
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

How do I get an Instant from a SystemDateTime #146

Closed
spacemanspiff2007 opened this issue Jul 8, 2024 · 8 comments
Closed

How do I get an Instant from a SystemDateTime #146

spacemanspiff2007 opened this issue Jul 8, 2024 · 8 comments
Labels
question Further information is requested

Comments

@spacemanspiff2007
Copy link

Before 0.6 I called LocalSystemDateTime(...).as_utc() to get an UTCDateTime.
Now UTCDateTime Is called Instant and LocalSystemDateTime is called SystemDateTime,
however it's unclear how I can get it to normalize.
I thought the Idea is to normalize timestamps to Instant and do all calculations there.
Is this a misunderstanding from my side?

@spacemanspiff2007 spacemanspiff2007 changed the title How to I get an Instant from a SystemDateTime How do I get an Instant from a SystemDateTime Jul 8, 2024
@ariebovenberg
Copy link
Owner

ariebovenberg commented Jul 8, 2024

Hi @spacemanspiff2007, thanks for reaching out. Let me see if I understand your use case correctly:

if:

  • you have a date and time in the system timezone
  • and you would like to find the corresponding (unambiguous) moment on the timeline

then: starting with SystemDateTime and using .instant() is the way to go.

# example: local system set to Europe/Amsterdam
>>> my_dt = SystemDateTime(2023, 4, 1, 12)
SystemDateTime(2023-04-01T12:00:00+02:00)
>>> my_dt.instant()
Instant(2023-04-01T10:00:00Z)

I thought the Idea is to normalize timestamps to Instant and do all calculations there.

In general, yes—if your doing calculations in "exact" units like hours, minutes, seconds etc. If you'd like to do calendar arithmetic (like adding months, calendar days) you need to consider more carefully: you may be better off doing arithmetic on the .date() first.


The Instant is the "normalized" type. It strips all concepts of local time away. The old UTCDateTime still kept concepts like "months" which didn't make sense.

edit: clarifications

@ariebovenberg ariebovenberg added the question Further information is requested label Jul 8, 2024
@spacemanspiff2007
Copy link
Author

spacemanspiff2007 commented Jul 8, 2024

Thank you for your quick and thorough reply.
Yes - my goal is to do "exact" calculations so thank you for the confirmation that I am on the right track.
I missed the function because it does not seem to align with the other names:
to_tz, to_system_to and to_fixed_offset.
Imho it would make sense to rename it as to_instant - what do you think?

Edit:
Can you elaborate why is it not possible to replace parts of the time any more?
If I want to have the next full second it's now only possible like this:

now = Instant.now()
target = (now + TimeDelta(seconds=1)).subtract(nanoseconds=now.to_system_tz().nanosecond)

@ariebovenberg
Copy link
Owner

@spacemanspiff2007 rounding an Instant is indeed a missing functionality! I'll add a .round() method for this purpose soon, but I'll have to give the API some thought.

About your suggestion: I had named instant() to be consistent with local(), but probably they should both be to_instant() and to_local() to avoid confusion.


BTW: A less hacky workaround for you until then. Still ugly, but handles nanoseconds properly.

now = Instant.now()
target = Instant.from_timestamp(math.ceil(now.timestamp_nanos() / 1_000_000_000))

@ariebovenberg
Copy link
Owner

@spacemanspiff2007 follow-up question that would help me out: What is the reason in particular you need to round an Instant? Is this because you're converting it to a string for another system? Or does your functionality depend on whole seconds?

@spacemanspiff2007
Copy link
Author

I am reworking EAScheduler - an easy to use asyncio scheduler - which lets you run coros/functions at specific points in time.
It's mostly used by HABApp, a smart home rule engine which works with MQTT and/or openHAB.
One option is e.g. to run something at e.g. sunrise or sunset. Since sometimes these timestamps are logged or further propagated it's unnecessary and imho not very pretty to have anything below seconds because it makes the timestamps hard to read.
So I am trying to round the calculated time stamps to the second.
The other use case is testing where I do some calculations which should return the next full second starting from now.
Obviously I can work around both issues by rounding the SystemDateTime and then converting the result to Instant or rework my tests so that they work different. It's just something I stumbled when going from 0.5 to 0.6.2.

Another thing I realized is that Instant.add does not take days as an argument any more. I understand that months is ambiguous so removing that makes sense. Have you removed days because of the leap second?
The SkippedTime and RepeatedTime Exceptions are also hard to find. May I suggest appending an Error suffix so it would be SkippedTimeError and RepeatedTimeError?

@ariebovenberg
Copy link
Owner

ariebovenberg commented Jul 9, 2024

Thanks for explaining, that helps. Rounding methods should be added to the other datetimes as well, I think. In fact, I probably think it'd be best to do this rounding before converting to Instant. This is because Instant (in theory) doesn't have a concept of a 'whole second'. It just identifies a moment on the timeline, and 'whole second' is only determined by local human interpretation. For example, historically sub-second UTC offsets exist (even though TZDB and whenever don't support them): this would mean rounding a second in that location would lead to a different result than rounding in another.


Relating to your suggestion about exception names: While I'm personally not a fan of redundant suffixes, I have to admit I'm in the minority here when it comes to exceptions. I'll probably bundle this with a bunch of other renames in the next release.

edit: I've created an issue to track naming discussions here: #151

@ariebovenberg
Copy link
Owner

I'm closing this issue since the original question has been answered.

Relevant follow-ups:

@spacemanspiff2007
Copy link
Author

I probably think it'd be best to do this rounding before converting to Instant.

I agree! That's how I'm doing it now and it seems to be the most straightforward and logic implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants