Basically, the Pendulum class is a replacement for the native datetime one with some useful and intuitive methods, the Interval class is intended to be a better time delta class and, finally, the Period class is a datetime-aware timedelta.
Timezones are also easier to deal with: Pendulum will automatically normalize your datetime to handle DST transitions for you.
import pendulum
pendulum.create(2013, 3, 31, 2, 30, 0, 0, 'Europe/Paris’)
# 2:30 for the 31th of March 2013 does not exist
# so pendulum will return the actual time which is 3:30+02:00
'2013-03-31T03:30:00+02:00’
dt = pendulum.create(2013, 3, 31, 1, 59, 59, 999999, 'Europe/Paris’)
'2013-03-31T01:59:59.999999+01:00’
dt = dt.add(microseconds=1)
'2013-03-31T03:00:00+02:00’
dt.subtract(microseconds=1)
'2013-03-31T01:59:59.999998+01:00’
To those wondering: yes I know [Arrow](http://crsmithdev.com/arrow/) exists but its flaws and strange API (you can throw almost anything at get() and it will do its best to determine what you wanted, for instance) motivated me to start this project. You can check why I think Arrow is flawed here: https://pendulum.eustace.io/faq/#why-not-arrow
Cool library, I'll definitely be looking into this more closely in the future. The automatic handling of ambiguous time during timezone transitions is curious. As an example, Django punts on automatic handling and requires a user to choose between pre and post transition (I wrote the is_dst handling): https://github.com/django/django/blob/19e20a2a3f763388bba926...
What if you were to begin with a time at 3:30 and then subtract an hour. Would your library properly return 1:30? What if a user had a naive time at 3:30, subtracted an hour, and then converted to an aware time using your library? For what it's worth, I think moving to 3:30 is the correct behaviour in the vast amount of cases. Requiring a user to provide a direction to move and throwing an exception if they don't is dangerous. How often are users going to see this exception, if at all? Just wondering how much you've considered cases, if they exist, that would be better off moving to 1:30.
I'll add one more thing. As soon as I started browsing the page I thought "why would I use this over arrow?". Great to see you addressed that by default. I didn't know about some of arrows shortcomings/bugs, so they were really useful.
Handling dates, times, and timezones in particular is a tricky problem, as evident by the large number of libraries in each language trying to get it right. If you haven't already, I'd really recommend reading the blog posts of Jon Skeet regarding Noda Time http://blog.nodatime.org/ and https://codeblog.jonskeet.uk/category/nodatime/ even if it turns up some corner cases you haven't considered, or validates ones you have.
I can't decide if auto-normalizing my times to DST is a feature or anti-feature. If I didn't know it was there, I would consider it a surprising default.
This area is prone to severe bikeshedding. Back in 2012, I filed a Python bug, "datetime: add ability to parse RFC 3339 dates and times"[1] RFC 3339 timestamps appear in email, RSS feeds, etc. The datetime library could output them, but not parse them. There are at least seven parsing functions in PyPi for them, and each has some major problem.
There have been steady discussions of this issue for almost four years now. I dropped out years ago, but the arguments go on.
Where exactly in email to do they appear? In the header, it's been my experience they all conform to the RFC 2822 spec, and could be parsed with the standard library function email.utils.parsedate_tz[1].
Past bikeshedding, there's also the long list of myths programmers believe about time[1] and the crowd-sourced followup[2]. Pendulum inherits from datetime in the stdlib, but I'm unsure how well either of those address the issues raised (or even if it's possible - some need to be addressed by the code that uses pendulum/datetime).
I know pandas is a bit meaty for a date time library if you don't already use it but their Timestamp class is awesome. String parsing is a breeze, offsets and timezones are easy and then there's a ton of support for time series.
In [34]: pd.Timestamp('2016-08') == pd.Timestamp('2016.08') == pd.Timestamp('2016/08') == pd.Timestamp('08/2016')
Out[34]: True
In [38]: pd.Timestamp('2016') == pd.Timestamp(datetime.datetime(2016,1,1))
Out[38]: True
In [49]: pd.Timestamp('2016') + pd.offsets.MonthOffset(months=7) == pd.Timestamp('2016-08')
Out[49]: True
In [52]: pd.Timestamp.now()
Out[52]: Timestamp('2016-08-17 08:01:07.576323')
In [53]: pd.Timestamp.now() + pd.offsets.MonthBegin(normalize=True)
Out[53]: Timestamp('2016-09-01 00:00:00')
I don't understand why this library exists. I am (literally) manipulating datetimes for a living in a Django app this whole year and we don't even have Arrow installed.
Pytz and maybe dateutil is all you need.
Also I really hate when someone fragment the energy and their time making a new, inferior library instead of fixing and patching the existings for basic things like this.
This way we will have a bunch of incomplete, inferior libraries which all have quirks instead of only one really good one which could everybody use...
I don't see what the big deal is. These people are spending their own time making libraries, and not using up your time. Are you to judge how people should make use of their time?
Second, I think it's great that people are making alternatives - it promotes a healthier ecosystem where people can share good ideas as well.
> instead of fixing and patching the existings
Finally, by your logic, the popular requests library shouldn't have existed and Kenneth would have been patching the more conventional urllib library
Django provides django.utils.timezone to make handling dates and times easier. Not every python project has access to django.utils.timezone. pytz is mostly what you need to get timezones right, but there's still room for something like this.
Also manipulating datetimes for a living (telemetry + billing). The reason I stick with Arrow despite its slowing maintainership? Its ability to round up or down time along a granularity: http://crsmithdev.com/arrow/#arrow.arrow.Arrow.floor
Looks like a nice polished interface.
I am wondering what is Pendulum's policy on invalid input. The examples illustrate the inconsistent approach to invalid inputs:
In some cases it guesses what you meant:
>>> pendulum.create(2013, 3, 31, 2, 30, 0, 0, 'Europe/Paris')
'2013-03-31T03:30:00+02:00' # 2:30 does not exist (Skipped time)
In other cases, it raises exceptions:
pendulum.parse('2016-06-31')
# ValueError: day is out of range for month
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..
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?
The README for Pendulum seems to show me one feature Delorean doesn't explicitly have -- `is_weekend()` -- otherwise these libraries are conceptually very similar.
I do agree that this (and Delorean) is a usability improvement over `datetime` and perhaps even Arrow (though I'm not tremendously familiar with Arrow).
Mainly, its API which tries to be as close as possible as the one provided by the standard datetime library while providing a bunch of helpful methods.
Also, Pendulum is not just about datetimes but also provides both the Interval class and Period class which are improvements over the native timedelta class.
And finally, it handles properly time shifting around DST transition times and normalization of datetimes when creating them which neither Delorean nor Arrow do well.
I've been happily using django.utils.timezone for a while now and doing everything on the backend in UTC. For any user-facing timestamps, to some degree I'd rather keep that in the front end and a separate concern from my API.
Not saying storing user timezone and converting on the backend is bad; but this is simpler when localized timestamps aren't a core part of my app.
Yes, always work in UTC. But you could use this library to convert user provided naive datetimes to UTC, and datetimes coming from the database into localised datetimes. Converting from/to timezones other than UTC in Django isn't as nice as it could be.
What about precision? There is the Date object with day-precision and the Datetime object with microsecond precision ... but nothing else. There's no canonical way in Python with any library that I know of to say "July, 2013" or even "12:15pm". The former will simply put in July 1st and the latter will put in seconds and microseconds implying precision that doesn't exist.
Anybody know of an elegant solution/library or even a library that would be open to including such a concept?
numpy does this, with np.datetime64('2013-07') or np.datetime64('2013-07-01 12:15'). I wouldn't recommend using it if you're not otherwise using numpy, though.
Good to see we're starting to come close to getting dates and times handled according to the rules (I won't say sensibly, because the rules themselves aren't sensible). But then we start over-reaching and trying to handle social constructs built on top of dates and times, which is even more of a mess D:
Eg, spot the error:
_weekend_days = [SATURDAY, SUNDAY]
date.is_weekend = date.day in _weekend_days
I think the `in_words()` function should probably be delimited by commas though, good to have your strings easily deconstructed into their constituent parts.
[+] [-] sdispater|9 years ago|reply
It is heavily inspired by [Carbon](http://carbon.nesbot.com) for PHP.
Basically, the Pendulum class is a replacement for the native datetime one with some useful and intuitive methods, the Interval class is intended to be a better time delta class and, finally, the Period class is a datetime-aware timedelta.
Timezones are also easier to deal with: Pendulum will automatically normalize your datetime to handle DST transitions for you.
To those wondering: yes I know [Arrow](http://crsmithdev.com/arrow/) exists but its flaws and strange API (you can throw almost anything at get() and it will do its best to determine what you wanted, for instance) motivated me to start this project. You can check why I think Arrow is flawed here: https://pendulum.eustace.io/faq/#why-not-arrowLink to the official documentation: https://pendulum.eustace.io/docs/
Link to the github project: https://github.com/sdispater/pendulum
[+] [-] jsmeaton|9 years ago|reply
What if you were to begin with a time at 3:30 and then subtract an hour. Would your library properly return 1:30? What if a user had a naive time at 3:30, subtracted an hour, and then converted to an aware time using your library? For what it's worth, I think moving to 3:30 is the correct behaviour in the vast amount of cases. Requiring a user to provide a direction to move and throwing an exception if they don't is dangerous. How often are users going to see this exception, if at all? Just wondering how much you've considered cases, if they exist, that would be better off moving to 1:30.
I'll add one more thing. As soon as I started browsing the page I thought "why would I use this over arrow?". Great to see you addressed that by default. I didn't know about some of arrows shortcomings/bugs, so they were really useful.
Handling dates, times, and timezones in particular is a tricky problem, as evident by the large number of libraries in each language trying to get it right. If you haven't already, I'd really recommend reading the blog posts of Jon Skeet regarding Noda Time http://blog.nodatime.org/ and https://codeblog.jonskeet.uk/category/nodatime/ even if it turns up some corner cases you haven't considered, or validates ones you have.
Thanks!
[+] [-] tedmiston|9 years ago|reply
[+] [-] dvl|9 years ago|reply
[+] [-] was_boring|9 years ago|reply
[+] [-] antar|9 years ago|reply
[+] [-] Animats|9 years ago|reply
There have been steady discussions of this issue for almost four years now. I dropped out years ago, but the arguments go on.
[1] https://bugs.python.org/issue15873
[+] [-] jgalt212|9 years ago|reply
Where exactly in email to do they appear? In the header, it's been my experience they all conform to the RFC 2822 spec, and could be parsed with the standard library function email.utils.parsedate_tz[1].
[1] https://docs.python.org/2/library/email.util.html#email.util...
[+] [-] fragmede|9 years ago|reply
[1] http://infiniteundo.com/post/25326999628/falsehoods-programm... [2] http://infiniteundo.com/post/25509354022/more-falsehoods-pro...
[+] [-] abuckenheimer|9 years ago|reply
[+] [-] jonathanpoulter|9 years ago|reply
[+] [-] Walkman|9 years ago|reply
Also I really hate when someone fragment the energy and their time making a new, inferior library instead of fixing and patching the existings for basic things like this. This way we will have a bunch of incomplete, inferior libraries which all have quirks instead of only one really good one which could everybody use...
[+] [-] pandatigox|9 years ago|reply
Second, I think it's great that people are making alternatives - it promotes a healthier ecosystem where people can share good ideas as well.
> instead of fixing and patching the existings Finally, by your logic, the popular requests library shouldn't have existed and Kenneth would have been patching the more conventional urllib library
[+] [-] jsmeaton|9 years ago|reply
[+] [-] kdeldycke|9 years ago|reply
[+] [-] koliber|9 years ago|reply
In some cases it guesses what you meant:
In other cases, it raises exceptions:[+] [-] baq|9 years ago|reply
[+] [-] forgotpwtomain|9 years ago|reply
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..
[+] [-] d0mine|9 years ago|reply
Related: http://stackoverflow.com/questions/441147/how-can-i-subtract...
[+] [-] bjt|9 years ago|reply
I don't see anything unreasonable about Pendulum's interface. Let's let Python be Python and Ruby be Ruby.
[+] [-] JelteF|9 years ago|reply
[+] [-] calpaterson|9 years ago|reply
[+] [-] josefdlange|9 years ago|reply
The README for Pendulum seems to show me one feature Delorean doesn't explicitly have -- `is_weekend()` -- otherwise these libraries are conceptually very similar.
I do agree that this (and Delorean) is a usability improvement over `datetime` and perhaps even Arrow (though I'm not tremendously familiar with Arrow).
[+] [-] sdispater|9 years ago|reply
Also, Pendulum is not just about datetimes but also provides both the Interval class and Period class which are improvements over the native timedelta class.
And finally, it handles properly time shifting around DST transition times and normalization of datetimes when creating them which neither Delorean nor Arrow do well.
[+] [-] ak217|9 years ago|reply
[+] [-] tedmiston|9 years ago|reply
Not saying storing user timezone and converting on the backend is bad; but this is simpler when localized timestamps aren't a core part of my app.
[+] [-] jsmeaton|9 years ago|reply
[+] [-] AdamN|9 years ago|reply
Anybody know of an elegant solution/library or even a library that would be open to including such a concept?
[+] [-] epistemenical|9 years ago|reply
[+] [-] savrajsingh|9 years ago|reply
[+] [-] Shish2k|9 years ago|reply
Eg, spot the error:
Hint: https://en.wikipedia.org/wiki/Workweek_and_weekend#Around_th...(TIL one country doesn't even have consecutive weekend days)
[+] [-] sdispater|9 years ago|reply
[+] [-] fastball|9 years ago|reply
I think the `in_words()` function should probably be delimited by commas though, good to have your strings easily deconstructed into their constituent parts.
[+] [-] fastball|9 years ago|reply
[deleted]