classification
Title: Add aware local time support to datetime module
Type: enhancement Stage:
Components: Extension Modules, Library (Lib) Versions: Python 3.2
process
Status: open Resolution:
Dependencies: No obvious and correct way to get the time zone offset, Time zone-capable variant of time.localtime
View: 1647654

View: 1667546
Superseder:
Assigned To: belopolsky Nosy List: Neil Muller, amaury.forgeotdarc, andersjm, belopolsky, catlee, davidfraser, eric.araujo, erik.stephens, guettli, haypo, hodgestar, jamesh, jribbens, loewis, mark.dickinson, pboddie, pitrou, r.david.murray, rhettinger, steve.roberts, techtonik, tim_one, tomster, werneck
Priority: normal Keywords: patch

Created on 2010-08-06 03:48 by belopolsky, last changed 2011-05-05 18:14 by r.david.murray.

Files
File name Uploaded Description Edit
datetime-localtime-proto.diff belopolsky, 2010-08-06 03:48 review
datetime-localtime-proto-1.diff belopolsky, 2011-01-14 19:39 review
Messages (8)
msg113067 - (view) Author: Alexander Belopolsky (belopolsky) (Python committer) Date: 2010-08-06 03:48
See python-dev post for motivation.

http://mail.python.org/pipermail/python-dev/2010-August/102842.html


I am attaching a patch implementing the proposed method in datetime.py.  I will also paste the code below.  Note that this is only prototype.  Real implementation will use tm_zone and tm_gmtoff components of tm structure on platforms that supply them.

    @classmethod
    def localtime(cls, t=None, isdst=-1):
        """Return local time as an aware datetime object.                                                                                                          
                                                                                                                                                                   
        If called without arguments, return current time.  Otherwise                                                                                               
        *t* is converted to local time zone according to the system                                                                                                
        time zone database.  If *t* is naive (i.e. t.tzinfo is None),                                                                                              
        it is assumed to be in local time.  In this case, a positive or                                                                                            
        zero value for *isdst* causes localtime to presume initially                                                                                               
        that summer time (for example, Daylight Saving Time) is or is                                                                                              
        not (respectively) in effect for the specified time.  A                                                                                                    
        negative value for *isdst* causes the localtime() function to                                                                                              
        attempt to divine whether summer time is in effect for the                                                                                                 
        specified time.                                                                                                                                            
        """
        if t is None:
            t = _time.time()
        else:
            if t.tzinfo is None:
                tm = t.timetuple()[:-1] + (isdst,)
                t = _time.mktime(tm)
            else:
                delta = t - datetime(1970, 1, 1, tzinfo=timezone.utc)
                t = delta.total_seconds()
        tm = _time.localtime(t)
        if _time.daylight:
            if tm.tm_isdst:
                offset = _time.altzone
                tzname = _time.tzname[1]
            else:
                offset = _time.timezone
                tzname = _time.tzname[0]
        tz = timezone(timedelta(seconds=-offset), tzname)
        return cls.fromtimestamp(t, tz)
msg113069 - (view) Author: Alexander Belopolsky (belopolsky) (Python committer) Date: 2010-08-06 03:55
Merging nosy lists from issues #1647654 and #2736.  If datetime.localtime() is implemented, I argue that the features requested in these two issues will become unnecessary.
msg118675 - (view) Author: Alexander Belopolsky (belopolsky) (Python committer) Date: 2010-10-14 15:52
Would anyone like to review this? The Rietveld link works (thanks Martin!) and I would like to get some feedback on the python version before I invest effort into coding this in C.
msg126292 - (view) Author: Alexander Belopolsky (belopolsky) (Python committer) Date: 2011-01-14 19:39
Following Anatoly's review, I renamed datetime argument and a local variable, added comments and expanded docstring.  I am uploading a new patch: datetime-localtime-proto-1.diff.

Martin, I could not figure out how to add the new patch to rietveld and I don't think auto-review feature works.
msg126295 - (view) Author: Alexander Belopolsky (belopolsky) (Python committer) Date: 2011-01-14 19:47
Forwarding Rietveld conversation to the tracker.  It looks like
Rietveld integration has a bug and sends reviews to
None@psf.upfronthosting.co.za rather than to report@bugs.python.org.

Forwarded conversation
Subject: Add aware local time support to datetime module (issue9527)
------------------------

From: <techtonik@gmail.com>
Date: Thu, Jan 13, 2011 at 7:14 PM
To: belopolsky@users.sourceforge.net
Cc: None@psf.upfronthosting.co.za

I'm not proficient in C and not an expert in datetime issues either, but
because nobody else stepped in to do review, I've left some comments.
Perhaps making the issue more acceptable by general public will help to
close it faster.

http://bugs.python.org/review/9527/diff/1568/2704
File Lib/datetime.py (right):

http://bugs.python.org/review/9527/diff/1568/2704#newcode1420
Lib/datetime.py:1420: def localtime(cls, t=None, isdst=-1):
The t param should probably be called 'time'.

http://bugs.python.org/review/9527/diff/1568/2704#newcode1421
Lib/datetime.py:1421: """Return local time as an aware datetime object.
ISTM that we need an object hierarchy like DateTime->DateTimeTZ, because
debugging which object is TZ aware and which is not is rather hard.

http://bugs.python.org/review/9527/diff/1568/2704#newcode1435
Lib/datetime.py:1435: t = _time.time()
Here we should always receive aware object, but I couldn't find
reference to C standard to ensure that all systems return this
correctly.

http://bugs.python.org/review/9527/diff/1568/2704#newcode1437
Lib/datetime.py:1437: if t.tzinfo is None:
I'd replace this with elif and place comment that here we detect
non-aware time object. Docstring above is nice, but it will probably be
parsed into documentation, and I am not sure if these details should be
present in user manual.

http://bugs.python.org/review/9527/diff/1568/2704#newcode1438
Lib/datetime.py:1438: tm = t.timetuple()[:-1] + (isdst,)
IIUC return result of time() value is time.struct_time which doesn't
have timetuple() method. If you work with datetime objects only, then
you need to name variables accordingly.

http://bugs.python.org/review/9527/show

----------
From: <techtonik@gmail.com>
Date: Fri, Jan 14, 2011 at 12:28 PM
To: belopolsky@users.sourceforge.net
Cc: None@psf.upfronthosting.co.za

On 2011/01/14 04:30:11, sasha wrote:
> Can you comment on whether you find the
> proposed function useful?  Is the interface intuitive?

I prefer to threat UTC time and timezone separately. My API wannabe:

global.time() - returns value that can be printed and it will be in UTC
global.offset() - difference in seconds between current timezone and UTC
(so that +2 will be 7200 seconds and -2 is -7200)
global.fromiso() - returns value parsed from ISO 8601 format, probably
pair (UTC time, offset)
global.toiso(time, [offset]) - for symmetry

Maybe its even better if global.time() returns tuple (UTC time, offset)

As you may see I am not interested in DST details etc. All I need is the
ability to parse and generate timestamps. If your datetime.localtime()
returns datetime object, how should I use it to generate Atom timestamp
with proper TZ modifier?

http://www.atomenabled.org/developers/syndication/atom-format-spec.php#date.constructs

In my low-level and non-OOP API it is:

global.toiso(global.time(), global.offset())

epoch as an
> argument (unlike the eponymous time module function).  It takes an
arbitrary
> datetime instance and converts it to an aware datetime instance with
tzinfo set
> to an appropriate fixed offset timezone.

At first I thought about datetime.toaware(dt), but this description of
yours is better than the one provided in docstring. If
datetime.localtime([dt]) gets local time in timezone aware object or
converts existing datetime (how about other types?), then the name
datetime.localtime() seems fine. But I would consider alternative
datetime.globaltime() name with the meaning that we get datetime object
that is globally synchronized, in other words it can be used not only
locally. .localtime() is ambiguous in this respect.
On 2011/01/14 04:30:11, sasha wrote:
> implementation.   I would not call it "time" because that conflicts
with the
> time class and localtime expects a datetime instance in t.

dt is a consistent name for datetime parameters in Python manual.
On 2011/01/14 04:30:11, sasha wrote:
> Early versions of datetime has a separate datetimetz class.  I don't
remember
> what were the actual reasons for removing it, but I am glad that this
was done.
> Hopefully applications will stop using naive datetime objects at some
point, so
> there will be less need to distinguish naive and aware instances.

It must be recorded for history if we want to get rid of date/time curse
in Python4 without missing any details. Removing naive objects in favor
of normalized objects with UTC timestamps seems like a way to go.
On 2011/01/14 04:30:11, sasha wrote:
> No.  _time.time() returns seconds since epoch. Naive/aware distinction
is not
> applicable.

But these seconds are in UTC. There is no TZ correction.
msg127516 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2011-01-30 04:56
I think Tim and Guido had deliberately avoided local timezone awareness when they designed the module.

Also, I question whether the proposed API is correct.  ISTM that any code that sets the *dst* parameter is guaranteed to be wrong (hardwiring-in a value that will change every few months).

Have you studied the solutions used in other libraries and other languages?  This path has been well-traveled, so original work may be less helpful than just researching existing solutions.
msg127517 - (view) Author: Alexander Belopolsky (belopolsky) (Python committer) Date: 2011-01-30 05:52
On Sat, Jan 29, 2011 at 11:56 PM, Raymond Hettinger
<report@bugs.python.org> wrote:
..
> Also, I question whether the proposed API is correct.  ISTM that any code that sets the *dst*
> parameter is guaranteed to be wrong (hardwiring-in a value that will change every few months).

Can you elaborate on this?  ISTM that your argument would equally
apply to C/POSIX mktime() API.  It won't be the first time C/POSIX got
time handling wrong, but I doubt it is the case in this instance.
msg135227 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2011-05-05 18:14
LocalTimezone support would be *really* helpful for the email module.  It would allow us to have unambiguous semantics for datetime objects representing timestamps exacted from or inserted into email messages (see issue 665194 for recent discussion).  The email module is already trying to handle timestamp translation, and I'd be willing to bet it is buggier than the proposal here.

At one point I even started to copy the LocalTimezone class from the docs into the email module.  I implemented a naive extension of the current formatdate function instead, but after Alexander's feedback on #665194 I think the naive implementation is not a good idea.
History
Date User Action Args
2011-07-20 15:46:22r.david.murrayunlinkissue665194 dependencies
2011-05-05 18:14:51r.david.murraysetnosy: + r.david.murray
messages: + msg135227
2011-05-05 16:44:03r.david.murraylinkissue665194 dependencies
2011-04-07 19:56:22belopolskyunlinkissue1475397 dependencies
2011-01-30 15:17:10tebekasetnosy: - tebeka
2011-01-30 05:52:55belopolskysetnosy: tim_one, loewis, jribbens, rhettinger, pboddie, jamesh, guettli, amaury.forgeotdarc, tebeka, mark.dickinson, davidfraser, belopolsky, pitrou, andersjm, catlee, haypo, techtonik, tomster, werneck, hodgestar, Neil Muller, eric.araujo, erik.stephens, steve.roberts
messages: + msg127517
2011-01-30 04:56:22rhettingersetnosy: + rhettinger
messages: + msg127516
2011-01-29 23:11:11belopolskysetnosy: tim_one, loewis, jribbens, pboddie, jamesh, guettli, amaury.forgeotdarc, tebeka, mark.dickinson, davidfraser, belopolsky, pitrou, andersjm, catlee, haypo, techtonik, tomster, werneck, hodgestar, Neil Muller, eric.araujo, erik.stephens, steve.roberts
dependencies: + No obvious and correct way to get the time zone offset
2011-01-29 23:08:24belopolskysetnosy: tim_one, loewis, jribbens, pboddie, jamesh, guettli, amaury.forgeotdarc, tebeka, mark.dickinson, davidfraser, belopolsky, pitrou, andersjm, catlee, haypo, techtonik, tomster, werneck, hodgestar, Neil Muller, eric.araujo, erik.stephens, steve.roberts
dependencies: + Time zone-capable variant of time.localtime
2011-01-14 19:48:20belopolskysetnosy: tim_one, loewis, jribbens, pboddie, jamesh, guettli, amaury.forgeotdarc, tebeka, mark.dickinson, davidfraser, belopolsky, pitrou, andersjm, catlee, haypo, techtonik, tomster, werneck, hodgestar, Neil Muller, eric.araujo, erik.stephens, steve.roberts
title: Add aware local time support to datetime module (issue9527) -> Add aware local time support to datetime module
2011-01-14 19:47:19belopolskysetnosy: tim_one, loewis, jribbens, pboddie, jamesh, guettli, amaury.forgeotdarc, tebeka, mark.dickinson, davidfraser, belopolsky, pitrou, andersjm, catlee, haypo, techtonik, tomster, werneck, hodgestar, Neil Muller, eric.araujo, erik.stephens, steve.roberts
messages: + msg126295
title: Add aware local time support to datetime module -> Add aware local time support to datetime module (issue9527)
2011-01-14 19:39:34belopolskysetfiles: + datetime-localtime-proto-1.diff
nosy: + loewis
messages: + msg126292

2011-01-12 01:44:32belopolskylinkissue7662 superseder
2011-01-10 23:52:22belopolskylinkissue1667546 superseder
2011-01-08 06:17:14belopolskylinkissue1475397 superseder
2010-12-01 18:56:13eric.araujosetnosy: + eric.araujo
2010-10-14 15:52:23belopolskysetmessages: + msg118675
2010-10-05 18:02:52belopolskylinkissue7582 dependencies
2010-09-13 13:46:05belopolskylinkissue1475397 dependencies
2010-08-06 13:56:36gvanrossumsetnosy: - gvanrossum
2010-08-06 03:55:58belopolskysetnosy: + gvanrossum, tim_one, jribbens, pboddie, jamesh, guettli, amaury.forgeotdarc, tebeka, mark.dickinson, davidfraser, pitrou, andersjm, catlee, haypo, techtonik, tomster, werneck, hodgestar, Neil Muller, erik.stephens, steve.roberts
messages: + msg113069
2010-08-06 03:52:10belopolskylinkissue1647654 superseder
2010-08-06 03:50:47belopolskylinkissue2736 superseder
2010-08-06 03:48:18belopolskycreate