From leewangzhong+python at gmail.com Tue Dec 8 19:34:19 2015 From: leewangzhong+python at gmail.com (Franklin? Lee) Date: Tue, 8 Dec 2015 19:34:19 -0500 Subject: [Datetime-SIG] Allow numerical arguments for timezones Message-ID: (Originally posted at http://bugs.python.org/issue25428) Proposal: Functions in `datetime` which take a `tzinfo` object should allow, as an alternative, a numerical argument, which would be interpreted as the number of hours. There are time zones with half-hour offsets, so floats should be allowed. Current: To create a `datetime` object with a particular time zone offset, from datetime import datetime, timezone, timedelta mytime = datetime(2015, 10, 16, 9, 13, 0, tzinfo=timezone(timedelta(hours=-7))) That's two extra imports and two extra objects created. Suggested way: mytime = datetime(2015, 10, 16, 9, 13, 0, tzinfo=-7) # mytime.tzinfo == -7 # or: mytime.tzinfo == timezone(timedelta(-7)) Alternatively, introduce a new keyword parameter to explictily indicate hours: mytime = datetime(2015, 10, 16, 9, 13, 0, tzhours=-7) # mytime.tzinfo == timezone(timedelta(-7)) Rationale: For time zones, hours are the normal unit of time. At least, I think about time zones in hours, and I don't know who would think about them in minutes. Imagine you have about a year of experience dabbling in Python, and you're trying to do a relatively simple task, like reading PDT times and converting them to local time. You would go to the datetime docs, and see that you need to pass in a tzinfo object. You look up `tzinfo`: """tzinfo is an abstract base class, meaning that this class should not be instantiated directly. You need to derive a concrete subclass, and (at least) supply implementations of the standard tzinfo methods needed by the datetime methods you use.""" Well, great. If you want to convert times, you'll have to subclass an abstract base class (if you know what that means), and implement five methods. You'd probably have to read the whole docs for this ABC, too. (The docs for `tzinfo` are nine pages long on my screen.) If you're not frightened off by the first two sentences, you'll see that there's the concrete subclass `datetime.timezone`. We're two levels down, now. Going there, you'll see that you need to pass in a `datetime.timedelta` object. Three levels. You need to learn three classes to specify an hour offset: `tzinfo`, `timezone`, and `timedelta`. Time zones are something that many non-programmers understand, and the rules are pretty simple (except for DST). Ideally, it should be simple to do simple things. PS: There seems to be an unnecessary naming inconsistency with `.astimezone`, `fromtimestamp`, and `now` taking a `tz` kwarg rather than a `tzinfo` kwarg. From 4kir4.1i at gmail.com Wed Dec 9 06:38:32 2015 From: 4kir4.1i at gmail.com (Akira Li) Date: Wed, 09 Dec 2015 14:38:32 +0300 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: (Franklin's message of "Tue, 8 Dec 2015 19:34:19 -0500") References: Message-ID: <87poyf4zt3.fsf@gmail.com> "Franklin? Lee" writes: > (Originally posted at http://bugs.python.org/issue25428) > > Proposal: Functions in `datetime` which take a `tzinfo` object should > allow, as an alternative, a numerical argument, which would be > interpreted as the number of hours. There are time zones with > half-hour offsets, so floats should be allowed. > > Current: To create a `datetime` object with a particular time zone offset, > > from datetime import datetime, timezone, timedelta > mytime = datetime(2015, 10, 16, 9, 13, 0, > tzinfo=timezone(timedelta(hours=-7))) > > That's two extra imports and two extra objects created. > > > Suggested way: > mytime = datetime(2015, 10, 16, 9, 13, 0, tzinfo=-7) > # mytime.tzinfo == -7 > # or: mytime.tzinfo == timezone(timedelta(-7)) > > Alternatively, introduce a new keyword parameter to explictily indicate hours: > mytime = datetime(2015, 10, 16, 9, 13, 0, tzhours=-7) > # mytime.tzinfo == timezone(timedelta(-7)) timedelta(-7) is 7 *days* Such simple errors are an argument against using unlabeled integers instead of objects that know that they represent days, hours, etc. > > Rationale: > > For time zones, hours are the normal unit of time. At least, I think > about time zones in hours, and I don't know who would think about them > in minutes. > > Imagine you have about a year of experience dabbling in Python, and > you're trying to do a relatively simple task, like reading PDT times > and converting them to local time. You would go to the datetime docs, > and see that you need to pass in a tzinfo object. You look up > `tzinfo`: > > """tzinfo is an abstract base class, meaning that this class should > not be instantiated directly. You need to derive a concrete subclass, > and (at least) supply implementations of the standard tzinfo methods > needed by the datetime methods you use.""" > > Well, great. If you want to convert times, you'll have to subclass an > abstract base class (if you know what that means), and implement five > methods. You'd probably have to read the whole docs for this ABC, too. > (The docs for `tzinfo` are nine pages long on my screen.) > > If you're not frightened off by the first two sentences, you'll see > that there's the concrete subclass `datetime.timezone`. We're two > levels down, now. Going there, you'll see that you need to pass in a > `datetime.timedelta` object. Three levels. You need to learn three > classes to specify an hour offset: `tzinfo`, `timezone`, and > `timedelta`. > > Time zones are something that many non-programmers understand, and the > rules are pretty simple (except for DST). Ideally, it should be simple > to do simple things. > Using integers would encourage a wrong model. It is incorrect to equate a utc offset and a time zone. Many time zones have different utc offsets at different dates. Most areas in North America and Europe observe DST https://en.wikipedia.org/wiki/Daylight_saving_time_by_country I would understand if you were to suggest to use the timezone names, to simplify usage: dt = datetime(2015, 10, 16, 9, 13, 0, tzinfo='America/Los_Angeles') The only way to get a reasonable (on the scale of correctness vs. complexity tradeoffs) answer is to use libraries built on top of *pytz* package at the moment: tz = pytz.timezone('America/Los_Angeles') dt = tz.localize(datetime(2015, 10, 16, 9, 13), is_dst=None) > PS: There seems to be an unnecessary naming inconsistency with > `.astimezone`, `fromtimestamp`, and `now` taking a `tz` kwarg rather > than a `tzinfo` kwarg. > _______________________________________________ > Datetime-SIG mailing list > Datetime-SIG at python.org > https://mail.python.org/mailman/listinfo/datetime-sig > The PSF Code of Conduct applies to this mailing list: https://www.python.org/psf/codeofconduct/ From chris.barker at noaa.gov Thu Dec 10 19:46:54 2015 From: chris.barker at noaa.gov (Chris Barker) Date: Thu, 10 Dec 2015 16:46:54 -0800 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: <87poyf4zt3.fsf@gmail.com> References: <87poyf4zt3.fsf@gmail.com> Message-ID: yeah, now that datetime has the fixed offset timezone object out of the box, this may well make sense. On Wed, Dec 9, 2015 at 3:38 AM, Akira Li <4kir4.1i at gmail.com> wrote: > "Franklin? Lee" writes: > > mytime = datetime(2015, 10, 16, 9, 13, 0, tzinfo=-7) > > # mytime.tzinfo == -7 > > # or: mytime.tzinfo == timezone(timedelta(-7)) > > > > Alternatively, introduce a new keyword parameter to explictily indicate > hours: > > mytime = datetime(2015, 10, 16, 9, 13, 0, tzhours=-7) > > # mytime.tzinfo == timezone(timedelta(-7)) > > timedelta(-7) is 7 *days* > > Such simple errors are an argument against using unlabeled integers > instead of objects that know that they represent days, hours, etc. > Except he made this error creating the timedelta object anyway -- so no help there. But a new keyword would make this pretty clear: mytime = datetime(2015, 10, 16, 9, 13, 0, tzhours=-7) if you can't figure out that tzhours is expected to be units of hours, we can forget the whole thing! I have to agree: mytime = datetime(2015, 10, 16, 9, 13, 0, tzinfo=timezone(timedelta(hours=-7))) is pretty wordy, and requires a fair bit of digging into the docs to understand. though an example of this in the docs would be a good start. And yes, in the general case, "timezones" are NOT fixed-offset -- but working with fixed-offset data is pretty common. I would understand if you were to suggest to use the timezone names, to > simplify usage: > > dt = datetime(2015, 10, 16, 9, 13, 0, tzinfo='America/Los_Angeles') > well, that's a whole other ball of wax, requiring a database that's maintained. There was a PEP For that, but I don't think it's going forward. but anyway, the OP WANTS a fixed-offset -- NOT a region, politically driven timezone -- there should be a way to get that easily -- the only issue is whether explicitly creating a timezone object with a timedelta object s easy enough. I'm actually surprised that the built- in timezone class takes a timedelta -- this seems to be a heavyweight object-oriented, statically types style approach :-) -- I've never seen a timezone offset described anyting other than hours -- why not use that? -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker at noaa.gov -------------- next part -------------- An HTML attachment was scrubbed... URL: From guido at python.org Thu Dec 10 20:09:37 2015 From: guido at python.org (Guido van Rossum) Date: Thu, 10 Dec 2015 17:09:37 -0800 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: There definitely are timezones with other offsets than whole hours ( http://www.timeanddate.com/time/time-zones-interesting.html). The reason that timezone() takes a timedelta is to avoid mistakes in the units. The world is better off with a recipe or an example in the docs than with yet another variant to this API. -- --Guido van Rossum (python.org/~guido) -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.belopolsky at gmail.com Thu Dec 10 20:20:24 2015 From: alexander.belopolsky at gmail.com (Alexander Belopolsky) Date: Thu, 10 Dec 2015 20:20:24 -0500 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: On Thu, Dec 10, 2015 at 8:09 PM, Guido van Rossum wrote: > The reason that timezone() takes a timedelta is to avoid mistakes in the > units. That was more or less the original reasoning. Note that an early prototype required the offset to be specified in minutes. [1] I don't expect people to have to construct timezone objects "by hand". You would normally get tzinfo populated with a local timezone by calling .astimezone() on a UTC instance: >>> from datetime import * >>> dt = datetime.now(timezone.utc) >>> print(dt.astimezone()) 2015-12-10 20:19:34.446688-05:00 [1]: http://bugs.python.org/issue5094#msg106911 -------------- next part -------------- An HTML attachment was scrubbed... URL: From guido at python.org Thu Dec 10 20:26:31 2015 From: guido at python.org (Guido van Rossum) Date: Thu, 10 Dec 2015 17:26:31 -0800 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: My guess is that the OP is parsing dates that have a numerical TZ offset (like most date formats found in internet protocols like http or email headers). But there's really no substitute for just calling datetime(....., tzinfo=timezone(timedelta(hours=......))) On Thu, Dec 10, 2015 at 5:20 PM, Alexander Belopolsky < alexander.belopolsky at gmail.com> wrote: > > On Thu, Dec 10, 2015 at 8:09 PM, Guido van Rossum > wrote: > >> The reason that timezone() takes a timedelta is to avoid mistakes in the >> units. > > > That was more or less the original reasoning. Note that an early > prototype required the offset to be specified in minutes. [1] > > I don't expect people to have to construct timezone objects "by hand". > You would normally get tzinfo populated with a local timezone by calling > .astimezone() on a UTC instance: > > >>> from datetime import * > >>> dt = datetime.now(timezone.utc) > >>> print(dt.astimezone()) > 2015-12-10 20:19:34.446688-05:00 > > [1]: http://bugs.python.org/issue5094#msg106911 > -- --Guido van Rossum (python.org/~guido) -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.belopolsky at gmail.com Thu Dec 10 20:29:57 2015 From: alexander.belopolsky at gmail.com (Alexander Belopolsky) Date: Thu, 10 Dec 2015 20:29:57 -0500 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: On Thu, Dec 10, 2015 at 8:20 PM, Alexander Belopolsky < alexander.belopolsky at gmail.com> wrote: > > Note that an early prototype required the offset to be specified in minutes. [1] .. and the idea of allowing (float) number of hours was also discussed [2] and ultimately rejected. [1]: http://bugs.python.org/issue5094#msg106911 [2]: http://bugs.python.org/issue5094#msg106980 -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander.belopolsky at gmail.com Thu Dec 10 20:35:06 2015 From: alexander.belopolsky at gmail.com (Alexander Belopolsky) Date: Thu, 10 Dec 2015 20:35:06 -0500 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: On Thu, Dec 10, 2015 at 8:26 PM, Guido van Rossum wrote: > My guess is that the OP is parsing dates that have a numerical TZ offset > (like most date formats found in internet protocols like http or email > headers). > If datetime.strptime() does not satisfy OP needs already, I am +1 for improving it. We have an open issue for that already: < http://bugs.python.org/issue24954>. > But there's really no substitute for just calling > > datetime(....., tzinfo=timezone(timedelta(hours=......))) > This is ugly, but hopefully you won't see this outside of timezone support library functions. -------------- next part -------------- An HTML attachment was scrubbed... URL: From rosuav at gmail.com Thu Dec 10 20:40:24 2015 From: rosuav at gmail.com (Chris Angelico) Date: Fri, 11 Dec 2015 12:40:24 +1100 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: On Fri, Dec 11, 2015 at 11:46 AM, Chris Barker wrote: > Except he made this error creating the timedelta object anyway -- so no help > there. But a new keyword would make this pretty clear: > > mytime = datetime(2015, 10, 16, 9, 13, 0, tzhours=-7) > > if you can't figure out that tzhours is expected to be units of hours, we > can forget the whole thing! > > And yes, in the general case, "timezones" are NOT fixed-offset -- but > working with fixed-offset data is pretty common. Is that because information about political timezone has been lost, or because there is a real need for arithmetic on a fixed-offset non-zero timezone? If the former, any sort of arithmetic is meaningless, so all that can really be done is convert it to UTC. (Which can be done pretty easily with a timedelta.) >> I would understand if you were to suggest to use the timezone names, to >> simplify usage: >> >> dt = datetime(2015, 10, 16, 9, 13, 0, tzinfo='America/Los_Angeles') > > > well, that's a whole other ball of wax, requiring a database that's > maintained. There was a PEP For that, but I don't think it's going forward. You mean PEP 431, withdrawn by its author? I think that post-PEP-495, this could be revived (or an equivalent put together). What I'd like to see is a simple recipe for an aware datetime, nice and high in the docs. The best I've found is this: https://docs.python.org/3.5/library/datetime.html#datetime.datetime.utcnow which suggests that datetime.datetime.now(datetime.timezone.utc) is the way to do this. If that is indeed the correct solution, it'd be good to push that higher in the docs. If it isn't, there definitely needs to be something else. I'm also more than a little confused about the right way to construct non-now() aware datetimes, as this appears to work: datetime.datetime(2015,12,11,1,34,49,tzinfo=datetime.timezone.utc) but people recommend pytz.localize instead. > but anyway, the OP WANTS a fixed-offset -- NOT a region, politically driven > timezone -- there should be a way to get that easily -- the only issue is > whether explicitly creating a timezone object with a timedelta object s easy > enough. I can't think of any real-world use-cases for an actual fixed-offset timezone. Usually these are either fake (like when you parse an RFC822 time), or incorrect (when you're trying to represent "local time" in any way - although it might happen to mostly work in places without DST). OP, can you explain more of what you're needing? > I'm actually surprised that the built- in timezone class takes a timedelta > -- this seems to be a heavyweight object-oriented, statically types style > approach :-) -- I've never seen a timezone offset described anyting other > than hours -- why not use that? With the understanding that UTC offsets can be fractional hours, yes, this might be a useful short-hand. Most places in the world have offsets that are a multiple of 0.25 hours, so float hours would cover that easily. Working with historical times usually will need the proper tzinfo database anyway. ChrisA From leewangzhong+python at gmail.com Fri Dec 11 00:23:16 2015 From: leewangzhong+python at gmail.com (Franklin? Lee) Date: Fri, 11 Dec 2015 00:23:16 -0500 Subject: [Datetime-SIG] Allow numerical arguments for timezones In-Reply-To: References: <87poyf4zt3.fsf@gmail.com> Message-ID: On Thu, Dec 10, 2015 at 8:40 PM, Chris Angelico wrote: > On Fri, Dec 11, 2015 at 11:46 AM, Chris Barker wrote: >> but anyway, the OP WANTS a fixed-offset -- NOT a region, politically driven >> timezone -- there should be a way to get that easily -- the only issue is >> whether explicitly creating a timezone object with a timedelta object s easy >> enough. > > I can't think of any real-world use-cases for an actual fixed-offset > timezone. Usually these are either fake (like when you parse an RFC822 > time), or incorrect (when you're trying to represent "local time" in > any way - although it might happen to mostly work in places without > DST). OP, can you explain more of what you're needing? I'm thinking about throwaway code, not robust applications that really need to know about DST and political changes.. I'm also thinking about use at a lower level of expertise: people learning Python, playing around with it, etc. Quick-and-dirty scripting. I might also want to keep certain kinds of logs in fixed-time offsets, for a compromise between ease of mental processing and ease of comparison. I think I was working on parsing timestamps from a game server which does NOT properly handle DST. The server location and my target timezone are usually a fixed time apart, so I could've used a timedelta, but I thought it made more sense to express it as a difference of timezones. From alexander.belopolsky at gmail.com Fri Dec 11 11:17:59 2015 From: alexander.belopolsky at gmail.com (Alexander Belopolsky) Date: Fri, 11 Dec 2015 11:17:59 -0500 Subject: [Datetime-SIG] Fixed offset timezones Message-ID: On Thu, Dec 10, 2015 at 8:40 PM, Chris Angelico wrote: > I can't think of any real-world use-cases for an actual fixed-offset > timezone. Usually these are either fake (like when you parse an RFC822 > time), or incorrect (when you're trying to represent "local time" in > any way - although it might happen to mostly work in places without > DST). > You certainly know one important "real-world use-case for an actual fixed-offset timezone": UTC. In fact, when datetime.timezone was introduced in Python, support for UTC was the main motivation. Arbitrary fixed offset timezones were added primarily because once we've already paid a price of adding a timezone class to the datetime module, support for arbitrary fixed offset timezones came essentially for free. Non-UTC fixed offset timezones are quite useful when your timestamps come with UTC offset information. Once you parse such timestamps into aware datetime instances (using strptime or your own parser), you can do almost everything you want with the result: convert to UTC, reformat/serialize for further transmission, compute time differences, etc. The only operation that is slightly odd is the addition of a timedelta which may give you a result that uses winter time offset in the summer. Note that the result is not wrong - just not what some users may expect. -------------- next part -------------- An HTML attachment was scrubbed... URL: