Use datetime.strftime() on years before 1900? ("require year >= 1900") - python

I used :
utctime = datetime.datetime(1601,1,1) + datetime.timedelta(microseconds = tup[5])
last_visit_time = "Last visit time:"+ utctime.strftime('%Y-%m-%d %H:%M:%S')
But I have the time of 1601, so the error show:
ValueError: year=1601 is before 1900; the datetime strftime() methods require year >= 1900
I used python2.7, how can I make it? Thanks a lot!

You can do the following:
>>> utctime.isoformat()
'1601-01-01T00:00:00.000050'
Now if you want to have exactly the same format as above:
iso = utctime.isoformat()
tokens = iso.strip().split("T")
last_visit_time = "Last visit time: %s %s" % (tokens[0], tokens[1].strip().split(".")[0])
Not that there seems to be a patch for strftime to fix this behavior here (not tested)

the isoformat method accepts a parameter specifing the character(s) dividing the date part from the time part of a datetime obj in its representation. Therefore:
>>> utctime.isoformat(" ")
'1601-01-01 00:00:00.000050'
should do it.
Furthermore, if you want to remove the microseconds you can operate a split.
>>> utctime.isoformat(" ").split(".")[0]
'1601-01-01 00:00:00'

There are various ways to alter strftime so that it handles pre-1900 dates:
There's a recipe at ASPN that gives you a separate strftime method that you can call with a date object: aspn_recipe.strftime(dt, fmt) if you set it up in a module yourself
As #stephen-rumbalski said, the external mxDateTime package supports this; but that's using a totally different date object system
As of version 1.5, the virtualtime package will patch both time.strftime and datetime.datetime.strftime to behave as in Python 3.3+. You can take advantage of this without enabling the other virtual time functions. (Disclaimer: I work on this package)
Note that Python 2.7, 3.0 and 3.1 have errors before the year 1900, Python 3.2 has errors before the year 1000. Additionally, pre-3.2 versions interpret years between 0 and 99 as between 1969 and 2068. Python versions from 3.3 onward support all positive years in datetime (and negative years in time.strftime), and time.strftime doesn't do any mapping of years between 0 and 99.
The original Python bug explains that they decided that this was a feature in Python 2.7 (presumably since it avoided lack of system strftime support for these dates), and then gradually worked on it in the Python 3 series, by reimplementing functionality.

I recommend using arrow (which is an abstraction package on datetime and dateutil), it's really easy to handle every kind of datetime objects, even in Python 2.6/7.x and with dates prior to 1900.
For example:
>>> import arrow
>>> in_date_str = "1853-10-30T13:36:41.942623+00:00"
>>> in_date_obj = arrow.get(crea)
>>> print(in_date_obj)
arrow[1853-10-30T13:36:41.942623+00:00]>
# basic formatting
>>> in_date_obj.format()
u'1853-10-30 13:36:41-00:00'
# advanced formatting
>>> in_date_obj.format("dddd D MMMM YYYY", "fr_FR")
u'Dimanche 30 Octobre 1853'
# humanized delta
>>> in_date_obj.humanize()
u'162 years ago'
# easy localization handling
>>> in_date_obj.humanize(locale="fr_FR")
u'il y a 162 ans'

Related

Is it possible to extract a format string (e.g. "YY-mm-DD HH:MM:SS.sss") from a python datetime object? [duplicate]

Here's an array of datetime values:
array = np.array(['2016-05-01T00:00:59.3+10:00', '2016-05-01T00:02:59.4+10:00',
'2016-05-01T00:03:59.4+10:00', '2016-05-01T00:13:00.1+10:00',
'2016-05-01T00:22:00.5+10:00', '2016-05-01T00:31:01.1+10:00'],
dtype=object)
pd.to_datetime is very good at inferring datetime formats.
array = pd.to_datetime(array)
print(array)
DatetimeIndex(['2016-04-30 14:00:59.300000', '2016-04-30 14:02:59.400000',
'2016-04-30 14:03:59.400000', '2016-04-30 14:13:00.100000',
'2016-04-30 14:22:00.500000', '2016-04-30 14:31:01.100000'],
dtype='datetime64[ns]', freq=None)
How can I dynamically figure out what datetime format pd.to_datetime inferred? Something like: %Y-%m-%dT... (sorry, my datetime foo is really bad).
I don't think it's possible to do this in full generality in pandas.
As mentioned in other comments and answers, the internal function _guess_datetime_format is close to being what you ask for, but it has strict criteria for what constitutes a guessable format and so it will only work for a restricted class of datetime strings.
These criteria are set out in the _guess_datetime_format function on these lines and you can also see some examples of good and bad formats in the test_parsing script.
Some of the main points are:
year, month and day must each be present and identifiable
the year must have four digits
exactly six digits must be used if using microseconds
you can't specify a timezone
This means that it will fail to guess the format for datetime strings in the question despite them being a valid ISO 8601 format:
>>> from pandas.core.tools.datetimes import _guess_datetime_format_for_array
>>> array = np.array(['2016-05-01T00:00:59.3+10:00'])
>>> _guess_datetime_format_for_array(array)
# returns None
In this case, dropping the timezone and padding the microseconds to six digits is enough to make pandas to recognise the format:
>>> array = np.array(['2016-05-01T00:00:59.300000']) # six digits, no tz
>>> _guess_datetime_format_for_array(array)
'%Y-%m-%dT%H:%M:%S.%f'
This is probably as good as it gets.
If pd.to_datetime is not asked to infer the format of the array, or given a format string to try, it will just try and parse each string separately and hope that it is successful. Crucially, it does not need to infer a format in advance to do this.
First, pandas parses the string assuming it is (approximately) a ISO 8601 format. This begins in a call to _string_to_dts and ultimately hits the low-level parse_iso_8601_datetime function that does the hard work.
You can check if your string is able to be parsed in this way using the _test_parse_iso8601 function. For example:
from pandas._libs.tslib import _test_parse_iso8601
def is_iso8601(string):
try:
_test_parse_iso8601(string)
return True
except ValueError:
return False
The dates in the array you give are recognised as this format:
>>> is_iso8601('2016-05-01T00:00:59.3+10:00')
True
But this doesn't deliver what the question asks for and I don't see any realistic way to recover the exact format that is recognised by the parse_iso_8601_datetime function.
If parsing the string as a ISO 8601 format fails, pandas falls back to using the parse() function from the third-party dateutil library (called by parse_datetime_string). This allows a fantastic level of parsing flexibility but, again, I don't know of any good way to extract the recognised datetime format from this function.
If both of these two parsers fail, pandas either raises an error, ignores the string or defaults to NaT (depending on what the user specifies). No further attempt is made to parse the string or guess the format of the string.
DateInfer (PyDateInfer) library allows to infer dates based on the sequence of available dates:
github.com/wdm0006/dateinfer
Usage from docs:
>>> import dateinfer
>>> dateinfer.infer(['Mon Jan 13 09:52:52 MST 2014', 'Tue Jan 21 15:30:00 EST 2014'])
'%a %b %d %H:%M:%S %Z %Y'
>>>
Disclaimer: I have used and then contributed to this library
You can use _guess_datetime_format from core.tools to get the format. ie
from pandas.core.tools import datetimes as tools
tools._guess_datetime_format(pd.to_datetime(array).format()[0][:10])
Output :
'%Y-%m-%d'
To know more about this method you can see here. Hope it helps.

How to implement calendar in Python?

For example I give the date as:
2/12/2015
The result should be:
February/Thursday/2015
I tried to do with if but I'm not getting the result. It would be nice if you could tell me the long way (without using built in functions (like datetime and others) too much). I'm new to python and not much is taught in my school.
You don't have to use datetime too much, simply parse the date and output it in whatever format you want
from datetime import datetime
d = "2/12/2015"
print(datetime.strptime(d,"%m/%d/%Y").strftime("%B/%A/%Y"))
February/Thursday/2015
A = Locale’s full weekday name.
B = Locale’s full month name.
Y = Year with century as a decimal number.
All the format directives are here
You could create a dict mapping but you will find datetime is lot simpler.

BC dates in Python

I'm setting out to build an app with Python that will need to handle BC dates extensively (store and retrieve in DB, do calculations). Most dates will be of various uncertainties, like "around 2000BC".
I know Python's datetime library only handles dates from 1 AD.
So far I only found FlexiDate. Are there any other options?
EDIT: The best approach would probably be to store them as strings (have String as the basic data type) and -as suggested- have a custom datetime class which can make some numerical sense of it. For the majority it looks like dates will only consist of a year. There are some interesting problems to solve like "early 500BC", "between 1600BC and 1500BC", "before 1800BC".
Astronomers and aerospace engineers have to deal with BC dates and a continuous time line, so that's the google context for your search.
Astropy's Time class will work for you (and even more precisely and completely than you hoped). pip install astropy and you're on your way.
If you roll your own, you should review some of the formulas in Vallado's chapter on dates. There are lots of obscure fudge factors required to convert dates from Julian to Gregorian etc.
Its an interesting question, it seems odd that such a class does not exist yet (re #joel Cornett comment) If you only work in years only it would simplify your class to handling integers rather than calendar dates - you could possibly use a dictionary with the text description (10 BC) against and integer value (-10)
EDIT: I googled this:
http://code.activestate.com/lists/python-list/623672/
NASA Spice functions handle BC extremely well with conversions from multiple formats. In these examples begin_date and end_date contain the TDB seconds past the J2000 epoch corresponding to input dates:
import spiceypy as spice
# load a leap second kernel
spicey.furnsh("path/to/leap/second/kernel/naif0012.tls")
begin_date = spice.str2et('13201 B.C. 05-06 00:00')
end_date = spice.str2et('17191 A.D. 03-15 00:00')
Documentation of str2et(),
Input format documentation, as well as
Leapsecond kernel files are available via the NASA Spice homepage.
converting from datetime or other time methods to spice is simple:
if indate.year < 0.0:
spice_indate = str(indate.year) + ' B.C. ' + sindate[-17:]
spice_indate = str(spice_indate)[1:]
else:
spice_indate = str(indate.year) + ' A.D. ' + sindate[-17:]
'2018 B.C. 03-31 19:33:38.44'
Other functions include: TIMOUT, TPARSE both converting to and from J2000 epoch seconds.
These functions are available in python through spiceypy, install e.g. via pip3 install spiceypy
This is an old question, but I had the same one and found this article announcing datautil, which is designed to handle dates like:
Dates in distant past and future including BC/BCE dates
Dates in a wild variety of formats: Jan 1890, January 1890, 1st Dec 1890, Spring 1890 etc
Dates of varying precision: e.g. 1890, 1890-01 (i.e. Jan 1890), 1890-01-02
Imprecise dates: c1890, 1890?, fl 1890 etc
Install is just
pip install datautil
I explored it for only a few minutesso far, but have noted that it doesn't accept str as an argument (only unicode) and it implements its own date class (Flexidate, 'a slightly extended version of ISO8601'), which is sort of useful maybe.
>>> from datautil.date import parse
>>> parse('Jan 1890')
error: 'str' object has no attribute 'read'
>>> fd = parse(u'Jan 1890')
<class 'datautil.date.FlexiDate'> 1890-01
fd.as_datetime()
>>> datetime.datetime(1890, 1, 1, 0, 0)
>>> bc = parse(u'2000BC')
<class 'datautil.date.FlexiDate'> -2000
but alas...
>>> bc.as_datetime()
ValueError: year is out of range
Unfortunately for me, I was looking for something that could handle dates with "circa" (c., ca, ca., circ. or cca.)
>>> ca = parse(u'ca 1900')
<class 'datautil.date.FlexiDate'> [UNPARSED: ca 1900]
Oh well - I guess I can always send a pull request ;-)

validate date : python

I want to know how to convert different format dates to expected format in python .
ex : i want to get this format : 2/29/2012
['2012-02-01 // 2012-02-28', '2/15/2012', '2/13/2012', '2/14/2012', '2/23/2012', '2/18/2012', '2/29/2012']
How to check today date in the range '2012-02-01 // 2012-02-28'
Share your suggestions
Use the datetime library in python. You can just compare two different datetime.datetime objects. And you can separate the year, month, date thing to put it in anyform you want.
Check this link for all the library details.
http://docs.python.org/library/datetime.html
Hope that helped.
The dateutil python library parses a wider variety of date formats than the standard datetime module.

How can I convert an RFC 822 timestamp into a human readable format in Python?

Does anyone know of a Python module that will convert an RFC 822 timestamp into a human readable format (like Twitter does) in Python?
I found parsedatetime, which seems to do the reverse.
In python, you can use rfc822 module. This module provides the parsedate method.
Attempts to parse a date according to the rules in RFC 2822.
However, this module is deprecated.
Deprecated since version 2.3: The email package should be used in preference to the rfc822 module. This module is present only to maintain backward compatibility, and has been removed in 3.0.
According to this comment, it's better to use the parsedate method from the email.utils module.
email.utils.parsedate(date)
EDIT:
Example code :
import email.utils
from time import mktime
from datetime import datetime
example_date = "Sat, 02 Mar 2011 15:00:00"
date_parsed = email.utils.parsedate(example_date)
dt = datetime.fromtimestamp(mktime(date_parsed))
today = datetime.today()
diff_date = today - dt # timedelta object
print "%s days, %s hours ago" \
% (diff_date.days, diff_date.seconds / 3600)
Output (for now) :
31 days, 2 hours ago
datetime.strptime will turn the times stamp into a datetime object which you can format with datetime.strftime
http://docs.python.org/library/datetime.html#strftime-strptime-behavior
See
http://docs.python.org/library/rfc822.html#rfc822.parsedate

Categories