Hacker News new | ask | show | jobs
by forgotpwtomain 3593 days ago
Python stdlib datetime/time/calendar libs are junk. That one constantly has to read obscure function signatures in the docs to do rather obvious things is just awful.

On the otherhand if you've e.g. Ruby/Rails datetime handling than you get used to reasonable things working ( such as Time.now + 1.day ) that Arrow doesn't handle well. As a matter of fact Arrow got rid of DT deltas and seemingly made the situation worse.

I've only looked at the examples in the docs; but to be serious, Python should just scrap their DT/time/calendar libs and copy Ruby verbatim. This NIH thing needs to stop..

4 comments

Does Time.now + 1.day return the time 24 hours into the future or does it return the same time (hour:minutes) but the next date? (it may be more or less than 24 hours from now if the UTC offset has changed for any reason e.g., due a DST transition). How do you express these different cases in Ruby explicitly?

Related: http://stackoverflow.com/questions/441147/how-can-i-subtract...

1.day? I confess to not being a Rubyist, but does that require monkeypatching the base int class?

I don't see anything unreasonable about Pendulum's interface. Let's let Python be Python and Ruby be Ruby.

I am a rubyist for over a decade now, and while I don't have a problem with the monkeypatching per se, I don't think anyone should be holding up ActiveSupport's time zone support as a paragon of good API design. Yes, on the surface it looks pretty nice, but because of the weird mix of different classes and extensions you get a frankenstein API that is a very leaky abstraction. I could dig up a raft of examples, but just off the top of my head... Date.today respects the global setting of Time.zone, but Date.yesterday always gives you the UTC date. The inconsistencies and permutations of Date, DateTime, Time, and TimeWithZone, combined with machine clock, Time.zone global, and UTC lead to so much confusion that the only way to ensure correctness is to declare a subset of the API which you always use, and reject everything else just so your team gets used to reasoning about it.

Sorry for the rant, but I've spent many years as the only California developer for a time based in the UK, suffering the tyranny of developers who spend half their year blissfully living in UTC and unknowingly foisting off their dirty time zone bugs on me.

Similar idea to Ruby's .times() method [0].

[0]: http://ruby-doc.org/core-1.9.3/Integer.html#method-i-times

Well, for a long time, letting "Python be Python" required dealing with absolutely terrible time zone support. As an example, Python's strptime only got timezone support (in %z) in version 3.2 in 2011.
No, don't think so. I think this is a native syntax construct in Ruby.
1.day is not a native Ruby concept, it is a method monkeypatched into the Numeric class by Rails' ActiveSupport. See http://api.rubyonrails.org/classes/Numeric.html#method-i-day and https://ruby-doc.org/core-2.2.0/Numeric.html.
I can see how people think it is native Ruby. Very few people use Ruby without Rails.
I just added a feature proposal to this library with a similar syntax to this but in a Pythonic way. import pendulum as pm

    now_in_paris = pm.now('Europe/Paris')
    tomorrow_in_paris = now_in_paris + pm.day
    next_week_in_paris = now_in_paris + 7*pm.day
https://github.com/sdispater/pendulum/issues/17

    >>> from datetime import datetime, timedelta
    >>> datetime.now() - (datetime.now() + timedelta(days=1))
    datetime.timedelta(-2, 86399, 999969)
I’m not entirely sure what you were trying to demonstrate, but clearly the result of datetime.now() changes between the two invocations (it has microsecond precision).

Try:

    >>> from datetime import datetime, timedelta
    >>> now = datetime.now()
    >>> now - (now + timedelta(days=1))
    datetime.timedelta(-1)
datetime.timedelta internally uses a triple of (days,seconds,microseconds) to represent it's data and exposes that to users of the class.

That a timedelta can be represented in multiple ways is alone quite surprising but some of the representations that happen can be very confusing. I think the example I gave which represents "-1 day and a few microseconds" as "-2 days + 86399 milliseconds + 999969 microseconds" is very surprising and it commonly happens in practice.

For comparison, here's what postgres does:

    postgres=> select now() - (now() + '12 milliseconds'::interval + '1 day'::interval);
           ?column?        
    -----------------------
     -1 days -00:00:00.012
    (1 row)
That's a problem Pendulum is trying to solve

    d1 = datetime(2012, 1, 1, 1, 2, 3, tzinfo=pytz.UTC)
    d2 = datetime(2011, 12, 31, 22, 2, 3, tzinfo=pytz.UTC)
    delta = d2 - d1
    delta.days
    -1
    delta.seconds
    75600
    
    d1 = Pendulum(2012, 1, 1, 1, 2, 3)
    d2 = Pendulum(2011, 12, 31, 22, 2, 3)
    delta = d2 - d1
    delta.days
    0
    delta.hours
    -3