Re: Proposal: Syntax for attribute initialisation in __init__ methods

2022-04-16 Thread dn
On 17/04/2022 09.20, Sam Ezeh wrote:
>> Perhaps I'm missing the point, but what functionality or advantage(s)
>> does this give, over data-classes?
> 
> One advantage is maintaining control over the __init__ function without
> having to write extra code to do so. In the linked discussion from
> python-ideas, it was mentioned that keyword-only and positional-only
> arguments can't be used with dataclasses [1].
> 
>> Maybe Dataclasses are not being used as much as one might hope, but they
>> are relatively new, and many Python-Masters simply carry-on constructing
>> classes the way they have for years...
> 
> I think one concern I have is that even if this is useful, it might
> still fall to the same fate.


Don't be discouraged by that - and that thread was not the first of such
discussions! The way Python is being applied is continually changing...

I'm not sure about the criticism of dataclasses though. Starting with
'explicit over implicit', once a parameter-list is more than two or
three long, shouldn't we be using 'labels' in order to avoid (potential)
confusion, ie keyword-parameters?

This removes the order/sequence of arguments from the list of potential
problems/gotchas one can fall into!

In which case, I'm wondering just how often the criticism applies 'in
real life'?

So, now the question becomes: what are the cases/examples which
require/desire improvement over the 'traditional' __init__ of
attributes, and facilities offered through dataclasses?
-- 
Regards,
=dn
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Jon Ribbens via Python-list
On 2022-04-16, Dennis Lee Bieber  wrote:
> On Sat, 16 Apr 2022 20:35:22 - (UTC), Jon Ribbens
> declaimed the following:
>>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?  It would appear that, without
>>converting to UTC before doing the calculation, you can't.
>
> Which is probably the recommended means to do just that.

Yes, as I've already mentioned it is good advice to always use UTC
when doing date/time calculations and only convert to another timezone
for display. However it is somewhat surprising that Python's datetime
simply *does not work* when doing arithmetic on timezone-aware objects.
It's not "disrecommended", it's straight-up broken.

> The only thing that is most noticeable about UTC is the incorporation
> of leap-seconds.

I've never yet managed to find an application where leap-seconds matter
;-)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Pre-Pre-PEP: The datetime.timedeltacal class

2022-04-16 Thread 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,
they come boxes of 84 (6 cards * 14 tablets), and the pharmacist
dutifully opens a box, cuts off an extra 6 and adds them in.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Chris Angelico
On Sun, 17 Apr 2022 at 08:37, Dennis Lee Bieber  wrote:
> And proposals to make
> DST permanent year round -- so "noon" (1200hrs) is not "noon" (sun at
> zenith) pretty much anywhere.
>

Noon isn't precisely zenith anyway, for several reasons:

1) Time zones synchronize their clocks on the mean noon at some
location. Usually that's approximately close to the most populous part
of the region, but not always - for instance, all of China is on one
timezone, despite spanning 4-5 hours' worth of solar noon.

2) Solar noon migrates around a bit during the year. I don't remember
the exact figures, but if you want to read a sundial with any
precision, you need to take a date-based adjustment.

3) Solar days aren't all 24 hours long anyway.

The clock and calendar should *roughly* correspond to the sun, in that
broadly speaking, 2AM will be in darkness and 2PM will be in sunlight,
and the solstices will land in June and December. But down to the
minute, it's much more useful to synchronize on atomic time than
astronomical.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Dennis Lee Bieber
On Sat, 16 Apr 2022 20:35:22 - (UTC), Jon Ribbens
 declaimed the following:

>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?  It would appear that, without
>converting to UTC before doing the calculation, you can't.
>

Which is probably the recommended means to do just that. UTC is an
international standard (call it a zero-reference). All other time-zones
(and daylight savings time) tend to be local/civil time entities (even if
widely accepted), subject to change by whim of the government (consider,
just in the US alone, there are some states, or even parts of states, that
do not honor the DST change over [I really don't know how my watch would
handle some of those, since it time-syncs with WWV-B, including shifting to
DST when WWV-B includes the flag in its broadcast]). And proposals to make
DST permanent year round -- so "noon" (1200hrs) is not "noon" (sun at
zenith) pretty much anywhere.

The only thing that is most noticeable about UTC is the incorporation
of leap-seconds.


-- 
Wulfraed Dennis Lee Bieber AF6VN
wlfr...@ix.netcom.comhttp://wlfraed.microdiversity.freeddns.org/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Tuple unpacking inside lambda expressions

2022-04-16 Thread Sam Ezeh
> In general, if you're using map() with a lambda function, it's often
simpler to switch to a comprehension.

Oh, of course, completely went past my head.

> [result.process(module, data) for module, data in jobs]

And this works great, thanks!

On Sat, 16 Apr 2022 at 22:42, Chris Angelico  wrote:
>
> On Sun, 17 Apr 2022 at 07:37, Sam Ezeh  wrote:
> >
> > Two questions here.
> >
> > Firstly, does anybody know of existing discussions (e.g. on here or on
> > python-ideas) relating to unpacking inside lambda expressions?
> >
> > I found myself wanting to write the following.
> >
> > ```
> > map(
> > lambda (module, data): result.process(module, data),
> >  jobs
> > )
> > ```
> > However, it's of course not legal Python syntax.
>
> What about:
>
> [result.process(module, data) for module, data in jobs]
>
> (or with () instead of [] around the outside if you want a generator)?
>
> In general, if you're using map() with a lambda function, it's often
> simpler to switch to a comprehension.
>
> ChrisA
> --
> https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Fwd: Proposal: Syntax for attribute initialisation in __init__ methods

2022-04-16 Thread Sam Ezeh
I've just seen Pablo's very recent post on python-ideas so I thought
I'd link it here. [1]

[1]: 
https://mail.python.org/archives/list/python-id...@python.org/message/SCXHEWCHBJN3A7DPGGPPFLSTMBLLAOTX/

Kind Regards,
Sam Ezeh


On Fri, 15 Apr 2022 at 22:57, Ethan Furman  wrote:
>
> On 4/15/22 04:19, Sam Ezeh wrote:
> > Elsewhere, the idea of supporting new syntax to automatically initialise
> > attributes provided as arguments to __init__ methods was raised.
>
> [...]
>
> Good post!  You'll want to send this to python-ideas at some point (that's 
> where most new python features are
> discussed).  This particular desire has come up in the past, so you'll need 
> to do some more research (i.e. find the
> previous threads on python-ideas) so you can answer objections already 
> raised, or find new data supporting/refuting
> previous arguments.
>
> --
> ~Ethan~
> --
> https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Jon Ribbens via Python-list
On 2022-04-16, Peter J. Holzer  wrote:
> On 2022-04-16 14:22:04 -, Jon Ribbens via Python-list wrote:
>> On 2022-04-16, Jon Ribbens  wrote:
>> > On 2022-04-16, Peter J. Holzer  wrote:
>> >> Python missed the switch to DST here, the timezone is wrong.
>> >
>> > Because you didn't let it use any timezone information. You need to
>> > either use the third-party 'pytz' module, or in Python 3.9 or above,
>> > the built-in 'zoneinfo' module.
>>
>> ... 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?  It would appear that, without
converting to UTC before doing the calculation, you can't.

> 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. It doesn't know anything about when or if that
offset ever 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.

>> then it can pretend timezones don't exist and do 'naive' arithmetic.
>
> On the contrary. When a datetime is timezone aware, it must use that
> timezone's rules. Adding one day to a datetime just before a DST switch
> must add 23 or 25 hours, not 24. This is NOT naive.

But it is. It's adding 24 hours and while it's doing so it's naively
assuming that the UTC offset doesn't change during that period. Then
once it's got that naive result it's labelling it with what it thinks
is the timezone data at that time.

Here's another example to prove the point:

>>> LONDON = zoneinfo.ZoneInfo('Europe/London')
>>> d0 = datetime.datetime(2022, 3, 27, 0, tzinfo=LONDON)
>>> print(d0)
2022-03-27 00:00:00+00:00
>>> print(d0 + datetime.timedelta(seconds=3600+1800))
2022-03-27 01:30:00+00:00

That is impossible - 2022-03-27 01:30 is a time that *doesn't exist*
in the Europe/London timezone. At 01:00 the clocks moved instantly
to 02:00 as daylight savings kicked in. So the following is wrong too:

>>> print(d0 + datetime.timedelta(seconds=3600*2))
2022-03-27 02:00:00+01:00

That's not 2 hours after midnight, that's 1 hour after midnight.

Doing the calculations in UTC works of course:

>>> print((d0.astimezone(UTC) + 
datetime.timedelta(seconds=3600+1800)).astimezone(LONDON))
2022-03-27 02:30:00+01:00
>>> print((d0.astimezone(UTC) + 
datetime.timedelta(seconds=3600*2)).astimezone(LONDON))
2022-03-27 03:00:00+01:00

> (There is an ambiguity, though: Should 2021-03-27T12:00 CEST -
> 2021-03-26T12:00 CET return 1 day or 25 hours? Both results are correct,
> and depending on context you might prefer one or the other).

But if you're returning that result as a timedelta then only "25 hours"
is correct (or indeed "1 day 3,600 seconds"), because for a timedelta a
day is 24 hours *by definition*.

>> There is a general guideline that you should always keep and use your
>> datetimes as UTC, only ever using timezones for the purposes of display.
>> Usually this is because it keeps things simpler for the programmer, and
>> hence they are less likely to introduce bugs into their programs.
>
> While I generally do this (and often preach it to my collegues) it must
> be stated that this is only a GENERAL guide line.

Yes, that's what I just said.

>> 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.
-- 
https://mail.python.org/mailman/listinfo/python-list


Fwd: Proposal: Syntax for attribute initialisation in __init__ methods

2022-04-16 Thread Sam Ezeh
> Perhaps I'm missing the point, but what functionality or advantage(s)
> does this give, over data-classes?

One advantage is maintaining control over the __init__ function
without having to write extra code to do so. In the linked discussion
from python-ideas, it was mentioned that keyword-only and
positional-only arguments can't be used with dataclasses [1].

> Maybe Dataclasses are not being used as much as one might hope, but they
> are relatively new, and many Python-Masters simply carry-on constructing
> classes the way they have for years...

I think one concern I have is that even if this is useful, it might
still fall to the same fate.

[1]: 
https://mail.python.org/archives/list/python-id...@python.org/message/SCTXSEKOWDRDGVXXOEB7JUC6WE7XKGMO/


On Fri, 15 Apr 2022 at 22:30, dn  wrote:
>
> On 15/04/2022 23.19, Sam Ezeh wrote:
> ...
>
> Kudos for doing the research!
>
>
> > Some related implementations are attrs, dataclasses and the use of a
> > decorator. And there's potentially a point to be raised that the results
> > from the first query indicate that the @dataclasse decorator is not being
> > used enough. One advantage this proposal offers is control over the
> > arguments that the __init__ function takes.
> >
> > A downside to using a decorator is that it might become difficult to accept
> > arguments that don't need to be assigned to anything.
> >
> > I gave the example of the following code (unlike the above, this is not
> > taken from existing python source code). In this example, a decorator can't
> > assign all of the arguments to attributes or else it would produce code
> > that does something different.
> ...
>
>
> I will support anything which reduces 'boiler-plate' or 'make busy' work!
>
> Perhaps I'm missing the point, but what functionality or advantage(s)
> does this give, over data-classes?
>
> Maybe Dataclasses are not being used as much as one might hope, but they
> are relatively new, and many Python-Masters simply carry-on constructing
> classes the way they have for years...
>
> If data-classes give the impression of being 'syntactic sugar', there's
> no particular need to use them - and certainly no rule or demand.
>
> There are constructs where one might find it easier not to use them.
>
> @dataclass does allow init=False.
>
> There is an argument which says that all data-attributes should be
> 'created' inside an __init__() or __post_init__(), rather than
> 'somewhere', 'later'.
> --
> Regards,
> =dn
> --
> https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Tuple unpacking inside lambda expressions

2022-04-16 Thread Chris Angelico
On Sun, 17 Apr 2022 at 07:37, Sam Ezeh  wrote:
>
> Two questions here.
>
> Firstly, does anybody know of existing discussions (e.g. on here or on
> python-ideas) relating to unpacking inside lambda expressions?
>
> I found myself wanting to write the following.
>
> ```
> map(
> lambda (module, data): result.process(module, data),
>  jobs
> )
> ```
> However, it's of course not legal Python syntax.

What about:

[result.process(module, data) for module, data in jobs]

(or with () instead of [] around the outside if you want a generator)?

In general, if you're using map() with a lambda function, it's often
simpler to switch to a comprehension.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Tuple unpacking inside lambda expressions

2022-04-16 Thread Sam Ezeh
Two questions here.

Firstly, does anybody know of existing discussions (e.g. on here or on
python-ideas) relating to unpacking inside lambda expressions?

I found myself wanting to write the following.

```
map(
lambda (module, data): result.process(module, data),
 jobs
)
```
However, it's of course not legal Python syntax.

The following were potential options but I felt they removed some of
the meaning from the code, making it less understandable for other
people.

```
map(
lambda job: result.process(job[0], job[1]),
 jobs
)
```

```
map(
lambda job: result.process(*job),
jobs
)
```

Secondly, for situations like these, do you have any go-to methods of
rewriting these while maintaining clarity?

Kind Regards,
Sam Ezeh
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Pre-Pre-PEP: The datetime.timedeltacal class

2022-04-16 Thread Karsten Hilbert
Am Sat, Apr 16, 2022 at 07:35:51PM +0200 schrieb Peter J. Holzer:

> So I'll start by gathering some feedback
> here with a rough sketch.

> [TODO: Research how other systems handle overflow
> (e.g. 2022-01-31 + 1 month: 2022-02-31 doesn't exist)],

That is context dependant:

Take this medication for 1 month !

is quite likely to mean "take it for 28 days".

This standing order (Dauerauftrag) is to be run every
months from now on.

will mean "every 1st of the month, regardless of how many
days passed".

Karsten
GNUmed
--
GPG  40BE 5B0E C98E 1713 AFA6  5BC0 3BEA AC80 7D4F C89B
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Chris Angelico
On Sun, 17 Apr 2022 at 05:38, Peter J. Holzer  wrote:
>
> On 2022-04-17 02:46:38 +1000, Chris Angelico wrote:
> > On Sun, 17 Apr 2022 at 02:45, Peter J. Holzer  wrote:
> > > For adding a datetime and timedelta I think the answer is clear.
> > > But subtracting two datetimes is ambiguous.
> > >
> >
> > But if the difference between two datetimes is a timedelta, then
> > surely adding a timedelta to a datetime should give the other
> > datetime? It's just as ambiguous.
>
> To answer the same question in a different way:
>
> No, because the timedelta object is overspecified when applied to a
> specific datetime (when you start at 2022-04-16T21:29, it doesn't matter
> whether you add 7 days or 168 hours) but that extra information matters
> with different starting points. When you subtract two specific
> datetimes, there is no way to extract that extra information. So
> addition and subtraction are not symmetrical.
>

Ah, that's fair. So what you're really saying is that the difference
between two datetimes *isn't* a timedelta, but when we subtract them
and get back a timedelta, we're throwing away information for
simplicity.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Pre-Pre-PEP: The datetime.timedeltacal class

2022-04-16 Thread Chris Angelico
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.

> * 1 month may be 28, 29, 30 or 31 days (let's stick to the Gregorian
>   calendar)
>
> The standard library has a datetime.timedelta class which does store
> days and seconds separately, so somebody seems to have had the right
> idea, but the normalization rules make it impossible to distinguish
> between "1 day plus 1 hour" and "25 hours", and it doesn't deal with
> months at all.
>
> Technically it shouldn't be too hard to "fix" timedelta, but that
> wouldn't be backward compatible and would very likely break existing
> code.

Almost certainly, yes; but I would say that that's because you're not
"fixing" timedelta, you're making a completely different concept. The
existing timedelta measures a difference in time; your proposal
represents a difference between two civil calendar points. So I agree
with your suggestion to make it a new and independent class.

> 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?

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).

> 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:

Pike v8.1 release 15 running Hilfe v3.5 (Incremental Pike Frontend)
> import Calendar.ISO;
> object base = now();
> base;
(1) Result: Fraction(Sun 17 Apr 2022 5:42:15.703571 AEST)
> (base - Day() * 17) + Month();
(2) Result: Fraction(Sat 30 Apr 2022 5:42:15.703571 AEST)
> (base - Day() * 18) + Month();
(3) Result: Fraction(Sat 30 Apr 2022 5:42:15.703571 AEST)
> (base - Day() * 19) + Month();
(4) Result: Fraction(Fri 29 Apr 2022 5:42:15.703571 AEST)
> (base - Day() * 16) + Month();
(5) Result: Fraction(Sun 1 May 2022 5:42:15.703571 AEST)
> (base - Day() * 15) + Month();
(6) Result: Fraction(Mon 2 May 2022 5:42:15.703571 AEST)

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. Other nearby dates given for
reference.

> 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:

> base - Day() * 15;
(7) Result: Fraction(Sat 2 Apr 2022 5:42:15.703571 AEDT)
> base - Day() * 14;
(8) Result: Fraction(Sun 3 Apr 2022 5:42:15.703571 AEST)
> base - Day() * 14 - Hour() * 4;
(9) Result: Fraction(Sun 3 Apr 2022 2:42:15.703571 AEDT)
> base - Day() * 14 - Hour() * 3;
(10) Result: Fraction(Sun 3 Apr 2022 2:42:15.703571 AEST)
> base - Day() * 14 - Hour() * 2;
(11) Result: Fraction(Sun 3 Apr 2022 3:42:15.703571 AEST)
> base - Day() * 14 - Hour() * 1;
(12) Result: Fraction(Sun 3 Apr 2022 4:42:15.703571 AEST)

BTW, even though the "object display" notation (the repr, if you like)
shows some of these in AEST and some in AEDT, internally, they all
have the same timezone: Australia/Melbourne.

(Side point: I've 

Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Peter J. Holzer
On 2022-04-17 02:46:38 +1000, Chris Angelico wrote:
> On Sun, 17 Apr 2022 at 02:45, Peter J. Holzer  wrote:
> > For adding a datetime and timedelta I think the answer is clear.
> > But subtracting two datetimes is ambiguous.
> >
> 
> But if the difference between two datetimes is a timedelta, then
> surely adding a timedelta to a datetime should give the other
> datetime? It's just as ambiguous.

To answer the same question in a different way:

No, because the timedelta object is overspecified when applied to a
specific datetime (when you start at 2022-04-16T21:29, it doesn't matter
whether you add 7 days or 168 hours) but that extra information matters
with different starting points. When you subtract two specific
datetimes, there is no way to extract that extra information. So
addition and subtraction are not symmetrical.

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: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Jon Ribbens via Python-list
On 2022-04-16, Peter J. Holzer  wrote:
> On 2022-04-16 13:47:32 -, Jon Ribbens via Python-list wrote:
>> That's impossible unless you redefine 'timedelta' from being, as it is
>> now, a fixed-length period of time, to instead being the difference
>> between two specific dates and times in specific timezones. Days and
>> months have different lengths depending on when and where you are.
>
> That's what I would have expected it to be. Otherwise, why bother with a
> class when a simple float suffices?
>
> Date arithmetic isn't simple. You need complex data types to implement
> it correctly.
>
>> >> It's an undocumented feature of timedelta that by 'day' it means '86400
>> >> seconds'.
>> >
>> > I'd call that a bug, not a feature:
>>
>> It's the only possible way of implementing it,
>
> It's definitely not the only possible way of implementing it.

It's the only possible way of implementing a fixed time period, which is
what timedelta is (modulo the bugs in 'datetime' I mentioned in my other
post).

>> > Python missed the switch to DST here, the timezone is wrong.
>>
>> Because you didn't let it use any timezone information.
>
> I used astimezone() and it returned something something that Python
> calls "timezone aware" containing time zone information which is
> correct for that time and my location
> (tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET')). Why
> should I expect a "timezone aware" datetime to not be actually timezone
> aware?

I think by "timezone aware" it doesn't mean "timezone aware", it means
"has a specified fixed offset from UTC". Yes this is distinctly sub-optimal.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Chris Angelico
On Sun, 17 Apr 2022 at 03:52, Peter J. Holzer  wrote:
>
> On 2022-04-17 02:46:38 +1000, Chris Angelico wrote:
> > On Sun, 17 Apr 2022 at 02:45, Peter J. Holzer  wrote:
> > > On 2022-04-17 02:14:44 +1000, Chris Angelico wrote:
> > > > So which one is it? Which one do you get when you add days=7 to a 
> > > > datetime?
> > >
> > > For adding a datetime and timedelta I think the answer is clear.
> > > But subtracting two datetimes is ambiguous.
> > >
> >
> > But if the difference between two datetimes is a timedelta, then
> > surely adding a timedelta to a datetime should give the other
> > datetime?
>
> Not necessarily. You might compute the difference for another purpose.
> If you compute a change rate from two gauge readings you would compute
> something like (r1 - r0) / (t1 - t0). You don't intend to add (t1 - t0)
> to any timestamp, so that property would be irrelevant. However, you do
> want something which can be used in a division and which has a
> consistent unit (so one could argue that you don't want a timedelta
> object at all, but a floating point number).
>

True, but logically, it's hard to explain arithmetic when (x - y) + x
!= y. ( And yes, I'm aware that floats can violate that, but the
discrepancy isn't a good thing.)

Your example definitely wants to be measured in UTC, though. It wants
to ignore silly changes of clocks, and just show the amount of time
that passed.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Pre-Pre-PEP: The datetime.timedeltacal class

2022-04-16 Thread Barry


> On 16 Apr 2022, at 18:38, Peter J. Holzer  wrote:
> 
> I intend to take this to python-ideas, but I'm not currently subscribed
> there and I think I should probably do a bit of research before
> proposing something over there. So I'll start by gathering some feedback
> here with a rough sketch.
> 
> 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).
> * 1 month may be 28, 29, 30 or 31 days (let's stick to the Gregorian
>  calendar)
> 
> The standard library has a datetime.timedelta class which does store
> days and seconds separately, so somebody seems to have had the right
> idea, but the normalization rules make it impossible to distinguish
> between "1 day plus 1 hour" and "25 hours", and it doesn't deal with
> months at all.
> 
> Technically it shouldn't be too hard to "fix" timedelta, but that
> wouldn't be backward compatible and would very likely break existing
> code.
> 
> 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.
> 
> 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)], 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.
> 
> 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.
> 
> 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]

Suggest that you start with the use cases that you want supported.
Then you can turn them into a set of tests to check that the solution works.

Barry

> 
>hp
> 
> -- 
>   _  | Peter J. Holzer| Story must make more sense than reality.
> |_|_) ||
> | |   | h...@hjp.at |-- Charles Stross, "Creative writing
> __/   | http://www.hjp.at/ |   challenge!"
> -- 
> https://mail.python.org/mailman/listinfo/python-list
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Pre-Pre-PEP: The datetime.timedeltacal class

2022-04-16 Thread Peter J. Holzer
On 2022-04-16 19:35:51 +0200, Peter J. Holzer wrote:
> Note that t + d - d is in general not equal to t.
> 
> 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.

Just noticed this. Using a method or constructor instead of an operator
adjusting behaviour via additional parameters. 

So for example a parameter "maxunit" could be used to restrict the units
used in the result:

Given:

>>> CET = zoneinfo.ZoneInfo('Europe/Vienna')
>>> t0 = datetime.datetime(2022, 3, 1, tzinfo=CET)
>>> t1 = datetime.datetime(2022, 4, 16, 20, tzinfo=CET)

we could get these results:

>>> timedeltacal(t0, t1, maxunit="month")
timedeltacal(months=1, days=15, seconds=72000)
>>> timedeltacal(t0, t1, maxunit="days")
timedeltacal(days=46, seconds=72000)
>>> timedeltacal(t0, t1, maxunit="seconds")
timedeltacal(seconds=4042800)

(note that 4042800 == 46 * 86400 + 19 * 3600)

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: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Peter J. Holzer
On 2022-04-17 02:46:38 +1000, Chris Angelico wrote:
> On Sun, 17 Apr 2022 at 02:45, Peter J. Holzer  wrote:
> > On 2022-04-17 02:14:44 +1000, Chris Angelico wrote:
> > > So which one is it? Which one do you get when you add days=7 to a 
> > > datetime?
> >
> > For adding a datetime and timedelta I think the answer is clear.
> > But subtracting two datetimes is ambiguous.
> >
> 
> But if the difference between two datetimes is a timedelta, then
> surely adding a timedelta to a datetime should give the other
> datetime?

Not necessarily. You might compute the difference for another purpose.
If you compute a change rate from two gauge readings you would compute
something like (r1 - r0) / (t1 - t0). You don't intend to add (t1 - t0)
to any timestamp, so that property would be irrelevant. However, you do
want something which can be used in a division and which has a
consistent unit (so one could argue that you don't want a timedelta
object at all, but a floating point number).

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


Pre-Pre-PEP: The datetime.timedeltacal class

2022-04-16 Thread Peter J. Holzer
I intend to take this to python-ideas, but I'm not currently subscribed
there and I think I should probably do a bit of research before
proposing something over there. So I'll start by gathering some feedback
here with a rough sketch.

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).
* 1 month may be 28, 29, 30 or 31 days (let's stick to the Gregorian
  calendar)

The standard library has a datetime.timedelta class which does store
days and seconds separately, so somebody seems to have had the right
idea, but the normalization rules make it impossible to distinguish
between "1 day plus 1 hour" and "25 hours", and it doesn't deal with
months at all.

Technically it shouldn't be too hard to "fix" timedelta, but that
wouldn't be backward compatible and would very likely break existing
code.

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.

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)], 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.

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.

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]

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: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Chris Angelico
On Sun, 17 Apr 2022 at 02:45, Peter J. Holzer  wrote:
>
> On 2022-04-17 02:14:44 +1000, Chris Angelico wrote:
> > On Sun, 17 Apr 2022 at 02:03, Peter J. Holzer  wrote:
> > > On the contrary. When a datetime is timezone aware, it must use that
> > > timezone's rules. Adding one day to a datetime just before a DST switch
> > > must add 23 or 25 hours, not 24. This is NOT naive.
> > >
> > > (There is an ambiguity, though: Should 2021-03-27T12:00 CEST -
> > > 2021-03-26T12:00 CET return 1 day or 25 hours? Both results are correct,
> > > and depending on context you might prefer one or the other).
> > >
> >
> > That's exactly the problem. A day IS 24 hours *and* it is the time
> > period required for you to get to the same clock on the following
> > date. It's fundamentally ambiguous.
> >
> > Let's take this out of Python altogether for a moment. Imagine that
> > it's 9AM Thursday. You say to your friend, hey, let's meet up again,
> > same time next week. Are you planning to meet 168 hours later, or at
> > 9AM the following Thursday?
> >
> > OF COURSE you mean 168 hours later. That's what "next week" means.
>
> Of course NOT. It means that only in 50 out of 52 weeks. A 4% error rate
> is more than enough to make me acutely aware that it isn't true in
> general. Also, won't count off 168 hours but look at my calendar/clock.
>
>
> > OF COURSE you're meeting at 9AM the following Thursday. That's what
> > "next week" means.
>
> This. Certainly when meeting a friend. Almost certainly when dealing
> with humans (if they are in a different time zone we may have to agree
> on a time zone for "same time"). For a technical process I *might*
> simplify "1 week" to "168 hours", but only if the spec gives me
> sufficient leeway.
>
>
> > And they can't both be true if DST is changing.
> >
> > So which one is it? Which one do you get when you add days=7 to a datetime?
>
> For adding a datetime and timedelta I think the answer is clear.
> But subtracting two datetimes is ambiguous.
>

But if the difference between two datetimes is a timedelta, then
surely adding a timedelta to a datetime should give the other
datetime? It's just as ambiguous.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Peter J. Holzer
On 2022-04-17 02:14:44 +1000, Chris Angelico wrote:
> On Sun, 17 Apr 2022 at 02:03, Peter J. Holzer  wrote:
> > On the contrary. When a datetime is timezone aware, it must use that
> > timezone's rules. Adding one day to a datetime just before a DST switch
> > must add 23 or 25 hours, not 24. This is NOT naive.
> >
> > (There is an ambiguity, though: Should 2021-03-27T12:00 CEST -
> > 2021-03-26T12:00 CET return 1 day or 25 hours? Both results are correct,
> > and depending on context you might prefer one or the other).
> >
> 
> That's exactly the problem. A day IS 24 hours *and* it is the time
> period required for you to get to the same clock on the following
> date. It's fundamentally ambiguous.
> 
> Let's take this out of Python altogether for a moment. Imagine that
> it's 9AM Thursday. You say to your friend, hey, let's meet up again,
> same time next week. Are you planning to meet 168 hours later, or at
> 9AM the following Thursday?
> 
> OF COURSE you mean 168 hours later. That's what "next week" means.

Of course NOT. It means that only in 50 out of 52 weeks. A 4% error rate
is more than enough to make me acutely aware that it isn't true in
general. Also, won't count off 168 hours but look at my calendar/clock.


> OF COURSE you're meeting at 9AM the following Thursday. That's what
> "next week" means.

This. Certainly when meeting a friend. Almost certainly when dealing
with humans (if they are in a different time zone we may have to agree
on a time zone for "same time"). For a technical process I *might*
simplify "1 week" to "168 hours", but only if the spec gives me
sufficient leeway.


> And they can't both be true if DST is changing.
> 
> So which one is it? Which one do you get when you add days=7 to a datetime?

For adding a datetime and timedelta I think the answer is clear.
But subtracting two datetimes is ambiguous.

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: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Chris Angelico
On Sun, 17 Apr 2022 at 02:03, Peter J. Holzer  wrote:
>
> On 2022-04-16 14:22:04 -, Jon Ribbens via Python-list wrote:
> > 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.
>
> > but d1 is 25 hours later
> > than 'd'. If we do the calculations in UTC instead, it works correctly:
> >
> > >>> print((d.astimezone(UTC) + 
> > datetime.timedelta(days=1)).astimezone(LOS_ANGELES))
> > 2020-11-01 11:00:00-08:00
> >
> > It seems that Python is assuming that if the tzinfo attributes of two
> > datetimes are the same,
>
> There is only one datetime in your examples.
>
> > then it can pretend timezones don't exist and do 'naive' arithmetic.
>
> On the contrary. When a datetime is timezone aware, it must use that
> timezone's rules. Adding one day to a datetime just before a DST switch
> must add 23 or 25 hours, not 24. This is NOT naive.
>
> (There is an ambiguity, though: Should 2021-03-27T12:00 CEST -
> 2021-03-26T12:00 CET return 1 day or 25 hours? Both results are correct,
> and depending on context you might prefer one or the other).
>

That's exactly the problem. A day IS 24 hours *and* it is the time
period required for you to get to the same clock on the following
date. It's fundamentally ambiguous.

Let's take this out of Python altogether for a moment. Imagine that
it's 9AM Thursday. You say to your friend, hey, let's meet up again,
same time next week. Are you planning to meet 168 hours later, or at
9AM the following Thursday?

OF COURSE you mean 168 hours later. That's what "next week" means.

OF COURSE you're meeting at 9AM the following Thursday. That's what
"next week" means.

And they can't both be true if DST is changing.

So which one is it? Which one do you get when you add days=7 to a datetime?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Peter J. Holzer
On 2022-04-16 14:22:04 -, Jon Ribbens via Python-list wrote:
> On 2022-04-16, Jon Ribbens  wrote:
> > On 2022-04-16, Peter J. Holzer  wrote:
> >> Python missed the switch to DST here, the timezone is wrong.
> >
> > Because you didn't let it use any timezone information. You need to
> > either use the third-party 'pytz' module, or in Python 3.9 or above,
> > the built-in 'zoneinfo' module.
> 
> ... 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.

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.


> 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.

> but d1 is 25 hours later
> than 'd'. If we do the calculations in UTC instead, it works correctly:
> 
> >>> print((d.astimezone(UTC) + 
> datetime.timedelta(days=1)).astimezone(LOS_ANGELES))
> 2020-11-01 11:00:00-08:00
> 
> It seems that Python is assuming that if the tzinfo attributes of two
> datetimes are the same,

There is only one datetime in your examples.

> then it can pretend timezones don't exist and do 'naive' arithmetic.

On the contrary. When a datetime is timezone aware, it must use that
timezone's rules. Adding one day to a datetime just before a DST switch
must add 23 or 25 hours, not 24. This is NOT naive.

(There is an ambiguity, though: Should 2021-03-27T12:00 CEST -
2021-03-26T12:00 CET return 1 day or 25 hours? Both results are correct,
and depending on context you might prefer one or the other).

> There is a general guideline that you should always keep and use your
> datetimes as UTC, only ever using timezones for the purposes of display.
> Usually this is because it keeps things simpler for the programmer, and
> hence they are less likely to introduce bugs into their programs.

While I generally do this (and often preach it to my collegues) it must
be stated that this is only a GENERAL guide line. There are many
exceptions, especially when scheduling events in the future. For
example, if want to meet somebody on July 18th, 2023 at 19:00 in Vienna,
Austria, it would be wrong to store that date as 2023-07-18T17:00Z. The
EU has decided to abolish DST, and while I don't expect them to get
around to it within the next year (or maybe ever), it might still
happen. So we simply don't know yet whether 19:00 local time will be
17:00 or 18:00 UTC. There have been cases where countries have changed
their DST rules only days in advance.

> 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. Use a
different library or write one yourself. (Unless of course the customer
doesn't want to pay for the extra work, then they get what they pay
for.)

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: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Peter J. Holzer
On 2022-04-16 13:47:32 -, Jon Ribbens via Python-list wrote:
> On 2022-04-16, Peter J. Holzer  wrote:
> > On 2022-04-14 15:22:29 -, Jon Ribbens via Python-list wrote:
> >> On 2022-04-14, Paul Bryan  wrote:
> >> > I think because minutes and hours can easily be composed by multiplying
> >> > seconds. days is separate because you cannot compose days from seconds;
> >> > leap seconds are applied to days at various times, due to
> >> > irregularities in the Earth's rotation.
> >>
> >> That's an argument that timedelta should *not* have a 'days' attribute,
> >> because a day is not a fixed number of seconds long (to know how long
> >> a day is, you have to know which day you're talking about, and where).
> >
> > Which is exactly why timedelta *must* have separate fields for seconds,
> > days and months. You can't simply express the larger units as
> > multiples of the smaller units, so they have to be stored separately for
> > date arithmetic to work.
> 
> That's impossible unless you redefine 'timedelta' from being, as it is
> now, a fixed-length period of time, to instead being the difference
> between two specific dates and times in specific timezones. Days and
> months have different lengths depending on when and where you are.

That's what I would have expected it to be. Otherwise, why bother with a
class when a simple float suffices?

Date arithmetic isn't simple. You need complex data types to implement
it correctly.


> >> It's an undocumented feature of timedelta that by 'day' it means '86400
> >> seconds'.
> >
> > I'd call that a bug, not a feature:
> 
> It's the only possible way of implementing it,

It's definitely not the only possible way of implementing it. PostgreSQL
for examply has implemented it correctly. I'm quite sure some other
programming languages have, too.


>  from datetime import datetime, timedelta
>  t0 = datetime.fromisoformat("2022-03-26T12:00").astimezone()
>  t0
> > datetime.datetime(2022, 3, 26, 12, 0, 
> > tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
>  d = timedelta(days=1)
>  t1 = t0 + d
>  t1
> > datetime.datetime(2022, 3, 27, 12, 0, 
> > tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
>  t1.isoformat()
> > '2022-03-27T12:00:00+01:00'
> >
> > Python missed the switch to DST here, the timezone is wrong.
> 
> Because you didn't let it use any timezone information.

I used astimezone() and it returned something something that Python
calls "timezone aware" containing time zone information which is
correct for that time and my location
(tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET')). Why
should I expect a "timezone aware" datetime to not be actually timezone
aware?

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: Suggestion for Linux Distro (from PSA: Linux vulnerability)

2022-04-16 Thread Peter J. Holzer
On 2022-04-16 16:49:17 +0200, Marco Sulla wrote:
> Furthermore, you didn't answer my simple question: why does the
> security update package contain metadata about Debian patches, if the
> Ubuntu security team did not benefit from Debian security patches but
> only from internal work?

It DOES NOT contain metadata about Debian patches. You are
misinterpreting the name "debian". The directory has this name because
the tools (dpkg, quilt, etc.) were originally written by the Debian team
for the Debian distribution. Ubuntu uses the same tools. They didn't
bother to rename the directory (why should they?), so the directory is
still called "debian" on Ubuntu (and yes I know this because I've built
numerous .deb packages on Ubuntu systems).

For example, here is the patches directory of one of my own packages:

% ls -l debian/patches
total 24
-rw-r--r-- 1 hjp hjp  982 Sep 12  2017 makefile
-rw-r--r-- 1 hjp hjp  966 Sep 12  2017 makefile-all
-rw-r--r-- 1 hjp hjp  367 Jan 15  2021 makefile-checkmk.diff
-rw-r--r-- 1 hjp hjp  849 Dec 14  2017 makefile-check_cronwrapper
-rw-r--r-- 1 hjp hjp 1126 Sep 12  2017 makefile-mkdir
-rw-r--r-- 1 hjp hjp   86 Jan 15  2021 series

5 patches in the subdirectory debian/patches (the file "series" just
contains the list of patches in proper order). None of these patches was
written by Debian. They were all written by me. Yet they are all in a
subdirectory "debian/patches", because that's where they have to be for
the tools to find them (yes, this is on Ubuntu).

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: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Jon Ribbens via Python-list
On 2022-04-16, Jon Ribbens  wrote:
> On 2022-04-16, Peter J. Holzer  wrote:
>> Python missed the switch to DST here, the timezone is wrong.
>
> Because you didn't let it use any timezone information. You need to
> either use the third-party 'pytz' module, or in Python 3.9 or above,
> the built-in 'zoneinfo' module.

... 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*. timedelta(days=1) is 24 hours (as you can check by
calling timedelta(days=1).total_seconds() ), but d1 is 25 hours later
than 'd'. If we do the calculations in UTC instead, it works correctly:

>>> print((d.astimezone(UTC) + 
datetime.timedelta(days=1)).astimezone(LOS_ANGELES))
2020-11-01 11:00:00-08:00

It seems that Python is assuming that if the tzinfo attributes of two
datetimes are the same, then it can pretend timezones don't exist and
do 'naive' arithmetic. This is of course a totally false assumption.
Apparently when making the native version of 'zoneinfo', the lessons
learned from 'pytz' have been discarded.

There is a general guideline that you should always keep and use your
datetimes as UTC, only ever using timezones for the purposes of display.
Usually this is because it keeps things simpler for the programmer, and
hence they are less likely to introduce bugs into their programs. 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!
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Jon Ribbens via Python-list
On 2022-04-16, Peter J. Holzer  wrote:
> On 2022-04-14 15:22:29 -, Jon Ribbens via Python-list wrote:
>> On 2022-04-14, Paul Bryan  wrote:
>> > I think because minutes and hours can easily be composed by multiplying
>> > seconds. days is separate because you cannot compose days from seconds;
>> > leap seconds are applied to days at various times, due to
>> > irregularities in the Earth's rotation.
>>
>> That's an argument that timedelta should *not* have a 'days' attribute,
>> because a day is not a fixed number of seconds long (to know how long
>> a day is, you have to know which day you're talking about, and where).
>
> Which is exactly why timedelta *must* have separate fields for seconds,
> days and months. You can't simply express the larger units as
> multiples of the smaller units, so they have to be stored separately for
> date arithmetic to work.

That's impossible unless you redefine 'timedelta' from being, as it is
now, a fixed-length period of time, to instead being the difference
between two specific dates and times in specific timezones. Days and
months have different lengths depending on when and where you are.

>> It's an undocumented feature of timedelta that by 'day' it means '86400
>> seconds'.
>
> I'd call that a bug, not a feature:

It's the only possible way of implementing it, so it can't be a bug.
The documentation could be better though.

 from datetime import datetime, timedelta
 t0 = datetime.fromisoformat("2022-03-26T12:00").astimezone()
 t0
> datetime.datetime(2022, 3, 26, 12, 0, 
> tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
 d = timedelta(days=1)
 t1 = t0 + d
 t1
> datetime.datetime(2022, 3, 27, 12, 0, 
> tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
 t1.isoformat()
> '2022-03-27T12:00:00+01:00'
>
> Python missed the switch to DST here, the timezone is wrong.

Because you didn't let it use any timezone information. You need to
either use the third-party 'pytz' module, or in Python 3.9 or above,
the built-in 'zoneinfo' module.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Suggestion for Linux Distro (from PSA: Linux vulnerability)

2022-04-16 Thread Marco Sulla
On Sat, 16 Apr 2022 at 10:15, Peter J. Holzer  wrote:
> It doesn't (or at least you can't conclude that from the evidence you
> posted).
>
> There is a subdirectory called "debian" in the build directory of every
> .deb package. This is true on Debian, Ubuntu and every other
> distribution which uses the .deb package format. This directory is
> required by the build tools and it contains all the data (e.g. build
> instructions, dependencies, patches, description, extra documentation)
> which was added by the packager. The name of the directory does not
> imply that any of the files there was created by Debian. I have built
> quite a few packages myself and I'm not a member of the Debian team.

Actually I don't care if the package was made by Debian. I'm sure that
it does not, since the Ubuntu packages have other terminology in
versions. For example, the git package is version 2.17.1-1ubuntu0.10

The important fact is that I suppose it's quite evident that the
Ubuntu team uses Debian patches to release their security updates,
since the release notes are public and worldwide, made by a
professional company, they are not made by an amateur. Furthermore I
checked all the security updates my system released when we started
this discussion, and all of them have release notes that contain
information about security patches made by Debian. Only the security
updates have these infos. Is it an amazing coincidence? I suppose no.

Furthermore, you didn't answer my simple question: why does the
security update package contain metadata about Debian patches, if the
Ubuntu security team did not benefit from Debian security patches but
only from internal work? I suppose I have to answer myself: because
the patch applied by Ubuntu _is_ actually a Debian patch.

The more interesting fact is that I checked all the security updates
and it seems they are only applications of Debian patches. So it seems
that the work of the Ubuntu security team is only to apply Debian
security patches. If so, probably Debian is really more secure than
Ubuntu, since I don't know if all the security patches made by Debian
are applied.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Why does datetime.timedelta only have the attributes 'days' and 'seconds'?

2022-04-16 Thread Peter J. Holzer
On 2022-04-14 15:22:29 -, Jon Ribbens via Python-list wrote:
> On 2022-04-14, Paul Bryan  wrote:
> > I think because minutes and hours can easily be composed by multiplying
> > seconds. days is separate because you cannot compose days from seconds;
> > leap seconds are applied to days at various times, due to
> > irregularities in the Earth's rotation.
> 
> That's an argument that timedelta should *not* have a 'days' attribute,
> because a day is not a fixed number of seconds long (to know how long
> a day is, you have to know which day you're talking about, and where).

Which is exactly why timedelta *must* have separate fields for seconds,
days and months. You can't simply express the larger units as
multiples of the smaller units, so they have to be stored separately for
date arithmetic to work.

> It's an undocumented feature of timedelta that by 'day' it means '86400
> seconds'.

I'd call that a bug, not a feature:

>>> from datetime import datetime, timedelta
>>> t0 = datetime.fromisoformat("2022-03-26T12:00").astimezone()
>>> t0
datetime.datetime(2022, 3, 26, 12, 0, 
tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
>>> d = timedelta(days=1)
>>> t1 = t0 + d
>>> t1
datetime.datetime(2022, 3, 27, 12, 0, 
tzinfo=datetime.timezone(datetime.timedelta(seconds=3600), 'CET'))
>>> t1.isoformat()
'2022-03-27T12:00:00+01:00'

Python missed the switch to DST here, the timezone is wrong.

If I do the same thing in PostgreSQL:

hjp=> select '2022-03-26T12:00'::timestamptz;
╔╗
║  timestamptz   ║
╟╢
║ 2022-03-26 12:00:00+01 ║
╚╝
(1 row)

Time: 5.542 ms
hjp=> select '2022-03-26T12:00'::timestamptz + '1 day'::interval;
╔╗
║?column?║
╟╢
║ 2022-03-27 12:00:00+02 ║
╚╝
(1 row)

It correctly determines that DST is already in effect at noon of March 27th.

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: Suggestion for Linux Distro (from PSA: Linux vulnerability)

2022-04-16 Thread Peter J. Holzer
On 2022-04-14 19:31:58 +0200, Marco Sulla wrote:
> On Wed, 13 Apr 2022 at 20:05, Peter J. Holzer  wrote:
> >
> > On 2022-04-12 21:03:00 +0200, Marco Sulla wrote:
> > > On Tue, 29 Mar 2022 at 00:10, Peter J. Holzer  wrote:
> > > > They are are about a year apart, so they will usually contain
> > > > different versions of most packages right from the start. So the
> > > > Ubuntu and Debian security teams probably can't benefit much
> > > > from each other.
> > >
> > > Well, this is what my updater on Lubuntu says to me today:
[...]
> > > - debian/patches/CVE-2018-16301.patch: Add check of
[...]
> > > - debian/patches/CVE-2020-8037.patch: Add a limit to the
[...]
> > > I use an LTS version. So it seems that Ubuntu benefits from Debian
> > > security patches.
> >
> > Why do you think so? Because the release notes mention
> > debian/patches/*.patch?
> 
> Of course.
> 
> > This may be an artefact of the build process. The build tools for .deb
> > packages expect all kinds of meta-data to live in a subdirectory called
> > "debian", even on non-debian systems. This includes patches, at least if
> > the maintainer is using quilt (which AFAIK is currently the recommended
> > tool for that purpose).
> 
> And why does the security update package contain metadata about Debian
> patches,

It doesn't (or at least you can't conclude that from the evidence you
posted).

There is a subdirectory called "debian" in the build directory of every
.deb package. This is true on Debian, Ubuntu and every other
distribution which uses the .deb package format. This directory is
required by the build tools and it contains all the data (e.g. build
instructions, dependencies, patches, description, extra documentation)
which was added by the packager. The name of the directory does not
imply that any of the files there was created by Debian. I have built
quite a few packages myself and I'm not a member of the Debian team.

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