Time is a simple thing, right?
And working with it in Python is great.
You just import date time and, somewhat oddly,
use the date time class from that module.
Oh, except there are times with time zones
and times without time zones.
And why is there a total seconds,
but no total minutes, total hours,
or total days on time delta?
How about computing the number of weeks in a time span?
What if you wanted to iterate
over the next 21 workdays, skipping weekends?
All right, we'd better talk about time in Python.
Good thing Paul Gansel is here.
He's a core developer who controls time in CPython.
This is Talk Python to Me, episode 271,
recorded June 18th, 2020.
Welcome to Talk Python to Me,
a weekly podcast on Python,
the language, the libraries, the ecosystem,
and the personalities.
This is your host, Michael Kennedy.
Follow me on Twitter where I'm @mkennedy.
Keep up with the show and listen to past episodes
at talkpython.fm.
And follow the show on Twitter via at Talk Python.
This episode is brought to you by Brilliant.org
and us with our online courses over at Talk Python Training.
Speaking of Talk Python Training,
have you been thinking about taking one of our courses?
We're participating in the latest Humble Bundle deal for Python developers along with a bunch of other great educators and tool developers.
Until July 22nd, you can get $1,400 worth of Python goodies, including three of our popular courses for just $25.
Yeah, Humble Bundles are crazy.
That's $25 for our three courses and all those other things combined.
Just visit talkpython.fm/humble2020.
That's talkpython.fm/humble2020 altogether before July 22nd to take advantage of this offer.
Now, let's get to that interview.
Paul, welcome to Talk Python to me.
Glad to be here.
Yeah, it's great to have you here.
Really excited to talk about the meaning of time and all of that.
Time is really tricky, actually.
Time is one of those things that seems really obvious and simple until it's not.
And then until you start working with it and you're like,
oh, actually that code's running on the server and that server we forgot,
you know, we didn't set the time zone to actually where it is.
So maybe it's UTC.
Maybe it's where the server's located or where our office is.
And all of a sudden you find yourself juggling all these things.
And especially if you're building anything that has to do with calendars or stuff like that,
that's going to be a real adventure.
Yeah, well, I will say that I did not set out to become like the date time guy,
but I think that kind of complexity, like the natural complexity of the subject has,
it's either drawn me in or what's the word for when something gets you stuck,
like in a Kragmire or like a Venus flytrap or something.
It's enticed you in and now it's got you trapped in its world.
Yeah, it certainly seems like a one-way function,
like something barbed where you can move in one direction,
but not in the other direction.
Yeah, for sure.
Well, you know, it's really great that you're working on it.
And just for the listeners, so you're a Python core developer working on basically
times, date times, time spans, that kind of stuff in Python.
Yeah, I think I originally got into it with working on DateUtil.
So I've been maintaining that for about, oh God, now it's like six years.
And, you know, DateUtil has a lot of little minor extensions.
And then when PEP495 came around, the core developers showed up in DateUtil and said,
hey, we kind of used your library as a prototype for how this could work.
So maybe you want to actually implement PEP495.
And then I did that.
And then I had a relationship with the core developers.
And then I just kind of stuck around and started doing more stuff.
And eventually it's one of those things like you never set out to do it.
And I don't even have a job that's particularly date time heavy.
It's just like, if you start monitoring the issue tracker for something like DateUtil or
even CPython, and then specifically just focusing on any one thing, like you'll just learn a stupidly
large amount about edge cases and how everything works.
I can see how that happens.
And it's definitely one of those things that pulls you in.
Before we dive too much into all that, though, let's start with your story.
How'd you get into programming in Python?
I knew this question was coming and I was sort of dreading trying to answer it because
I feel like every time someone asks me how I started programming, I give them a slightly
different answer because I've had quite a bit of false starts.
Like I had when I was a kid, they taught us basic and I sort of remembered enough of that.
And then so I didn't go to high school.
But when I was sort of in place of high school, going to like a homeschooling center every once
in a while, I guess I shouldn't say every once in a while, I was regularly going to a
homeschooling center.
You know, I started learning C++.
And then weirdly, my friend became close friends with someone who was what they call
the wizard on a moo, which is a mud, but object oriented.
And mud stands for multi-user dungeon, I think.
You know, I don't know if the young people listening these days will know what a mud was,
but man, muds were super fun back in the early days.
Yeah.
See if you can describe a mud to people listening who have never played it.
Yeah.
So a mud is a text-based game that you would connect to via like Telnet or something.
It's kind of like Zork or some sort of, if you don't know what a mud is, you probably don't
know what Zork is either.
But you know, like it's a text-based game where you describe, it'll say, you know, like, oh,
you're in a room, you can go north or south and you'll go north, you know, you'll pick
up an object or something.
So it's like kind of a fantasy game or a Dungeons and Dragons type thing where it's all text-based.
And then you can also talk to other people there.
Yeah.
And there's usually, potentially hundreds of people all running around.
They might be in these rooms and you can have battles, you can go on quests.
One of the hallmarks, I think, is it's not super obvious what you can do.
It's not like, well, here are my five commands.
Like you kind of have to interrogate the game with words to figure out like, oh, there's actually
a rock and I could move the rock.
I didn't know that.
But now I, you know, that kind of stuff.
What I liked about it was it was, you know, as great as graphics are on games these days,
it really just leveraged your imagination.
And yet there were other people there and stuff.
I thought it was pretty cool.
Yeah.
Well, so I actually got into that stuff like after the heyday of MUDs, like when there was
like not that many people in there.
It was just my friend had this, like was running, it was basically a chat server that you could
just build whatever room you wanted.
And then like you could just directly program stuff.
And it was interesting because when you would actually play MUD games in say the early 2000s
or something, a decent fraction of the people or like a much higher fraction of the people
than you would think, than you would meet in your daily life were blind because that was
like the game was all textual.
And so it was one of those things where, you know, you're not really going to appreciate
World of Warcraft or something, but you could go on a MUD or something and then it'll describe,
it just describes everything in the room and all that kind of stuff.
So it was really interesting to see when like a decent fraction of the users are, you know,
just interacting with computers in a completely different way.
You see some interesting stuff.
If I think about this too much, I'm going to stop being the daytime guy and I'm going to
just take up a second career as the accessibility guy.
Yeah.
For sure.
Well, it is super interesting.
I hadn't really put that together, but of course, because it's pure text, you can have
a screen reader.
And like, once you have the screen reader, it's pretty much on par with everyone else's
experience.
That's super cool.
A cool bit of nostalgia there.
So you got into this Moo somehow that led you into programming.
Yeah.
So it was a programmable Moo.
So that was like, you could do object-oriented programming.
So I was just doing a little Moo scripting stuff.
And then later I took up Tickle TK.
I had this job that I had these very long shifts and nothing to do.
It was just kind of sitting around doing nothing.
And I could play on the computer.
So I bought a laptop and just programmed a notepad clone.
Then I went off to grad school, did a lot of MATLAB and some C programming.
And then at some point I was on some forum somewhere trying to make a point about something.
And I made a chart in MATLAB and I posted it.
And MATLAB has like terrible anti-aliasing, or at least it did at the time.
And someone was like, oh, what is this alias nonsense?
Like you should use MATplotlib instead.
So, and my friend had told me the one, the same one who had the Moo.
He had told me about this programming language called Python that was like interesting and,
you know, like natural language text or something.
Fewer curly braces.
Yeah.
So I just like, I was like, all right, I'll give it a try.
And then I really, really liked MATplotlib.
I rewrote my whole thesis or I guess I just wrote my whole thesis, made all my charts in
in MATplotlib.
And then when I went and graduated and got a job, there was this one day when all the MATLAB
licenses were taken on the, like you had a certain number of site licenses.
And if you ran multiple processes, it would take up two licenses.
And I just couldn't do any work that day.
So I was like, how about this?
I'll just rewrite all of our MATLAB scripts in Python.
And so then at work, I got to use Python.
And then, you know, I started doing open source and I don't think I've used MATLAB since I
left that job.
Isn't it interesting how these draconian licensing systems, like these licensed servers and other
super intense things that are like just there to punish you, even if you follow the rules,
you know, it's just, it's like in their world, the worst possible scenario is that in some edge
case, some user gets to run 11 copies instead of 10 when they only paid for 10.
Whereas, you know, they've lost all the goodwill and they've actually pushed you to just, you
know what, we're just going to go do something that doesn't work like this at all.
Those are really interesting situations.
That's one of the reasons I really like open culture is it just cuts down on friction so much.
Like there are just so many times when it's like, oh, if I get this image from Unsplash instead
of iStockphoto or whatever, it's just, I don't have to think about it.
I can use it however.
And that's why I tend to create a lot of open artifacts.
You know, I, my blog is all CC zero.
I'm just really trying to cut down on the friction of letting people use my work.
But, you know, I understand like my business model for myself is to sell my labor day to
day to big companies.
I understand how it would, you know, if you are a company, you may want to sell software.
I also totally love that.
I have to rent, you know, so many things via cloud services.
And I think part of that is because it's so easy to get around licensing restrictions.
So I don't know.
I'm of two minds, but I think wherever I can, just cutting down friction by using free and
open source licenses is, is just, just makes everyone happy.
Yeah.
Well, I mean, there could always, always be some sort of grace slack area, right?
Like, okay, you have 10 licenses, but we're not going to cut it off until you have 15 processes
right.
Yeah.
There's just like, when it's such a hard and fast rule, I don't know.
It just cuts me the wrong way.
All right.
So you talked about some of the stuff that you've done at work and you talked to, gave me the
sense that you're kind of just doing some consulting and helping out various companies on various
projects.
But what do you do day to day?
Oh, sorry.
Yeah.
No, I don't do consulting.
I work for Google.
So I, I, I'm more of a, less of a philanderer and more of a serial monogamist.
So I gotcha.
Yeah.
I worked for Bloomberg for about four years and now I work for Google and our team is
called a Corp Eng machine learning.
So Corp Eng is our internal infrastructure team that, that handles things like facilities
and like tickets.
Like if you, if you open tickets with people like HR, things like that, those are all within
Corp Eng and we build machine learning models for other people in Corp Eng for, to, to provide
them insights or to make their job easier, that kind of thing.
So this is like the Google scale of automate the boring stuff to help you do your work
a little better.
Yeah, definitely.
So, you know, my day to day work is playing around in Jupyter Notebook.
Well, okay.
Everything in Google is like its own proprietary thing or even like when it's not proprietary,
it's still its own thing.
So like, we usually use collabs.
Unfortunately, you know, I like to rag on people being like having their own proprietary versions
of stuff.
But like every time I try and do that with Google, like they have like stupidly good
reasons.
It just makes it so much less fun to make fun of our proprietary technologies when, when
it's like, oh, well, they do have native integration with like Google Docs and, and, Google drive.
So yeah, I guess it does make sense to use it.
Yeah.
Sure.
I mean, there is in the tech space and the developer space, certainly the not built here.
So we've got to build our own sort of obsession where people could take that too far.
And it's just a, just a drag.
Like we don't need to build our own like booking system.
We can just get a, get a calendar system somewhere else and things like that.
But when it's large enough scale and it has like built in advantages, sure.
It makes sense.
Yeah.
I mean, I just wish that my colleagues were less competent because then I can make fun of
them, but you know, now I just have to respect them.
Oh, what kind of a work environment is that?
Pretty good one.
This portion of Talk Python to Me is brought to you by Brilliant.org.
Brilliant has digestible courses in topics from the basics of scientific thinking all the
way up to high end science, like quantum computing.
And while quantum computing may sound complicated, Brilliant makes complex learning uncomplicated
and fun.
It's super easy to get started and they've got so many science and math courses to choose
from.
I recently used Brilliant to get into rocket science for an upcoming episode and it was a
blast.
The interactive courses are presented in a clean and accessible way and you could go from knowing
nothing about a topic to having a deep understanding.
Put your spare time to good use and hugely improve your critical thinking skills.
Go to talkpython.fm/brilliant and sign up for free.
The first 200 people that use that link get 20% off the premium subscription.
That's talkpython.fm/brilliant or just click the link in the show notes.
All right.
Let's talk about time.
Every programming language has to deal with dates and times and they all have their own
way of doing it.
And I would say Python's is pretty solid, right?
It's got a pretty good system there.
So there's a couple of interesting things, I guess, about time.
One is it only goes back so far in computer time, right?
Some of if you if you're talking in ticks or things like that.
So I don't know.
What do you think about the daytime story in Python now that you're down in it?
I'm actually a big fan.
I may not have a great breadth of experience outside of Python, but I think, you know, the
more I've learned about Python daytime, the more I understand the choices that were made.
Like one of the biggest issues with daytimes is that you often see people like, oh, I can't
believe daytimes are so terrible in Python because of X, Y, Z.
Like, why isn't why isn't every daytime UTC by default?
Like, why is it some other naive thing or or like, why do I have to attach a different time
zone to this or that?
And the issue is that there are multiple camps of people who have equally strong.
It should just be this way opinions, but in opposite directions.
So most of the people think UTC is the natural thing to do.
But I think those same people may not realize that when you're working with dates in the
future or you're working with civil times in general, UTC is actually a very bad choice
because generally speaking, UTC is good for.
So I say UTC is good and UTC is actually like the best that we have.
I don't love that UTC has leap seconds in it because it takes some nice monotonic constant
that you can, you know, that you can use as a reference and turns it into this weird thing
with its own edge cases where sometimes there are 60 and sometimes there are 61 seconds in
a minute.
Very annoying.
Really?
I had no idea.
Yeah.
every fourth minute has an extra second or something.
It can happen as many as two times per year.
And sometimes they, I think they'll either skip the 59th second or they'll add one second.
I think it's only ever that they've added one second.
It's for the purposes of leap seconds.
Leap seconds are, I think, useful for some things like astro navigation or something, but
they're incredibly important for astronomers.
I have no idea why they're built into the foundations of civil time of regular human does not need
to know to the second when the sun is going to be overhead in Greenwich.
Right, right.
You know, maybe it makes more sense to have like an astro time that takes those like peculiarities
into account, right?
Astronomy has its own whole big long set of ways of doing timekeeping.
Like they have sidereal times and solar time.
And, and I think they usually use the Julian calendar going backwards.
I don't really understand exactly why they do all that stuff, but if you really want to
dig into like weird timekeeping practices, astronomers are astronomers and weirdly astrologers.
Like something you, you may not know is that a decent amount of the like historical corrections.
And actually I think the original basis of a lot of the data in the time zone database
that everyone uses came from astrologers who were like deeply concerned with exactly what
second you were born at.
So like if you birth certificate says like three, 15 and 14 seconds in Yugoslavia in 1981, they
have to dig up the, like the old Soviet era Yugoslavian timekeeping records to find out what that
meant in UTC time so that they could find out whether Jupyter was in the house of Aquarius
or some, some crazy thing like that.
That is crazy.
I had no idea.
If you don't cut me off on these things, I will just go on as many tangents, like a weird
fact.
Tell me how they're still involved and then I want to dig into something else.
Oh, well, they just, it's still important for them.
So you'll still see corrections where they're very concerned with like times before 1970 because
the record keeping is a little shoddier.
And so the time zone database, you know, basically they say anything after 1970, we try and keep
it as accurate as possible before its best effort.
So you'll still see people making sure they're like, oh, well the, like exactly how did the
clocks move on the ground at this time?
It's like the people who are on the time zone mailing list are basically a bunch of Unix
people, the historians who are digging through, looking at historical stuff and astrologers who
are just weirdly concerned with exactly the minute you were born.
How interesting.
I had no idea.
All right.
So what I, what I want to dig into is this idea of naive time versus aware times.
Sure.
You can do interesting math.
Like you can subtract two date times, but I don't think you can subtract like a naive
time from an aware time and stuff like that.
Like you can't combine these things.
Can you not?
I don't remember.
I feel like I've seen an error from that before.
That is true.
So it's changed a little bit between Python two and Python three, but not to the point
where arithmetic is allowed between them.
So in Python two, there was this idea that a naive time was essentially just a representation
of a time as it would show up on a calendar.
So it's divorced from any notion of real time.
It's an abstract, perfect daytime that just is the proleptic Gregorian calendar.
And an aware time represents a specific timestamp.
So you can take something that's in UTC and you can turn it into local time in New York
or in Shanghai or any, anything like that.
You can get durations between things.
So that was the distinction.
And, you know, the idea was that it's kind of like a naive daytime was a daytime without
a unit and aware daytime is putting units on it.
So the number five is just a number.
Five feet is equivalent to one and a quarter meters or something like that.
Right.
Yes.
1.6 or something.
In Python three, it changed a little bit for reasons that are complicated and like probably
not worth getting into.
It's very complicated to create a time zone, like a TZ info that represents local time and
maintains all the semantics that you would hope.
If during an entire process where the local time might change over the course of the process.
And so one of the things that happened in Python three is that now instead of naive times being
unit list, they just represent local time.
So they still act mostly the same way.
But if you do something like you call dot timestamp on them, they will give you, they'll convert
it to UTC and give you the number of seconds since 1970, January 1st in UTC.
You can also do like as time zone and you can just directly, you can pass that a time zone.
It'll convert.
It'll assume that the daytime represents local time and then convert it into the time zone you
care about.
So at this point, local times are, or naive times represent local time, which is why UTC
now and UTC from timestamp are not functions you should use these days.
Okay.
Because they basically, they generate a naive timestamp without attaching UTC offset or like
without attaching the UTC object to it, but they do it as if that represents UTC.
So if you do UTC now and then dot timestamp, it'll give you a timestamp representing a different
time than now.
Like I'm in a minus eight, so it would subtract eight hours from it or something like that
or add eight hours rather.
It'll plus or minus eight hours, but it'll change it in some direction.
That's not just leave it alone.
It was UTC now.
So it just, it is that time, right?
Yeah, exactly.
Okay.
Interesting.
Yeah.
I always feel like daytime seems so straightforward until you get into here and then it's just
like fraught with education.
Like, wait a minute.
What?
I didn't know I couldn't use UTC now.
Why is it still there?
Right.
Without at least a warning.
It's even worse than you might think too, because the semantics of like subtraction
are made even more complicated.
And like the people who designed this library, like they weren't just like idiots.
They actually were like really thinking things through.
And so most of the time you won't even notice this kind of thing.
But when you learn about it, it's a bit like makes your head explode.
So there's subtract, like subtraction works differently when you do it between the same
time zone and a different time zone.
So if you have two dates and they're both in New York time, right?
America slash New York.
What it'll do is subtract them just based on the calendar.
It won't give you the amount, the total amount of time elapsed between those.
Even if like, so if it's like the day before daylight saving time transition and the day after
23 hours have elapsed between one o'clock and one o'clock the following day, it'll give
you 24 hours between those two.
If they're both in New York.
Okay.
Because that's how it works in the other direction.
If you add 24 hours to something, it'll just shift over the calendar by one day.
And I think the idea was that they wanted it to be the way it works in the other direction
is you add one day and then it'll create something that's one calendar day in the future.
And then it'll attach the same time zone object to the new daytime.
So if you then subtract it back, you'll get, you'll still get one day.
The problem is that like, you can't just sort of shift around on the calendar when you're
trying to do operations between two daytimes, like one in Chicago and one in New York.
And the relevant, like the most reasonable thing to do is to just get the total amount of elapsed
time.
You just convert them both to UTC and say how much time has passed.
Right.
The thing is that, the way they decide between inter zone and different zone, like same
zone and different zone is whether the objects are the exact same object.
So if you construct a new time zone object, if your time zone provider allows you to create
a new time zone object representing the exact same zone, it won't check if they're equal.
It'll just check if they're the same object.
This is not really a problem with PyTZ because PyTZ doesn't use normal daytime mechanisms.
And like basically literally everything you do will generate a new time zone object.
So everything is an inter zone comparison.
Yeah.
And with date util and with the new zone info module, I've implemented a cache.
So basically all of these zones are singletons anyway.
So nowadays it's basically like if you use the same INA key, you'll get same zone semantics.
And otherwise you'll get different zone semantics.
It's more complicated than you would think.
And it's really just all down to these overloaded concepts that are just everywhere in daytimes.
Like the idea of adding a duration is horribly ambiguous, right?
If you consider adding a month, right?
What does that mean?
Does that mean 30 days?
Does it mean 31?
Does it mean give me the next, the same day, the next month?
What if it's January 31st?
Do you go to the end of February?
Do you go to the beginning of March?
So for two days, if you add one month, does it all go to the same day?
Like, you know, do you just do one month, mod, however many days the difference is?
Like there's so many different options.
You know, you kind of have to pick one, but it's very frequently the case that
different users will have different, very strong expectations that it will do one thing or the other.
And for something so low level, like the datetime module, which is, you know,
essentially something like a standard, right?
It's trying to be basically a data type, an interchange type.
You just have to make choices that are hopefully going to be useful for the most,
the greatest number of people.
Yeah.
Well, it makes a lot of sense, but man, there are more and more edge cases.
The more we talk, I'm like, yeah, that's, that's tricky.
And you know, you think about, so if I was in Indiana, for example, like certain places
in the United States have different rules about following things like daylight savings, right?
So Arizona, Indiana, a couple others, but I pick on Indiana because they've got a county
by county system.
So depending on which county you live in, like you're actually, let me just read this a bit
from Wikipedia just so people know what I'm talking about.
It says, most portions of the state that were in the Eastern time zone do not observe
DTS daylight savings.
However, Floyd Clark and Harrison counties, which are near Louisville, Kentucky and Ohio
and Dearborn counties, which are near Cincinnati and Ohio unofficially observe it because they're
proximity to these cities, which do observe it.
So if I've, if I have like two day times, one in that county or not in that county, right?
It's in different time zones in different parts of the year based on like region.
Like what do you even do there?
Well, in the time zone database, the INA time zone database is also sometimes called the
Olsen database.
What they have is that, I mean, it's one of the reasons why names like us slash Eastern
and us slash Pacific are actually deprecated.
The way those keys work is that they usually go with a region slash the largest city in the
region that has continuously had used the same rules since 1970.
So America slash New York is the same one that you use in New York as in Boston.
Yeah.
Or in Virginia, anything like that.
If Massachusetts switches over to being part of a Atlantic standard time, then there will
be a new zone created called like America slash Boston and it'll cover Massachusetts going
back all the way to 1970 in Indiana.
They have their own like sub key.
So they have like America slash Indiana slash Indianapolis and then like five different states
there.
I think Mountain Time has a couple things like that as well.
Like Denver and Phoenix are separately, are handled separately.
I see.
So you have to be very precise about your, like your time zone info passed over, but then it'll
actually take care of that.
Yeah.
It definitely handles that in terms of historical times.
Like this gets to an issue that it's another one of these overloaded concepts, which is like
when we talk about a date time for some people, like if you're looking at server logs, people
are like, why would you not just use UTC all the time?
It's unambiguous, but those people are not implementing say a scheduling service, right?
Where, you know, like you and I scheduled to meet at a specific time to record this podcast.
Right.
If someone had changed daylight saving time, like if between the point where I scheduled it
and today, the United States said, we're in so many crises right now that we're just going
to like switch off daylight saving time.
I don't know why politicians love messing with time at the last minute, but they absolutely
do.
If someone had done that, then we would still want to meet at four o'clock because relative
to my work schedule and your work schedule and everyone's school schedules, that's still
the right time for us to meet.
But the mapping between four o'clock and UTC will have changed.
So what that means is like, if we had recorded that as saying, okay, this is going to be as a
daytime guy, I should always be embarrassed by this, but I can never do any daylight saving
time calculations in my head.
Hey, we have computers for this stuff.
Come on.
Yeah.
It's like eight o'clock UTC is when this recording is going to happen.
If all of a sudden the mapping between four o'clock and eight o'clock changes, you and I
will be very unhappy that they stored it in UTC and then converted it before showing it to
people.
So when you're dealing with the distinction I usually make is timestamps versus civil times.
So a civil time is like when you actually care what the clock on the wall says, then
you should use a civil time, which is you store exactly what the clock on the wall says.
And then the time zone you stored it in America, New York, something like that.
Right.
This is to get back to this point about what you do, like how you store it right now.
There's no way to solve exactly that problem, or there's not a great way to solve exactly
that problem.
Because what you really care about is like a little hard to pin down because, you know,
I'm in New York, you're in Portland, right?
Yeah.
So, you know, if one of us changes our time zone, if our relative time zones change, New
York changes its time zone offset, but Portland doesn't.
Which, you know, the meetings with two people, which one controls, which one matters, you
know, or like, I said, it's American.
Do you reorient it based on like the current understanding of time in New York and then break
Portland or do you stick with Portland and now you're out of sync?
I think the best you can do is you pick an INA zone and you just store it that way.
Usually that won't be a major problem.
If you're like super belt and suspenders, like storing a user's location, you say like,
where is this meeting or like, where's the rules that you care about?
And then you'd have to find a library that maps locations to time zones as a function of
time.
And then just make sure that that library is kept up to date.
That should sort of sort you out.
But I think the best you can do is to monitor the time zone mailing list and, you know, just
be aware if you see anything that's going to affect you.
Yeah.
Well, there's definitely a lot of little edge cases and that's pretty interesting.
So another thing that's interesting in the whole time space of Python, and I think it's
done pretty well, is time deltas, right?
And the fact that I can have two daytimes and I just subtract them and that gives me a time
delta object, or I can have a daytime and then add or subtract the time delta and that generate
a new daytime that's offset by that.
What's weird about time deltas that I should be learning about?
Because they seem pretty straightforward.
I would like to see them do a little bit more help for people, but this is already pretty
good.
The biggest thing semantically is an issue that I already alluded to, which is that they're
a little overloaded in that sometimes they represent an elapsed amount of time.
And most of the time, and usually they're interpreted when you like apply them to something, they're
usually interpreted as a calendrical delta.
So it's like, it'll give you, you know, if you add one hour to something, if you add one
hour to like 1.30 right before a standard time to daylight saving time transition, what you'll
get is some non-existent time that is right in the middle.
Like, you know, it's like a 2.30 that never happened.
Or you add one hour, like one minute to right before that you'll get, or you add one hour
and one minute in such a way that it spans that you'll get something that is nominally
one hour and one minute away.
But in fact, two minutes have elapsed, something like that.
Right.
Okay.
So that surprises people.
I think it tends to surprise people more on certain scales, like for very short time scales,
one minute, two minutes, something like that.
You're like, why isn't this working exactly as I expect when it's like one day, you're
usually trying to just get the same time the next day, something like that.
I don't know that there's a great solution to that.
One thing that I would kind of like to do, and I don't know that there's any way to do it
without breaking backwards compatibility is to separate out the concept of like a calendrical
delta and an absolute delta, which is like, give me this elapsed period of time.
You can certainly add a type that represents elapsed times.
And then when you add it to a daytime, it converts the daytime to UTC, does the addition
and then converts back.
But the issue there is that what you'd really want is you'd really want the results of those
interzone subtractions to return those elapsed time, you know, elapsed time time deltas, because
that's actually what's happening.
You know, you're actually getting an elapsed time time delta.
So if you take something that's like something in America Chicago minus something in America
New York, you'll get the absolute exact time.
And then if you add that to America New York and then convert the result back to America
Chicago, you might get a different value than the value that you started with.
So like that property is something that you would expect to be true.
Right.
That item potency of like, if I change it this way and then I change it back or that sort of
additive identity or whatever you call it there that like I make this change and I undo that
change.
It would be weird if it's like not back to where it started and stuff.
Right.
Yeah.
So, I mean, in that very particular edge case, it is a little bit lossy and I would really
like it if there were a bit that I could add.
And maybe you could like maybe everyone who is seeing this behavior is expecting the that
like reversible transformation.
And basically, we would just be fixing a bug for every single person.
But there may be people like you always hate to punish people who figured out the right thing
to do and then did it.
And then you just like change what the right thing to do is out from under them.
Yeah.
Once you've kind of put it in place, then it's really hard to change it.
Right.
I mean, you're kind of stuck.
Yeah.
I mean, that's the story of my life.
But you make slow and steady changes and you break things only when you absolutely have
to.
And hopefully you get a reputation for not breaking things just willy nilly.
And people take you seriously when you say, hey, we really want to break all your stuff
today.
Yeah.
Well, I think that that's actually one of the reasons that Python is going so strong.
Right.
You know, JavaScript is going strong as well.
But the challenge with JavaScript is like I spent all the time learning Angular and then
they threw away Angular 1 and they rewrote the API and they switched it to TypeScript.
So I got to start over.
Or, you know, like pick your framework du jour.
Like the stability of those things or the life cycle of those things is so short.
And, you know, the fact that you don't have to keep changing because your dependencies or
whatever changed.
That's like dependency being Python potentially.
That's a really good feature, I think.
Yeah.
I think sometimes also things have a short, tend to have a short shelf life in some situations
because people want to break a whole bunch of stuff.
And I guess I'm just glad that we have maintainers around who are willing to kind of put in the
work for the long haul to make it so that, you know, hey, this thing is still
supported and you don't have to migrate to a new framework every 30 minutes.
Yeah.
So one thing about daytimes that I want to ask, sorry, time deltas that I want to ask you
about because it drives me crazy is I find myself doing math way more than I think I should with
time deltas.
For example, if I have a time delta and I want to know how many days that that time delta
represents, that's a math problem for me, right?
It has a day's operation, a day's property or field, but it gives me unusual answers in some sense and not a
fraction of days, right?
So if I have something that's 30 seconds, I would like it to be whatever that is, like one one hundredth of a day.
Or I would like to be able to ask, how many hours are there?
How many weeks?
You can do that.
Months and stuff starts to get hard.
Okay.
How do I do it?
Because all I know about is total seconds, for example.
And then there's seconds and then there's microseconds and there's days.
Those accessors, like the days, seconds, microseconds thing, those are actually, time delta is essentially
supposed to be like a struct type object that just like holds a time delta, you know, and it has three
canonical components, which is days, microseconds, days, seconds and microseconds.
I understand that it's confusing that those accessors are like not the total number of days.
The way you're actually supposed to, this was added in Python 3.
The way you're supposed to get this information is time deltas can just be divided by other
time deltas.
So if you just have like a time delta and you want to know how many days there are, you just
divide it by time delta days equals one.
Oh, interesting.
So instead of going total seconds divided by 60, divided by 60, divided by 24, I would say
dt divided by time delta days equals one.
Yeah.
And you can just have any arbitrary value as the denominator there.
So it's actually, this is one of those situations where it's like not super discoverable,
but it's incredibly elegant.
Yeah.
And like you can, the fact that time, that total seconds even exists is a problem.
Well, it's not a problem, but it highlights this fact that it's not super discoverable because
the, when they added total seconds, they had already added the ability to divide by, they
had already solved this problem by adding the, by defining a dunder div.
Yeah.
And one core developer didn't know about that and added total seconds.
And then the guy who was, you know, maintaining daytime showed up after it was all merged and
stuff and was like, oh, I wish I had seen this before.
I would have said, please don't add this.
Yeah.
So, you know, every once in a while we get people who show up and they're like, can we
get total microseconds and total whatever?
And it's like, we don't want to make 40 different, you know, things that say quarters and months
and years and things like that.
Like just, you just have to divide it by a time delta and it works super well, especially
now that increasingly you are, people are working in Python three only code bases.
If you have a two, three compatible code base, you generally do have to like do total seconds
and then divide that by total seconds of whatever your time delta is.
Gotcha.
Okay.
Interesting.
Yeah.
Cause I was hoping there would be a total minutes, total hours, total days, and it could
just do that math that I talked about just in line.
Right.
And like, just so I don't have, so I could be more expressive and not do like a long series
of divisions.
You certainly can do that.
Like, I can understand why you would want that, I suppose, but then, you know, you only
have the enumerated units that, that are in there.
And it also sort of hides the fact that you can just do regular division.
I mean, you don't have a dozens method on, on integers to find out how many times 12 evenly
divides in it.
You know, it's a fair point.
I think that's the discoverability that is the challenge, right?
To know that you can actually do the division and it'll, cause now you say it like, sure,
it makes total sense to say, I want to know how many whole weeks are in there.
So I would say time delta days equals seven and then divide it.
And that would give me a great answer.
Right.
And I can pick my units to be whatever.
You can also do weeks equals one.
Yeah.
Weeks equals one.
Sure.
So there's a lot of flexibility there, but yeah, it's just, I don't see a lot of examples
using that, you know, when you look around at code stuff.
That's partly because people don't see it.
And partly because anything that a lot of the code that we look at now, especially open source
code has been two, three compatible for like the past five or 10 years or something.
And that idiom is not available in Python two.
So Python three, when you're Python three only, you know, it's kind of like you're starting
to see f-strings everywhere.
Hopefully all the cool kids now are just dividing their time deltas.
Well, they will be now, now that they hear about it on the podcast.
Yeah.
I thought you were going to say the thing about how the rapper and the, the stir, like the
string cast of time deltas is just absolute trash.
Like I really wish I could fix that.
I think it's going to be difficult to do so, but it's like, if you print a time delta that
is negative one hour, it tells you one day minus 23 hours or tells it to you in seconds.
Yeah.
The internal reputation is weird.
Like so for, I do that for one that is one second long.
It's negative one day, 23 hours, 59 minutes and 59 seconds.
If it has like a negative one second or something in it.
Yeah.
It's, you know, it computes to the same, but it's not very human.
Yeah.
I would probably do it a different way.
I would probably do it as like negative and then abs, like an absolute value.
I think they're worried about some ambiguity there, but I don't think anyone ever wants
what we got.
So yeah.
You've given like 99.99% of people something they don't want to avoid a tiny bit of possible
ambiguity.
It's right.
Yeah.
What are you going to do?
Well, so let's talk a little bit about some of the, the peps here.
So you've got pep495 and that one, is that one already done?
That one's already done.
Yeah.
So pep495 was implemented for Python 3.6 and that adds the fold attribute.
The background of this is that prior to Python 3.6 time zone support was not super great.
Basically, whenever you have an offset change that where the offset decreases, that means
that you are jumping back by an hour or by any amount.
And that creates an ambiguity, right?
So it's two o'clock and then you jump back one hour.
Hopefully it's two o'clock.
I actually found one place in, I think in Argentina in 1992, their daylight saving time
transition happened at midnight on February 29th.
Cause it wasn't bad enough to do it at midnight with that ambiguity.
They also had to do it during leap day.
So my goodness.
Yeah.
So it's like, anyway, so you do something like that, right?
And so instead of it being February 29th or March 1st, it's now February 29th and at
11 PM a second time.
So the way time zone handling works in daytime is, is, is actually quite elegant.
The idea is that you attach because a time zone represents a set of rules for like taking
the current for mapping between absolute times, like time and UTC and local time.
Like what time does it say on the clock?
So I think the original design intent was that you would have a TZ info and the TZ info has
these functions that you can call that give you information about the time zone as a function
of the daytime.
So it's super great.
You just write this function that maps your daytime to UTC and you're done.
Except that the daytime portion is sometimes ambiguous, right?
So if it's 1992 and it's 1130 in Argentina on February 29th, there are two different offsets.
There's two different sets of information that you could apply there.
And there's no function that you can write that just takes the naive portion of that daytime
and gives you the correct offset because it's ambiguous.
So the way PyTZ solved this problem was that they added this localized concept where what
they do is they, you create a time zone and then instead of just like attaching it directly,
you have to call localize on it.
And what PyTZ will do is it'll just attach a dedicated fixed time zone offset.
So it has a little switch in there where you can say, do I want to be on the daylight saving
time side or the other side?
This is a major source of bugs because people will just do what the docs say and attach PyTZ
time zones directly to the TZ info instead of letting PyTZ do it itself.
And also it kind of circumvents a lot of the other logic in there about a lot of assumptions
about like you're just supposed to have this one set of rules, not a fixed set of offsets.
And then it's also a bit of a problem because they specifically use DST, but there are situations
where you have transitions that are not due to daylight saving time.
Like someone just switches their base offset or something.
So that's where PEP495 came in.
They, what they did was they said, we're just going to take the naive portion of the date
time and we're going to add an additional component to it called fold.
And I can take two values, zero or one.
The zero represents the first, the offset that happened before the transition.
And then after the transition, you put fold equals one.
It's very elegant.
It allows you to write time zones that just take the naive portion of the daytime and then
just flip a switch if it's ambiguous based on the fold.
Okay.
Yeah.
That's, that's cool.
Yeah.
Just catching these little edge cases.
And then PEP615 you're working on as well.
And this one's in 3.9.
So I guess in a sense it's accepted because 3.9's in its beta world.
Yeah.
It was accepted and we merged it.
So it's going to be, you can get it in the betas now.
You can actually get it.
I have a backport of it implemented back all the way to Python 3.6.
It works in PyPy.
I've tried to make it, you know, my goal here is basically that I would really, really like
it if people could stop using PyTZ.
I think the maintainer of PyTZ would also agree with me on that.
It's basically PyTZ was sort of a hack around this issue.
They did a really great job on it.
Like, I think, I don't know that there's a better way to have done that, but well, you
know, other than just coming up with this fold idea yourself and that has its own problems.
In DateUtil, I also have a backport of PEP495 that works in 2.7.
So even if you have a Python 2.7 implementation with some combination of the zone info module,
which was added in PEP615 and DateUtil, you can actually get proper PEP495 support all
the way back to Python 2.7.
And yeah, you know, there's a bunch of reasons why you should use zone info.
One is obviously, you know, I think it's enough of a selling point to just say, you don't have
to do this localized, normalized stuff.
Like you can just use time zones like they were meant to use and it'll just work.
But there's also the fact that PyTZ doesn't have any support for the version 2.tzif files.
So the INA, the compiled versions of the INA time zone, they're all version 2 or 3 now,
like since 2005.
And version 2 and 3 is when they switched from using 4 byte integers to 8 byte.
So each time zone now starts with version 1 file, like the entire version 1 file.
And then after that, they have the version 2 file.
So all the stuff that supports version 1 files only still works with your version 2 and 3 files.
But version 2 and 3 files will go past 2038.
And they, instead of just like stopping at some point, they also have like a general rule.
So they'll say like, here's the rule for transitions after 2038.
Right.
We don't have data for this, but here's how it has been.
So just keep computing it like this.
Yeah.
I mean, the further into the future and actually the further into the past, like the distant past,
like just like what was the time is significantly less meaningful question to ask.
So right now, you know, what time zone, like what is the UTC for New York in 2040 is not a terribly like gazing into a crystal ball, right?
It's right.
You can have a guess.
It's probably a better guess than randomly choosing, but it's not going to be accurate.
Like it's not, it might be a bit of an XY problem if you're asking that question, but you know, it's still like, at least it'll do what you expect.
But as time goes on in the next 10 years, in the next 15 years, we're getting a lot closer to 2038.
You're going to need that kind of support.
Right.
So PyTZ doesn't have support for that.
It doesn't have support for sub-minute offsets.
Another thing that ZoneInfo does and DateUtil does, but PyTZ does not do, is that they will hit your system time zone information first.
So there's a way to configure it.
They have their own access to time zone.
They have their own time zone data in a sense that you can get if your system time zone data, if your system doesn't provide time zones.
And there are mechanisms for specifying where you want to get the time zone data from.
But with PyTZ, it ships the time zone data with it.
So you have to keep your PyTZ up to date just to get the data updates.
There's a way to change that where I think you like set an environment variable and tell it where your system time zones are.
And it will use that instead of its own thing.
But you have to know where your stuff is.
Whereas with ZoneInfo, it's built in.
So it'll find it in the most common places.
And then there's a mechanism for the person who distributes Python to you to tell the compiler where it's going to be.
So if you use some system Python, it'll always hit your system time zone, which is very helpful.
So, you know, there's all those reasons to not use PyTZ.
Yeah.
There's still reasons why you might be worried about switching over.
Like, for example, since PyTZ has its own weird interface, you know, there's going to be a lot of your users possibly who've taken your TZ info and they've called localize or normalize on some date time.
And if you change over from PyTZ, it's going to break all of them.
But I am aware of this kind of thing.
So I've also created a library called PyTZ deprecation shim, which is just a thin wrapper around ZoneInfo, except that it supports the PyTZ interface as close to the semantics that PyTZ has as possible.
And then it just raises a warning if anyone's doing anything PyTZ specific.
So it just works like a regular 495 thing.
It works in 2.7 and 3.6 onwards.
And if anyone's, like, using localize or normalize or whatever, it'll raise a warning.
So you can basically say, oh, for the next two years, I'm going to depend on PyTZ deprecation shim, and then I'm going to drop it in favor of ZoneInfo.
And hopefully everyone has not been ignoring all my warnings.
Yeah, that's good.
It's really nice to have that warning there.
So it gives you some time to deal with it.
All right, Paul, we talked about a lot of different things, a lot of interesting edge cases and scenarios.
Maybe give us the main takeaways, like, if you could give people listening some advice on the please do and please don't with time in Python, what would you say?
Yeah, so for don'ts, I actually have a couple of blog articles about this.
Like, one of the things I see the most often is people using UTC now thinking like, oh, I want something in UTC.
But UTC now and UTC from timestamp are not something you should be using in modern Python.
I would like to remove them.
But there are, like, occasionally these situations where they're useful.
Like, if you're immediately trying to, if you're just using UTC now to, and then dumping it right into ISO format, and you don't want the, like, the UTC offset in there.
Right.
It's not a super great way to do that.
I might just bite the bullet and deprecate those.
And then maybe, you know, have a wrapper function for it in dateutil.
But for the most part, you don't want to use UTC now.
You should use just daytime.now and then pass it the daytime.timezone.utc object, which is just a UTC singleton that's in a standard library.
Also, I don't think you should use PyTZ.
I think you should take all your PyTZ code and migrate it over to zone info or dateutil.
And start getting on the PEP495 bandwagon.
And I've got a little migration guide for that.
Nice.
We can put the links to those in the show notes.
Now, I just want to do, maybe acknowledge a couple of libraries that are on the outside of CPython, but still pretty helpful.
And the first one actually is Python-DateUtil.
That one's yours, right?
Yeah.
So I didn't write that, but I've been maintaining it for about six years.
That's got some interesting stuff.
Even after PEP615, the timezone module does still have some useful timezones in it.
Like it has, well, you know, I say useful.
What I mean is like available, like different types of timezones that are not in the standard library.
So like there's this TZiCal.
If you have timezones in this iCalendar RFC format, dateutil will handle that.
And you can also like use like these POSIX strings.
Like if you ever see like EST5 EDT and then like a, there's a POSIX standard for expressing recurring DST transitions.
So it has that and some Windows specific stuff as well.
You know what I use it for that I really like is its parse.
Its parsing is really good because it seems like it generally just handles time strings, which is great.
Yeah.
The parser is the part that I like the least, but that's mainly, I mean, because I have to maintain it.
And it's got so many rules that it's super easy to break.
So anytime someone shows me something where it's broken, it's like, I'm really afraid to change anything.
Because if I do, it'll break someone else's use case that they've been using it for like 10 years.
It's also like pretty slow.
So it's super useful if you have something that you know is a date time and it's in a pretty standard format and you just want it to like chew at it until it finds something that looks like a date time.
But it could be chewing for like 200 microseconds.
If you have something that's in ISO 8601 format, dateutil also has ISO parse, which will handle anything that's in a valid ISO 8601 format.
And then date time, I think the first thing I added to CPython was from ISO format, which is like the inverse of ISO format.
Okay.
That's cool.
That's on date time.
It's got our rule.
Dateutil also has our rule for recurrence rules, which are very useful.
It has relative delta if you want to do time deltas, but include years and months and things like that.
And the best one I saved for last is Easter.
It just tells you when Easter is.
You give it a year and it's like, this is when Easter is.
Oh, that's cool.
Yeah.
There's a couple of different holidays and stuff that are all sorts of all over the place that are tricky, like Hanukkah and stuff.
So the two others that come to mind, and I'm sure there's like 10 additional libraries that people are out there, let's see.
But this one, I just don't have them off the top of my head.
One is called Arrow.
Are you familiar at all with Arrow?
Yeah.
I've contributed to Arrow a couple of times.
Yeah.
It's pretty cool.
Some of the things, I guess, that stand out to me, like, that got my attention the most is that it has humanized.
So you can have a time and you say .humanize.
It'll say an hour ago.
And you say humanize.
An hour.
The locale is Korean or something.
And then you get the Korean statement of an hour ago and so on.
And that's pretty easy.
Pretty nice.
Yeah.
I mean, so for stuff like Arrow and Pendulum and Maya and DeLorean and all these things, I've never found a huge amount of use for them.
But I'm not, like, a huge, like, I don't actually, like, I don't know that I have the exact use cases.
I tend to write libraries and taking on big dependencies is not the easiest thing for me.
But I do know that people kind of swear by these libraries.
They really like them.
So I think that there's certainly something to them.
The biggest problem I have with them is that they tend to be, they tend to try and advertise themselves as, like, drop-in replacements for date time.
And so they then subclass date time and time delta.
Stuff like Pendulum advertises itself as a drop-in replacement, but then it breaks all the stuff that I want to break, you know.
So it's not actually a drop-in replacement.
You can't even construct it the same way.
And they tend to be slow as well.
I mean, this is partially because they're not written in C or not mostly written in C.
But, you know, to do simple time delta arithmetic in Pendulum is, like, 10 times slower than doing the same thing in C.
But, you know, if you're not handling a huge number of date times, it's probably fine.
But, of course, you know, we don't have human eyes and things like that in the core.
I think that those are very useful things.
I would tend, like, I would love to see a library that is kind of like Pendulum or Arrow, but instead of it being methods on a date time subclass, it's, like, just free functions, you know, utility functions.
Right.
You could pass it, built-in items.
Yeah.
I mean, I think that would be faster in a lot of ways.
Sometimes people don't care about fast.
Yeah.
Well, if you're building a library, especially if you're building CPython itself, it's a different level of concern.
Yeah.
If I'm rendering a web page and I've got 10 items and I want, like, the human expression of how long ago they were, I probably don't care.
Plus, you can benchmark.
Yeah.
Like, I can sort of, you can benchmark and see where the bottlenecks are.
I can't benchmark everything on PyPI and everyone's proprietary code bases and find out, like, you know, do some sort of optimization and find that it's, this is not the bottleneck anywhere that this code is being used.
Right.
Exactly.
It's a different scenario.
And, yeah, I do find that just using bare date times is useful for interop.
But if you're mostly working in your own stuff, like, you're just passing it around, doing stuff with it, they do have some, like, you know, people do like it, you know, they really do like the interfaces.
They like that the time delta things that they give you have total minutes and that they have human errors.
Right, right.
Yeah, they got, like, weeks and hours and stuff.
The thing that stands out as most unique about Pendulum is they have a duration period thing that is aware.
So I could have a date time span, the subtraction between two date times, the equivalent of a time delta.
And then you can say in weekdays and then for each thing in the period.
And it'll give you day one, day two, skip the weekend, day three.
So, you know, Thursday, Friday, Monday, Tuesday, as a thing you can go.
So if you're like, well, there's, it's this long, I need to know how many weekdays there are or how many weeks or something in this span.
That's an interesting concept.
Like in detail, we have this R rule, which is based on a data type described in RFC 5545 called the recurrence rule.
And it is super, like, it's a little more complicated than that.
You know, again, this is why I think these sorts of things could be done as free functions.
It's very interesting.
And like, it's a little too complicated for the average person to just sort of jump right into it.
But you can express all kinds of stuff like that and say, like, how many Tuesdays are there?
Like one of the talks I give on date you till, I think I say, like, how many times did like the guy who played Mr.
Miyagi, Pat Morita, like how many times did his birthday fall on a Tuesday during the Vietnam War?
You know, and I have like a simple R rule that is like standardized.
You can cast it to a string and pop it into Google Calendar.
And I can just easily do that with an R rule.
I say easily, but that's after maintaining an R rule library for use, right?
Like a random person.
Right, right.
But it does it.
I don't know.
It's like saying you can find that with a regular expression.
Yeah.
Right.
Yeah.
You can easily do that with a regular expression.
I will struggle with that regular expression, but it's fine.
But it's powerful.
It's cool.
All right.
Well, I think that's probably it for all the time we have.
We've run out of time talking about time, but there's been a lot to talk about.
It's very interesting.
Thanks.
So before you go, though, let me ask you the final two questions.
If you're going to write some Python code, what editor do you use?
I usually just dictate that to my secretary and just kidding.
That sounds good.
I usually use Vim.
I don't feel strongly about it, though.
So if anyone wants to, well, don't try and convince me about it, but also don't see that
it as an attack on your Emacs using Waze.
Like I just picked one at random.
Sure.
Sounds good.
And then notable PyPI package.
There's one that's really fun, but please don't like if you install it, do it in a virtual
environment or something.
It's called a break my Python.
You pip install it, and then it just makes it so that your Python is broken.
Like you can't, you don't have to import it to have your Python be broken.
You just do pip install break my Python.
And if you type Python, it won't work anymore.
It'll just break it.
That's break dash my dash Python.
All right.
So that's kind of an anti-recommendation.
That's interesting.
Very cool.
Funny.
If you want a real recommendation of something that's like fun and useful to use is I actually
do like pipX.
Oh, yeah.
PipX is cool.
I love pipX.
Yeah.
At this point, my main Python installation, well, my main Python installation stuff is
like super layered with all kinds of indirection.
So like everything is all pip and or not pip and pyenv environments.
So like I have 10 different pythons installed.
But even within those, I never pip install anything directly.
It's either like working in a virtual environment or if it's tools like talks or virtual env or
something like PEP 517.
Well, actually, that one doesn't really work.
Like glances or PT Python or any of those types of tools.
pytest.
mypy.
Yep.
PyLint.
All that stuff.
You just do pipX install whatever.
You do it like you're going to pip install it.
But what it does is it will install each one of these tools into their own virtual environments
and then just put on your path the entry points that they expose.
So you do pipX install mypy.
And then if you try to like if you open your Python and try and import some mypy like thing,
it won't be there.
But if you just type mypy, it'll work as if by magic.
And this avoids the whole situation of like different tools stepping on each other's dependencies
or needing to update all that stuff.
It's really great.
Yeah, I really like it.
To me, it feels like homebrew for Python utilities and applications, right?
Like on my Mac, I can brew install MongoDB.
I can brew install FFmpeg, all these things that I might need.
And they'll be installed separately and maintained.
And you know when there's updates.
PipX is that for things that are tools based on Python that you would pip install them.
It's really nice.
Yeah, I mean, except brew also kind of maybe has that same problem, right?
Where because it's like a system package manager.
I mean, they handle it for you.
Yeah, it's a little more.
Yeah, it's less isolated.
Yeah, I agree.
Yeah.
I mean, as long as you're not using your brew Python, right?
Like if you don't open up Python that you brew installed.
Exactly.
Cool.
All right.
Well, PipX is a fun recommendation.
And Breakmypython is a good joke as well.
All right.
I'm looking forward to dig into that to see how it actually breaks your Python.
All right.
Well, thank you for being here.
Final call to action.
People want to get their time zones and time in order.
I mean, obviously, the recommendations you had, the do's and don'ts stand.
We'll put a link to those.
Anything else you want to leave people with?
I think it's pretty good.
Like I think I'm very interested in getting people to migrate over to Zone Info.
So especially right now when there's not a huge number of people knocking at my door
to ask about that.
But feel free to, you know, open some issues on there or send me an email or at me on Twitter
or something.
And yeah, like get out there and, you know, maybe like tweet or Instagram or TikTok or whatever
the kids do these days to all your friends about how great PEP615 is.
And hopefully we can get the word out that you don't have to use PyTZ anymore.
Yeah, absolutely.
Well, thanks for working on all this stuff and handling all these edge cases for people.
That way we can mostly ignore them except for when we can't.
Yeah.
Thanks.
See you later.
All right.
Bye.
This has been another episode of Talk Python to Me.
Our guest on this episode was Paul Gansel and it's been brought to you by Brilliant.org
and us over at Talk Python Training.
Brilliant.org encourages you to level up your analytical skills and knowledge.
Visit talkpython.fm/brilliant and get Brilliant Premium to learn something new every day.
Want to level up your Python?
If you're just getting started, try my Python Jumpstart by Building 10 Apps course.
Or if you're looking for something more advanced, check out our new Async course that digs into
all the different types of async programming you can do in Python.
And of course, if you're interested in more than one of these, be sure to check out our
Everything Bundle.
It's like a subscription that never expires.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play,
and the direct RSS feed at /rss on talkpython.fm.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
Bye.
Thank you.