Related
Is there any way to automatically parse strings with time only to datetime.time object (or something similar)? Same for datetime.date.
I've tried dateutil, arrow, moment, pandas.to_datetime.
All these parsers create timestamps with a current date.
>>> from dateutil.parser import parse
>>> parse('23:53')
datetime.datetime(2019, 1, 8, 23, 53) # datetime.time(23, 53) expected
>>> parse('2018-01-04')
datetime.datetime(2018, 1, 4, 0, 0) # datetime.date(2018, 1, 4) expected
UPD:
Thanks for the responses. Think that I should clarify the problem.
The program doesn't know what will be in the input (timestamp, date or time), and it should decide to set appropriate type. The problem is to distinguish these types.
For example, I can parse 23:53 and get a timestamp. How can I decide to extract the time from it or not?
You can use fromisoformat() from datetime.
import datetime
datetime.time.fromisoformat('23:53')
datetime.date.fromisoformat('2018-01-04')
What you basically want is for '23:53' to become a datetime.time object and for '2018-01-04' to become a datetime.date object. This cannot be achieved by using dateutil.parser.parse():
Returns a datetime.datetime object or, if the fuzzy_with_tokens option is True, returns a tuple, the first element being a datetime.datetime object, the second a tuple containing the fuzzy tokens.
From the documentation. So you'll always get a datetime.datetime object when using dateutil.parser.parse()
I would guess you need to interpret the input string yourself to define wether you're trying to parse a time or a date. When you do that, you can still use the dateutil.parser.parse() function to get the object you want:
from dateutil.parser import parse
my_time = parse('23:53')
my_time.time() # datetime.time(23, 53)
my_time.date() # datetime.date(2019, 1, 8)
Here you have an example. Just set the date attributes with replace, and select the output with strftime.
import datetime
date = datetime.datetime.now()
newdate = date.replace(hour=11, minute=59)
print(newdate.strftime('%H:%M'))
newdate2 = date.replace(year=2014, month=1, day=3)
print(newdate2.strftime('%Y-%m-%d'))
You can use either time or datetime modules, but one thing to bear in mind, is that these always create an object, that specifies a moment in time. (Also, if parsing strings, consider using the strptime function and displaying as string, strftime function respectively)
e.g.
>>> hours = time.strptime("23:59", "%H:%M")
>>> days = time.strptime("2018-01-04", "%Y-%m-%d")
>>> time.strftime("%H:%M", hours)
'23:59'
>>> time.strftime("%H:%M %Y", hours)
'23:59 1900'
Not recommended, but if you wish to separate these two object for some reason and wish to only care for a specific portion of your assignement, you can still adress the respective numbers with
>>> hours.tm_hour
23
>>> hours.tm_min
59
>>> days.tm_mon
1
>>> days.tm_mday
4
>>> days.tm_year
2018
A far better approach, in my opinion would be formatting the complete date string and using the strptime to form a complete timestamp - even if you get the time and date as separate inputs:
>>> ttime = "22:45"
>>> dday = "2018-01-04"
You can use the % formatter, or the "new" python f-Strings
>>> complete_t_string = "{} {}".format(dday, ttime)
>>> complete_t_string
'2018-01-04 22:45'
Now that we have a complete string, we can specify how it should be read and create a complete timestamp:
>>> complete_time = time.strptime(complete_t_string, "%Y-%m-%d %H:%M")
>>> complete_time
time.struct_time(tm_year=2018, tm_mon=1, tm_mday=4, tm_hour=22, tm_min=45, tm_sec=0, tm_wday=3, tm_yday=4, tm_isdst=-1)
EDIT:
Somebody will probably kill me, but if you absolutely know that you will only get two types of values, you could just do a simple try / except construct. It can probably be written more Pythonically:
try:
time.strptime(t_string, "%H:%M")
except ValueError:
time.strptime(t_string, "%Y-%m-%d")
I need to convert a python object datetime.time to an arrow object.
y = datetime.time()
>>> y
datetime.time(0, 0)
>>> arrow.get(y)
TypeError: Can't parse single argument type of '<type 'datetime.time'>'
Arrow follows a specific format, as specified in its documentation:
arrow.get('2013-05-11T21:23:58.970460+00:00')
you need to convert your datetime object to arrow-understandable format in order to be able to convert it to an arrow object. the codeblock below should work:
from datetime import datetime
import arrow
arrow.get(datetime.now())
A datetime.time object holds "An idealized time, independent of any particular day". Arrow objects cannot represent this kind of partial information, so you have to first "fill it out" with either today's date or some other date.
from datetime import time, date, datetime
t = time(12, 34)
a = arrow.get(datetime.combine(date.today(), t)) # <Arrow [2019-11-14T12:34:00+00:00]>
a = arrow.get(datetime.combine(date(1970, 1, 1), t)) # <Arrow [1970-01-01T12:34:00+00:00]>
You can use the strptime class method of the arrow.Arrow class and apply the appropriate formattting:
y = datetime.time()
print(arrow.Arrow.strptime(y.isoformat(), '%H:%M:%S'))
# 1900-01-01T00:00:00+00:00
However, you'll notice the date value is default, so you're probably better off parsing a datetime object instead of a time object.
If I print a datetime object in python with a simple print myDateTime (or print(myDateTime) in python3), how can I recover the datetime object from the resulting string?
I could have asked "what is the python strftime format used by datetime.__str__()"?
ps: There are many questions about conversion of strings to python datetime objects. In the spirit of using stack overflow as a repository of quickly available, useful programming tips, I'm asking this since none of those questions answer this rather specific and oft needed query.
By definition, str(datetime_obj) is datetime_obj.isoformat(' '). There is no method that would parse the ISO 8601 format back; you have to provide the format to strptime() explicitly:
>>> from datetime import datetime, timezone
>>> now = datetime.now(timezone.utc)
>>> s = str(now)
>>> s
'2015-04-06 10:31:08.256426+00:00'
>>> s[:26]
'2015-04-06 10:31:08.256426'
>>> datetime.strptime(s[:26]+s[26:].replace(':',''), '%Y-%m-%d %H:%M:%S.%f%z')
datetime.datetime(2015, 4, 6, 10, 31, 8, 256426, tzinfo=datetime.timezone.utc)
%z supports +HHMM but it doesn't support +HH:MM that is why the replace() call is used here.
datetime.timezone is available since Python 3.2. For older versions, see
How to parse ISO formatted date in python?
Convert timestamps with offset to datetime obj using strptime.
If the datetime object doesn't have timezone info (perhaps interpreted as UTC time), you can do something like this (python 2 in this case, but the same in python 3):
import datetime
unprintStrptimeFmt = "%Y-%m-%d %H:%M:%S.%f"
d = datetime.datetime.utcnow()
print d
# produces e.g.: 2015-04-06 03:11:23.840526
dd = datetime.datetime.strptime("2015-04-06 03:11:23.840526",unprintStrptimeFmt)
print dd == d
# produces: True
I have dt = datetime(2013,9,1,11), and I would like to get a Unix timestamp of this datetime object.
When I do (dt - datetime(1970,1,1)).total_seconds() I got the timestamp 1378033200.
When converting it back using datetime.fromtimestamp I got datetime.datetime(2013, 9, 1, 6, 0).
The hour doesn't match. What did I miss here?
solution is
import time
import datetime
d = datetime.date(2015,1,5)
unixtime = time.mktime(d.timetuple())
If you want to convert a python datetime to seconds since epoch you should do it explicitly:
>>> import datetime
>>> datetime.datetime(2012, 04, 01, 0, 0).strftime('%s')
'1333234800'
>>> (datetime.datetime(2012, 04, 01, 0, 0) - datetime.datetime(1970, 1, 1)).total_seconds()
1333238400.0
In Python 3.3+ you can use timestamp() instead:
>>> import datetime
>>> datetime.datetime(2012, 4, 1, 0, 0).timestamp()
1333234800.0
What you missed here is timezones.
Presumably you've five hours off UTC, so 2013-09-01T11:00:00 local and 2013-09-01T06:00:00Z are the same time.
You need to read the top of the datetime docs, which explain about timezones and "naive" and "aware" objects.
If your original naive datetime was UTC, the way to recover it is to use utcfromtimestamp instead of fromtimestamp.
On the other hand, if your original naive datetime was local, you shouldn't have subtracted a UTC timestamp from it in the first place; use datetime.fromtimestamp(0) instead.
Or, if you had an aware datetime object, you need to either use a local (aware) epoch on both sides, or explicitly convert to and from UTC.
If you have, or can upgrade to, Python 3.3 or later, you can avoid all of these problems by just using the timestamp method instead of trying to figure out how to do it yourself. And even if you don't, you may want to consider borrowing its source code.
(And if you can wait for Python 3.4, it looks like PEP 341 is likely to make it into the final release, which means all of the stuff J.F. Sebastian and I were talking about in the comments should be doable with just the stdlib, and working the same way on both Unix and Windows.)
Rather than this expression to create a POSIX timestamp from dt,
(dt - datetime(1970,1,1)).total_seconds()
Use this:
int(dt.strftime("%s"))
I get the right answer in your example using the second method.
EDIT: Some followup... After some comments (see below), I was curious about the lack of support or documentation for %s in strftime. Here's what I found:
In the Python source for datetime and time, the string STRFTIME_FORMAT_CODES tells us:
"Other codes may be available on your platform.
See documentation for the C library strftime function."
So now if we man strftime (on BSD systems such as Mac OS X), you'll find support for %s:
"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."
Anyways, that's why %s works on the systems it does. But there are better solutions to OP's problem (that take timezones into account). See #abarnert's accepted answer here.
For working with UTC timezones:
time_stamp = calendar.timegm(dt.timetuple())
datetime.utcfromtimestamp(time_stamp)
You've missed the time zone info (already answered, agreed)
arrow package allows to avoid this torture with datetimes; It is already written, tested, pypi-published, cross-python (2.6 — 3.xx).
All you need: pip install arrow (or add to dependencies)
Solution for your case
dt = datetime(2013,9,1,11)
arrow.get(dt).timestamp
# >>> 1378033200
bc = arrow.get(1378033200).datetime
print(bc)
# >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
print(bc.isoformat())
# >>> '2013-09-01T11:00:00+00:00'
If your datetime object represents UTC time, don't use time.mktime, as it assumes the tuple is in your local timezone. Instead, use calendar.timegm:
>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60
def dt2ts(dt, utc=False):
if utc:
return calendar.timegm(dt.timetuple())
if dt.tzinfo is None:
return int(time.mktime(dt.timetuple()))
utc_dt = dt.astimezone(tz.tzutc()).timetuple()
return calendar.timegm(utc_dt)
If you want UTC timestamp :time.mktime just for local dt .Use calendar.timegm is safe but dt must the utc zone so change the zone to utc. If dt in UTC just use calendar.timegm.
def datetime_to_epoch(d1):
"""
January 1st, 1970 at 00:00:00 UTC is referred to as the Unix epoch
:param d1: input date
:return: seconds since unix epoch
"""
if not d1.tzinfo:
raise ValueError("date is missing timezone information")
d2 = datetime(1970, 1, 1, tzinfo=timezone.utc)
time_delta = d1 - d2
ts = int(time_delta.total_seconds())
return ts
def epoch_to_datetime_string(timestamp, tz_name="UTC", **kwargs):
"""
method to convert unix timestamp to date time string
:param ts: 10 digit unix timestamp in seconds
:param tz_name: timezone name
:param kwargs: formatter=<formatter-string>
:return: date time string in timezone
"""
naive_date = datetime.fromtimestamp(timestamp)
aware_date = naive_date.astimezone(pytz.timezone(tz_name))
formatter = kwargs.pop("formatter", "%d %b %Y %H:%M:%S")
return aware_date.strftime(formatter)
Well, when converting TO unix timestamp, python is basically assuming UTC, but while converting back it will give you a date converted to your local timezone.
See this question/answer;
Get timezone used by datetime.datetime.fromtimestamp()
This class will cover your needs, you can pass the variable into ConvertUnixToDatetime & call which function you want it to operate based off.
from datetime import datetime
import time
class ConvertUnixToDatetime:
def __init__(self, date):
self.date = date
# Convert unix to date object
def convert_unix(self):
unix = self.date
# Check if unix is a string or int & proceeds with correct conversion
if type(unix).__name__ == 'str':
unix = int(unix[0:10])
else:
unix = int(str(unix)[0:10])
date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')
return date
# Convert date to unix object
def convert_date(self):
date = self.date
# Check if datetime object or raise ValueError
if type(date).__name__ == 'datetime':
unixtime = int(time.mktime(date.timetuple()))
else:
raise ValueError('You are trying to pass a None Datetime object')
return type(unixtime).__name__, unixtime
if __name__ == '__main__':
# Test Date
date_test = ConvertUnixToDatetime(datetime.today())
date_test = date_test.convert_date()
print(date_test)
# Test Unix
unix_test = ConvertUnixToDatetime(date_test[1])
print(unix_test.convert_unix())
import time
from datetime import datetime
time.mktime(datetime.now().timetuple())
I have variable which holds time which is of type datetime.time in UTC, I wanted it to convert to some other timezone.
we can convert timezones in datetime.datetime instance as shown in this SO link - How do I convert local time to UTC in Python?. I am not able to figure out how to convert timezones in datetime.time instances. I can't use astimezone because datetime.time doesn't have this method.
For example:
>>> t = d.datetime.now().time()
>>> t
datetime.time(12, 56, 44, 398402)
>>>
I need 't' in UTC format.
There are four cases:
input datetime.time has tzinfo set (eg OP mentions UTC)
output as non-naive time
output as naive time (tzinfo not set)
input datetime.time has tzinfo not set
output as non-naive time
output as naive time (tzinfo not set)
The correct answer needs to make use of datetime.datetime.timetz() function because datetime.time cannot be built as a non-naive timestamp by calling localize() or astimezone() directly.
from datetime import datetime, time
import pytz
def timetz_to_tz(t, tz_out):
return datetime.combine(datetime.today(), t).astimezone(tz_out).timetz()
def timetz_to_tz_naive(t, tz_out):
return datetime.combine(datetime.today(), t).astimezone(tz_out).time()
def time_to_tz(t, tz_out):
return tz_out.localize(datetime.combine(datetime.today(), t)).timetz()
def time_to_tz_naive(t, tz_in, tz_out):
return tz_in.localize(datetime.combine(datetime.today(), t)).astimezone(tz_out).time()
Example based on OP requirement:
t = time(12, 56, 44, 398402)
time_to_tz(t, pytz.utc) # assigning tzinfo= directly would not work correctly with other timezones
datetime.time(12, 56, 44, 398402, tzinfo=<UTC>)
In case naive timestamp is wanted:
time_to_tz_naive(t, pytz.utc, pytz.timezone('Europe/Berlin'))
datetime.time(14, 56, 44, 398402)
The cases where the time() instance has already tzinfo set are easier because datetime.combine picks up the tzinfo from the passed parameter, so we just need to convert to tz_out.
I would create a temp datetime object, convert the tz, and extract the time again.
import datetime
def time_to_utc(t):
dt = datetime.datetime.combine(datetime.date.today(), t)
utc_dt = datetime_to_utc(dt)
return utc_dt.time()
t = datetime.datetime.now().time()
utc_t = time_to_utc(t)
where, datetime_to_utc is any of the suggestions in the linked question.
Easy way to convert from/to UTC timezone using pytz:
import datetime, pytz
def time_to_utc(naive, timezone="Europe/Istanbul"):
local = pytz.timezone(timezone)
local_dt = local.localize(naive, is_dst=None)
utc_dt = local_dt.astimezone(pytz.utc)
return utc_dt
def utc_to_time(naive, timezone="Europe/Istanbul"):
return naive.replace(tzinfo=pytz.utc).astimezone(pytz.timezone(timezone))
# type(naive) """DateTime"""
# type(timezone) """String"""
Let's assume you need to convert EST time to UTC. Now, first of all, python datetime objects are not timezone aware by default. They take the system time.
So if you create a datetime object by doing:
from datetime import datetime
date = datetime(2022, 4, 28, 18, 0, 0) # or date = datetime.now() or strftime(), there are so many ways
date would not be timezone aware. We can use pytz to make datetimes timezonz aware and then convert between timezones using localize.
import pytz
from datetime import datetime
est = pytz.timezone('Europe/Paris')
utc = pytz.utc
We make the datetime timezone aware first.
est_time = est.localize(date)
then we can change the timezone and get the relvant time as we wish.
utc_time = est_time.astimezone(utc)
The full list of timezone strings are available at:
pytz.all_timezones