Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?
On 2022-04-16 20:35:22 -, Jon Ribbens via Python-list wrote: > On 2022-04-16, Peter J. Holzer wrote: > > On 2022-04-16 14:22:04 -, Jon Ribbens via Python-list wrote: > >> ... although now having looked into the new 'zoneinfo' module slightly, > >> it really should have a giant red flashing notice at the top of it > >> saying "BEWARE, TIMEZONES IN PYTHON ARE UTTERLY BROKEN, NEVER USE THEM". > >> > >> Suppose we do this: > >> > >> >>> import datetime, zoneinfo > >> >>> LOS_ANGELES = zoneinfo.ZoneInfo('America/Los_Angeles') > >> >>> UTC = zoneinfo.ZoneInfo('UTC') > >> >>> d = datetime.datetime(2020, 10, 31, 12, tzinfo=LOS_ANGELES) > >> >>> print(d) > >> 2020-10-31 12:00:00-07:00 > >> >>> d1 = d + datetime.timedelta(days=1) > >> >>> print(d1) > >> 2020-11-01 12:00:00-08:00 > >> > >> d1 is *wrong*. > > > > No, this is correct. That's the result you want. > > I can categorically guarantee you it is not. But let's put it a > different way, if you like, if I want to add 24 hours, i.e. 86,400 > seconds (or indeed any other fixed time period), to a timezone-aware > datetime in Python, how do I do it? What you *should* be able to do is use datetime.timedelta(hours=24). Unfortunately, you can't, because somebody decided to add a normalization rule to timedelta which turns this into timedelta(days=1, hours=0). > It would appear that, without converting to UTC before doing the > calculation, you can't. When doing calculations of this kind I frankly prefer converting to "seconds since the epoch" and doing simple arithmetic. (Yes, leap seconds, I know .. I just ignore those) > > So why didn't this work for me (I also used Python 3.9)? My guess is > > that astimezone() doesn't pick the correct time zone. > > astimezone() doesn't pick a time zone at all. It works out the current > local offset from UTC. The timezone object it returns also includes a timezone string ("CET" in my example). So it's not *just* the offset. The result is misleading, though. You get something which looks like it's a timezone object for Central European Time, but isn't. > It doesn't know anything about when or if that > offset ever changes. astimezone() doesn't have to. It just has to pick the correct timezone object. That object then knows about offset changes. > >> timedelta(days=1) is 24 hours (as you can check by > >> calling timedelta(days=1).total_seconds() ), > > > > It shouldn't be. 1 Day is not 24 hours in the real world. > > Nevertheless, timedelta is a fixed time period so that is the only > definition possible. Yeah, you keep repeating that. I think we are talking at cross-purposes here. You are talking about how timedelta is implemented while I'm talking what semantics it *should* have. > >> It appears that with Python it's not so much a guideline as an > >> absolute concrete rule, and not because programmers will introduce > >> bugs, but because you need to avoid bugs in the standard library! > > > > As a programmer you must always adapt to the problem. Saying "I must do > > it the wrong way because my library is buggy" is just lazy. > > I didn't say any of that. I said you must do it the conservative way, > and it's not "my library" that's buggy, it's the language's built-in > *standard library* that's buggy. With "your library" I meant "the library you have" not "the library you wrote". And while having a buggy (or just badly designed) standard library is especially annoying, you still aren't forced to use it if if doesn't fit your needs. hp -- _ | Peter J. Holzer| Story must make more sense than reality. |_|_) || | | | h...@hjp.at |-- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" signature.asc Description: PGP signature -- https://mail.python.org/mailman/listinfo/python-list
Re: Pre-Pre-PEP: The datetime.timedeltacal class
On 2022-04-17 06:08:54 +1000, Chris Angelico wrote: > On Sun, 17 Apr 2022 at 03:37, Peter J. Holzer wrote: > > Datetime arithmetic in the real world is typically not done in seconds, > > but in calendaric units: Hours, days, weeks, months, years, ... > > The problem is that several of these have varying lengths: > > > > * 1 minute may be 60 or 61 seconds (theoretically also 59, but that > > hasn't happened yet). > > * 1 day can be 23, 24 or 25 hours (unless you are in Troll, Antarctica, > > where it's even weirder). > > I think Troll still only has days that consist of 23-25 hours; the > weird part is that they move their clocks forward for Oslo's summer, > which is their winter. According to Wikipedia they switch between UTC+2 and UTC+0, so the switchover days would be 22 and 26 hours, respectively. > > Therefore a new class (provisionally called timedeltacal, because it is > > calendaric, not absolute) should be added to datetime: > > > > Internally it stores months, days, seconds and microseconds as ints. > > > > The seconds and microseconds split is mostly for compatibility with > > datetime and timedelta. We could store seconds as a float instead. > > > > We don't store minutes since leap seconds aren't usually represented in > > "computer time", so they are unlikely to be useful in a timedeltacal > > object. > > > > Days are stored since they aren't a fixed multiple of any smaller unit. > > Months are stored since they aren't a fixed multiple of any smaller unit. > > > > Hours, weeks and years aren't stored since they are always 60 minutes, 7 > > days and 12 months respectively. > > It sounds like you're planning for annual DST changes, but what about > other shifts? What about when a location adopts standard time, which > could change their UTC offset (yes, I'm aware that most places adopted > standard time before UTC was a thing, but we still usually call it a > UTC offset rather than messing with GMT-UTC changeover) by an > arbitrary amount, even minutes? Yes, I think you are right. I first thought it wouldn't matter because you'd have to look it up in the database anyway, but that's a non-sequitur. Clearly, when you cities switched from local times to timezones, one hour had to be longer or shorter than 3600 seconds. Similarily if India decided to switch to a whole-hour offset, then they would have one hour of 30 or 90 minutes. > It might be cleaner to simply have all of the arguments that datetime > has: year, month, day, hour, minute, second, microsecond (with the > possibility of merging second/usec into a single float). Yup. > > When adding a timedeltacal object to a datetime, the fields are added > > from most to least significant: First a new date is computed by > > advancing the number of months specified [TODO: Research how other > > systems handle overflow (e.g. 2022-01-31 + 1 month: 2022-02-31 doesn't > > exist)] > > Quick test in Pike: [...] > Subtracting seventeen days from today gets us to the 31st of March, > and adding one month to that gives us the 30th of April. Subtracting > eighteen days gets us to the 30th of March, and adding a month to that > _also_ gives us the 30th of April. Same for PostgreSQL. > > then advance the number of days. Finally add the number of > > seconds and microseconds, taking into accout daylight savings time > > switches if the datetime is time zone aware. > > Here's the local DST switchover: [results I expected] > > Subtracting a timedeltacal object from a datetime is the same, just in > > the opposite direction. > > > > Note that t + d - d is in general not equal to t. > > By "in general", do you mean "there will be some odd exceptions", or > "this is usually going to be unequal"? The former. > For instance, going back to the month boundary case, since it's not > possible for "add one month" from two different dates to give the same > result, obviously subtracting a month from that result can't give both > the originals. But for the most part, I would expect t + d - d to be > equal to t, modulo rounding error and possible DST corrections. > Crossing a DST boundary shouldn't break this pattern; only landing in > the actual gap/fold should cause issues. > Is that the intention? Yes, exactly. > > We can't cnange the semantics of datetime - datetime, so there must be a > > function to compute the difference between to datetimes as a > > timedeltacal. It could be a method on datetime (maybe t.sub(u) for t-u > > like in Go) or a constructor which takes two datetime objects. > > > > In any case I think that u + (t - u) == t should hold. [TODO: Check that > > this is possible] > > > > Isn't that the exact same thing as saying that t + d - d == t? No, because the overflow handling isn't reversible. Using the semantics from Pike or Postgres: 2022-03-31 + 1 month == 2022-04-30. But 2022-04-30 - 1 month == 2022-03-30. If "spill over" extra days (IIRC, PHP does that but I'd have to check) 2022-03-31 + 1 month == 2022-05-01 2022-05-01
Re: Pre-Pre-PEP: The datetime.timedeltacal class
On Sun, 17 Apr 2022 at 18:17, Peter J. Holzer wrote: > > On 2022-04-17 06:08:54 +1000, Chris Angelico wrote: > > On Sun, 17 Apr 2022 at 03:37, Peter J. Holzer wrote: > > > Datetime arithmetic in the real world is typically not done in seconds, > > > but in calendaric units: Hours, days, weeks, months, years, ... > > > The problem is that several of these have varying lengths: > > > > > > * 1 minute may be 60 or 61 seconds (theoretically also 59, but that > > > hasn't happened yet). > > > * 1 day can be 23, 24 or 25 hours (unless you are in Troll, Antarctica, > > > where it's even weirder). > > > > I think Troll still only has days that consist of 23-25 hours; the > > weird part is that they move their clocks forward for Oslo's summer, > > which is their winter. > > According to Wikipedia they switch between UTC+2 and UTC+0, so the > switchover days would be 22 and 26 hours, respectively. Ah, hmm. I'll have to play around with the Antarctica/Troll timezone a bit, but it could be that they track Oslo time when only Norwegians are there, and UTC when there are others? In any case, there are *plenty* of bizarre cases. Whether Troll itself is one of those or not, there certainly is no shortage of weird changeover to be found. > > > Subtracting a timedeltacal object from a datetime is the same, just in > > > the opposite direction. > > > > > > Note that t + d - d is in general not equal to t. > > > > By "in general", do you mean "there will be some odd exceptions", or > > "this is usually going to be unequal"? > > The former. Okay, cool. My lengthy explanation of the question was unnecessary then :) > > Isn't that the exact same thing as saying that t + d - d == t? > > No, because the overflow handling isn't reversible. > > > Or are you saying that, when you subtract two timestamps, you can > > never get one of the odd exceptions that would cause problems? > > Yes. > Perfect then. So if I've understood correctly, what you're looking for is a thing that can be added onto a timezone-aware datetime which will have the semantics of adding onto each component individually, and then normalizing. That seems internally consistent, and useful. It's also a natural continuation of Python's migration from "datetime kinda sorta supports timezones, but only if you get a third-party package" to "datetime actually does support timezones" (in the same way that Pike and PostgreSQL do). ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: Pre-Pre-PEP: The datetime.timedeltacal class
Am Sun, Apr 17, 2022 at 11:10:01AM +1200 schrieb Greg Ewing: > On 17/04/22 9:17 am, Karsten Hilbert wrote: > > Take this medication for 1 month ! > > > >is quite likely to mean "take it for 28 days". > > Except when your doctor prescribes 90 days worth of tablets, It *still* means "take for 28 days" :-) Karsten -- GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B -- https://mail.python.org/mailman/listinfo/python-list
Re: Pre-Pre-PEP: The datetime.timedeltacal class
On 2022-04-17 10:15:54 +0200, Peter J. Holzer wrote: > On 2022-04-17 06:08:54 +1000, Chris Angelico wrote: > > On Sun, 17 Apr 2022 at 03:37, Peter J. Holzer wrote: > > > Therefore a new class (provisionally called timedeltacal, because it is > > > calendaric, not absolute) should be added to datetime: > > > > > > Internally it stores months, days, seconds and microseconds as ints. > > > > > > The seconds and microseconds split is mostly for compatibility with > > > datetime and timedelta. We could store seconds as a float instead. > > > > > > We don't store minutes since leap seconds aren't usually represented in > > > "computer time", so they are unlikely to be useful in a timedeltacal > > > object. > > > > > > Days are stored since they aren't a fixed multiple of any smaller unit. > > > Months are stored since they aren't a fixed multiple of any smaller unit. > > > > > > Hours, weeks and years aren't stored since they are always 60 minutes, 7 > > > days and 12 months respectively. > > > > It sounds like you're planning for annual DST changes, but what about > > other shifts? What about when a location adopts standard time, which > > could change their UTC offset (yes, I'm aware that most places adopted > > standard time before UTC was a thing, but we still usually call it a > > UTC offset rather than messing with GMT-UTC changeover) by an > > arbitrary amount, even minutes? > > Yes, I think you are right. I first thought it wouldn't matter because > you'd have to look it up in the database anyway, but that's a > non-sequitur. Clearly, when you cities switched from local times to > timezones, one hour had to be longer or shorter than 3600 seconds. > Similarily if India decided to switch to a whole-hour offset, then they > would have one hour of 30 or 90 minutes. Thinking about it some more (while writing test cases) I've changed my mind again. I think "1 hour" should always be 3600 seconds (disregarding leap seconds), not "the time until the hour hand has advanced by 30° and the minute hand is in the same position". If I sit at a bar at 00:30 on the last Sunday in March, and I continue to sit there for 2 hours, then it's 03:30 when I get out of the bar, not 02:30. 02:30 doesn't even exist. That might be considered an inconsistency, but I think it "does the right thing" in most cases. hp -- _ | Peter J. Holzer| Story must make more sense than reality. |_|_) || | | | h...@hjp.at |-- Charles Stross, "Creative writing __/ | http://www.hjp.at/ | challenge!" signature.asc Description: PGP signature -- https://mail.python.org/mailman/listinfo/python-list