Path: csiph.com!usenet.pasdenom.info!goblin2!goblin.stu.neva.ru!newsfeed.xs4all.nl!newsfeed3.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; '(at': 0.04; 'argument': 0.05; 'encoding': 0.05; 'true,': 0.05; 'subject:Python': 0.06; '(b)': 0.07; 'javascript,': 0.07; 'method.': 0.07; 'ugly': 0.07; 'assumed': 0.09; 'bytes,': 0.09; 'lookup': 0.09; 'oh,': 0.09; 'part,': 0.09; 'valueerror:': 0.09; 'whatever.': 0.09; 'cc:addr :python-list': 0.11; 'python': 0.11; 'bug': 0.12; 'jan': 0.12; 'archive': 0.14; 'times,': 0.14; '(which,': 0.16; '57,': 0.16; 'born.': 0.16; 'debugging,': 0.16; 'digits.': 0.16; 'discuss.': 0.16; 'displayed.': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'integer,': 0.16; 'operation.': 0.16; 'partly': 0.16; 'peak': 0.16; 'reasonably': 0.16; 'repr': 0.16; 'roy': 0.16; 'sure.': 0.16; 'time.time()': 0.16; 'timestamp': 0.16; 'timestamps': 0.16; 'underlying': 0.16; 'unsigned': 0.16; 'utc': 0.16; 'windows:': 0.16; 'fix': 0.17; 'wrote:': 0.18; 'module': 0.19; 'written': 0.21; '>>>': 0.22; 'shell': 0.22; 'cc:addr:python.org': 0.22; 'print': 0.22; '(a)': 0.24; 'instance,': 0.24; 'month,': 0.24; '(or': 0.24; 'cc:2**0': 0.24; "i've": 0.25; 'handling': 0.26; 'nearly': 0.26; 'this:': 0.26; 'least': 0.26; 'skip:" 20': 0.27; 'header:In-Reply-To:1': 0.27; 'point': 0.28; 'chris': 0.29; '[1]': 0.29; 'am,': 0.29; 'unix': 0.29; 'message-id:@mail.gmail.com': 0.30; "i'm": 0.30; 'that.': 0.31; '"",': 0.31; 'file': 0.32; 'class': 0.32; 'there.': 0.32; 'probably': 0.32; 'stuff': 0.32; 'another': 0.32; 'text': 0.33; '(i.e.': 0.33; '(most': 0.33; 'cases': 0.33; 'fri,': 0.33; 'raw': 0.33; 'skip:t 40': 0.33; 'maybe': 0.34; 'subject:the': 0.34; 'could': 0.34; 'problem': 0.35; "can't": 0.35; 'agree': 0.35; 'common': 0.35; 'knows': 0.35; 'problem.': 0.35; 'something': 0.35; 'definition': 0.35; 'operations': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'there': 0.35; 'like,': 0.36; 'object,': 0.36; 'done': 0.36; 'next': 0.36; 'useful': 0.36; 'thanks': 0.36; 'should': 0.36; 'seconds': 0.37; 'so,': 0.37; 'turn': 0.37; 'list': 0.37; 'represent': 0.38; 'depends': 0.38; 'easiest': 0.38; 'somebody': 0.38; 'anything': 0.39; 'recent': 0.39; 'ability': 0.39; 'does': 0.39; 'mentioned': 0.61; 'today,': 0.61; 'traffic': 0.61; 'range': 0.61; 'simply': 0.61; 'simple': 0.61; 'times': 0.62; 'information': 0.63; 'happen': 0.63; 'skip:n 10': 0.64; 'our': 0.64; 'grab': 0.64; 'more': 0.64; 'different': 0.65; 'here': 0.66; 'direct': 0.67; 'invalid': 0.68; 'smith': 0.68; 'obvious': 0.74; 'day': 0.76; 'article': 0.77; "everything's": 0.84; 'ms.': 0.84; 'support:': 0.84; '"how': 0.91; 'notion': 0.91; 'to:none': 0.92; 'lot,': 0.93 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:cc :content-type; bh=EMONlwFQJg4SDbDCqfPYaBmVWVswDJ2rekAOrta1Knw=; b=gQW4SFH3rTq/7AvmFrD/pR+4wqByKuJEk0BuK8cCfPolCy3g2FkpJM6iLQ1I2ACDKt 6wm9utFVGleZIQhx5ixo3i9w4eeOrNWFXI4uAAzGo7HyZUqS3JQP0u9hjDPSp+fOIL2X 2XnpOfCYFEQMwlqwUgwpc7Kl6RiP2Vuu/geVf3bY+B6GxA1Yc+XMR2xdWgBCJ8Uad1fc 4E0Apx5vmQY1eB6dOvgf6byY+tXYgIrbYwoBKsZA/TehkqlyhPaUZo1HfUxkW9C+9h9/ e2W1jvIsMdfziBO0ubHUwAIcWP5lg55kq5T+izSTTb4n4Mvv/N2ltyuEvzeadmdE3jNL KPRw== MIME-Version: 1.0 X-Received: by 10.66.163.36 with SMTP id yf4mr4199259pab.67.1389279478040; Thu, 09 Jan 2014 06:57:58 -0800 (PST) In-Reply-To: References: <4b702$52cc262e$541826b9$22985@cache80.multikabel.net> <4cbf$52cc2e82$541826b9$11761@cache70.multikabel.net> <686$52cd4640$541826b9$21896@cache1.tilbu1.nb.home.nl> <52CE3416.9090501@stoneleaf.us> <7wiottej72.fsf@benfinney.id.au> Date: Fri, 10 Jan 2014 01:57:57 +1100 Subject: Re: the Gravity of Python 2 From: Chris Angelico Cc: "python-list@python.org" Content-Type: text/plain; charset=UTF-8 X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 108 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1389279482 news.xs4all.nl 2936 [2001:888:2000:d::a6]:55581 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:63602 On Fri, Jan 10, 2014 at 1:14 AM, Roy Smith wrote: > In article , > Chris Angelico wrote: > >> What can you (Roy), with your use-case, achieve with datetime that >> you can't achieve (at least reasonably easily) with a timestamp? Thanks for this collection! Now we can discuss. > As I'm mentioned several times, when you print a datetime, you get > something that's human friendly. When you print a timestamp (i.e. a > float), you get a lot of digits. I don't know about you, but I can't > look at 1389274842 and get any feel for whether that was in the middle > of the night or at 5 in the afternoon, near our peak traffic time. Nor > can I tell if it was today, yesterday, last month, or a week from next > Tuesday. Sure. There is a lot of value in having a class that knows how it should be displayed. I'm not sure the current datetime repr is good for anything more than debugging, but I agree that "datetime.datetime(2014, 1, 9, 5, 57, 59, 929176)" is more likely to be useful than a raw number. > Datetimes make it easy to do things like, "find the time of the > preceding (or following) midnight". Or, "what month is this timestamp > part of?" These are operations we need to do a lot, to answer questions > like, "How many unique users did we have on a given day?", or "Which > monthly database archive file do I need to grab to get information about > this historical event?" That's true; the same operations done with timestamps look like this: >>> ts = time.time() >>> ts_at_midnight_utc = ts - ts%86400 >>> ts_at_midnight_utc 1389225600.0 Not nearly as obvious what's happening. And months are more complicated still, so it's probably easiest to use strftime: >>> time.strftime("%Y%m",time.gmtime(ts)) '201401' which could then be used as a lookup key for a counter or whatever. Yep, that's not as clean as simply calling a method. > Datetimes are self-documenting. If I'm in the python shell and have > something called t, I can do help(t) or dir(t) to find out what > operations it has. Partly true, but not everything's there. For instance, if you have a list of strings, you won't find a way to join them together in its help() or dir(), and yet it's a fundamental and very important operation. > Datetimes are self-describing. If I have a datetime or a timedelta, I > know what I've got. I've written more than one bug where I assumed a > number somebody handed me was in seconds but it turned out to be in ms. > That can never happen with a timedelta. We do a lot of stuff in > javascript, where times are ms, so this is a common problem for us. Sure. Though that's no different from other cases where you need out-of-band information to understand something, as we've just been discussing in the threads about text handling - if you have a puddle of bytes, you can't decode them to text without knowing what the encoding is. [1] If your data's coming from JS, it won't be a timedelta, it'll be a number; at some point you have to turn that into a timedelta object, so you still have the same problem. > Oh, and another thing I can do with a datetime that I can't do with a > unix timestamp. I can represent the day I was born. Maybe you can't with the original C definition of time_t as an unsigned integer, but the notion of a Unix timestamp can plausibly be extended (a) to negative numbers, and (b) to non-integers. Python definitely does the latter; its ability to do the former depends somewhat on the underlying C library's support: Windows: >>> time.strftime("%Y%m",time.gmtime(-100000)) Traceback (most recent call last): File "", line 1, in time.strftime("%Y%m",time.gmtime(-100000)) OSError: [Errno 22] Invalid argument Linux: >>> time.strftime("%Y%m",time.gmtime(-100000)) '196912' >>> time.strftime("%Y%m",time.gmtime(-2**31)) '190112' >>> time.strftime("%Y%m",time.gmtime(-2**31-1)) Traceback (most recent call last): File "", line 1, in ValueError: timestamp out of range for platform time_t So what I'm seeing here is that the direct use of a time_t will cover everything in an ugly way, but that a class wrapping it up could fix that. And fundamentally, the only problem with datetime (which, for the most part, is exactly that wrapper) is that it's unobvious how to get a simple UTC timestamp. Has the unobviousness been solved by a simple recipe? And if so, should that tip be added to the datetime module docs somewhere? ChrisA [1] Yes, I said "puddle of bytes". What would you call it? Am interested to hear!