-
Notifications
You must be signed in to change notification settings - Fork 16
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
_KnowsLocal
methods and properties exclusiveness
#190
Comments
Hi @sasanjac, thanks for opening this issue! I agree that this can be a surprise at first. The confusion—I suspect—lies in this contradiction:
This issue comes up often, so I'll probably add a FAQ item. Let me know if this does (not) answer your question. I'm always happy to look at ways to make things more intuitive 😄 |
Yeah ok, that's actually what I guessed. I just got confused, because sometimes it seems to behave as a UTC Datetime and sometimes it just doesn't. |
But I think maybe there should be another Layer (e.g. |
Considering the recurrence of this topic, I'd be interested to hear more about your use case for manipulating individual components of UTC. Persuaded by other libraries and my experience, I came to the conclusion that you rarely ever need to think of UTC in these terms. But it could just be my lack of imagination 😄 In my experience, when I deal in UTC, it's only to perform operations like arithmetic ( >>> i = Instant.now()
i.date() # there is no such thing as the "current date", it's different throughout the world!
>>> i.to_tz("Asia/Tokyo").date()
Date(2024-12-17)
>>> i.to_tz("US/Eastern").date()
Date(2024-12-16)
Have you tried edit: clarifications |
For the last part: Yes that's how I implemented it currently. I think the main goal is to manage real time data from various sources spanning different time zones. The data affects each other so time zones are irrelevant thus I like to use something like But then, maybe you need to do periodic operations on that data e.g. calculating some values aggregated over set timeframes for which you need to calculate the start and end points. For example calculating a mean value since the start of the last quarter hour. I think most real time systems, where timezone does not matter in regards to algorithms is set up in a similar way and therefore it might be nice to have like a specialized |
Thanks for sharing. Your use case makes sense.
Aggregation makes sense, although note that any reference point is essentially arbitrary. The "last quarter hour" only works because every timezone on earth currently defines an offset in 15-minute increments. My initial thoughts are to:
>>> from whenever import Instant, minutes
>>> ref_point = Instant.from_utc(2024, 12, 16, hour=12) # arbitrary!
>>> data = Instant.now()
>>> # put the data point into 15-minute aggregated buckets
>>> data_bucket = int(
... (data - ref_point) # returns a TimeDelta
... / minutes(15) # dividing by another TimeDelta returns a float (i.e. how many times one fits in the other)
... ) |
I can't create the arbitrary reference point because it is dependent on the current point in time. I agree with your argument that it is up to the current time definition. I basically implemented it like this: now = whenever.ZonedDateTime.now("UTC")
minutes = now.minute % 15
start = now.replace(second=0, nanosecond=0, disambiguate="compatible") - whenever.TimeDelta(minutes=minutes) With a designated now = whenever.UTCDateTime.now()
minutes = now.minute % 15
start = now.replace(second=0, nanosecond=0) - whenever.TimeDelta(minutes=minutes) Semantically, this would be in between |
Looking at your case, it looks like you could use something similar to the rounding API in Temporal In # this API doesn't exist (yet)
now = OffsetDateTime.now(0, ignore_dst=True)
now.round(unit="minute", increment=15, mode="floor") |
In previous releases, Aside from adding the rounding API to all
The core dilemma comes to this:
Right now I'm leaning towards option (4). What are your thoughts? |
@ariebovenberg Sorry to butt in here (I'm the author of Jiff), but following along here, it kind of looks like the work around to just used a |
@BurntSushi It'd work for sure—maybe I'm overthinking it. What irks me though is the required disambiguation in edit: clarification |
@BurntSushi butting in is welcome 😄 , would be curious for your thoughts on #173 |
Ah yeah, in Jiff I just make |
I've thought about this a while now and I think we basically have what we need already: To address your comments:
I think
I think the
As above, why is there even a need for that in the first place? But maybe I really don't understand it.
I think that is an already too specific implementation for a specific problem. |
I'm happy to explain. The dilemma is that we either:
Solutions (2) and (3) make here are the docs on the topic. I'm always eager for feedback on its clarity 👂 edit: add UTC remark |
I really don't see the dilemma. As I understand it, However, if I had the information whether UTC-7 is Denver or Phoenix, it should be required to use |
Yes you are right if you are disciplined enough to only use # Taking delivery of a package in Denver. The system records a ISO8601 timestamp
delivery = OffsetDateTime.parse_common_iso("2024-03-09T12:00:00-07:00")
# this calculation *seems* safe, but it isn't!
can_open = delivery.add(hours=24) # "2024-03-10 12:00:00-07:00"
print('IMPORTANT: don't open package until {can_open.local()}') # prints 12:00, but should be 13:00 Having to type edit: typos |
To add, this is also why
Temporal (and Jiff) doesn't have a dedicated
|
I understand your argument and I can totally understand if you keep the logic as it is currently, but in my opinion, that's a user mistake. |
Also, if you keep the logic as is, maybe use |
Absolutely a user mistake, agree. As @BurntSushi mentions it's indeed a hard balancing act to create an API that's "easy to use, hard to misuse".
Could you elaborate on what you mean with "change in logic" and how this would create a clear distinction? |
Allowing arithmetic operations without setting |
@sasanjac in the latest release, 0.6.16, the explicit Pending implementation of rounding (#152), your use case becomes a bit cleaner: now = whenever.ZonedDateTime.now("UTC")
minutes = now.minute % 15
start = now.replace(second=0, nanosecond=0) - whenever.TimeDelta(minutes=minutes) |
perfect, thanks :) |
And how would you feel about a dedicated |
Quite the bold idea, considering the What might be an option is having Just for completeness, utcnow = partial(ZonedDateTime.now, "UTC") # creates a new callable
utcnow() # same as calling ZonedDateTime.now("UTC") What I would be open to is having |
My motivation is not really avoiding being verbose but ensuring being type safe and string literals are somewhat tricky. I would think that using enums for time zones is unfeasible due to the maintenance needed. |
@sasanjac FYI, the latest release as added rounding—also to so you can now do: >>> now = Instant.now()
Instant(2025-02-21 08:54:21Z)
>>> now.round("minute", increment=15, mode="floor")
Instant(2025-02-21 08:45:00Z) See the docs for more info |
Uhh that's cool! I'll check it out, thanks! |
Why are some methods and properties exclusive to
_KnowsLocal
, e.g.minute
,second
,replace()
etc?It's possible to create an
Instant
at an arbitrary point in time, so why is it not possible to set its components to an arbitrary value afterwards?Similarly, why are its components not accessible?
The text was updated successfully, but these errors were encountered: