Sort by datetime in python3 - python-3.x

Looking for help on how to sort a python3 dictonary by a datetime object (as shown below, a value in the dictionary) using the timestamp below.
datetime: "2018-05-08T14:06:54-04:00"
Any help would be appreciated, spent a bit of time on this and know that to create the object I can do:
format = "%Y-%m-%dT%H:%M:%S"
# Make strptime obj from string minus the crap at the end
strpTime = datetime.datetime.strptime(ts[:-6], format)
# Create string of the pieces I want from obj
convertedTime = strpTime.strftime("%B %d %Y, %-I:%m %p")
But I'm unsure how to go about comparing that to the other values where it accounts for both day and time correctly, and cleanly.
Again, any nudges in the right direction would be greatly appreciated!
Thanks ahead of time.

Datetime instances support the usual ordering operators (< etc), so you should order in the datetime domain directly, not with strings.
Use a callable to convert your strings to timezone-aware datetime instances:
from datetime import datetime
def key(s):
fmt = "%Y-%m-%dT%H:%M:%S%z"
s = ''.join(s.rsplit(':', 1)) # remove colon from offset
return datetime.strptime(s, fmt)
This key func can be used to correctly sort values:
>>> data = {'s1': "2018-05-08T14:06:54-04:00", 's2': "2018-05-08T14:05:54-04:00"}
>>> sorted(data.values(), key=key)
['2018-05-08T14:05:54-04:00', '2018-05-08T14:06:54-04:00']
>>> sorted(data.items(), key=lambda item: key(item[1]))
[('s2', '2018-05-08T14:05:54-04:00'), ('s1', '2018-05-08T14:06:54-04:00')]

Related

Python datetime conversion

import datetime as dt
from dateutil.tz import gettz
import time
timezone_a = "Japan"
timezone_b = "Europe/London"
unix_time = 1619238722
result = dt.datetime.fromtimestamp(unix_time, gettz(timezone_a)).strftime("%Y-%m-%d-%H-%M-%S")
print(result, timezone_a)
result = dt.datetime.fromtimestamp(unix_time, gettz(timezone_b)).strftime("%Y-%m-%d-%H-%M-%S")
print(result, timezone_b)
# This code prints
"""
2021-04-24-13-32-02 Japan
2021-04-24-05-32-02 Europe/London
I am trying to reverse it backwards so that input is
2021-04-24-13-32-02 Japan
2021-04-24-05-32-02 Europe/London
And output is 1619238722
"""
Hello, I am trying to figure out how to convert a string with a timezone into Unix time. Any help would be apreciated. Thanks!
afaik, there is no built-in method in the standard lib to parse IANA time zone names. But you can do it yourself like
from datetime import datetime
from zoneinfo import ZoneInfo # Python 3.9+
t = ["2021-04-24-13-32-02 Japan", "2021-04-24-05-32-02 Europe/London"]
# split strings into tuples of date/time + time zone
t = [elem.rsplit(' ', 1) for elem in t]
# parse first element of the resulting tuples to datetime
# add time zone (second element from tuple)
# and take unix time
unix_t = [datetime.strptime(elem[0], "%Y-%m-%d-%H-%M-%S")
.replace(tzinfo=ZoneInfo(elem[1]))
.timestamp()
for elem in t]
# unix_t
# [1619238722.0, 1619238722.0]
See if this code works.
# convert string to datetimeformat
date = datetime.datetime.strptime(date, "%Y-%m-%d-%H-%M-%S %Z")
# convert datetime to timestamp
unixtime = datetime.datetime.timestamp(date)

How to differentiate between a dateutil parsed date and a datetime with 0 for all time values

As far as I can tell there is no way to distinguish the difference between these two date strings ('2020-10-07', '2020-10-07T00:00:00') once they are parsed by dateutil. I really would like to be able to tell the difference between a standalone date and a date with a timestamp of zero.
import dateutil.parser
import datetime
date_str = '2020-10-07'
time_str = '2020-10-07T00:00:00'
s = dateutil.parser.parse(date_str)
e = dateutil.parser.parse(time_str)
The ultimate goal is to set the time to the beginning of the day in the end of the day when it is a standalone date but leave the date alone when there is a time included. Get close with something like this but it still can't differentiate from this one case. If do you know of any good solution to this that would be really helpful.
if s == e and s.time() == datetime.time.min:
e = datetime.datetime.combine(e, datetime.time.max)
Post is somewhat useful but it's outdated and I'm not even sure that it would work for my use case. Finding if a python datetime has no time information
Here's a function which uses a simple try/except to test if the input can be parsed to a date (i.e. has no time information) or a datetime object (i.e. has time information). If the input format is different from ISO format, you could also implement specific strptime directives.
from datetime import date, time, datetime
def hasTime(s):
"""
Parameters
----------
s : string
ISO 8601 formatted date / datetime string.
Returns
-------
tuple, (bool, datetime.datetime).
boolean will be True if input specifies a time, otherwise False.
"""
try:
return False, datetime.combine(date.fromisoformat(t), time.min)
except ValueError:
return True, datetime.fromisoformat(t)
# do nothing else here; will raise an error if input can't be parsed
for t in ('2020-10-07', '2020-10-07T00:00:00', 'not-a-date'):
print(t, hasTime(t))
# output:
# >>> 2020-10-07 (False, datetime.datetime(2020, 10, 7, 0, 0))
# >>> 2020-10-07T00:00:00 (True, datetime.datetime(2020, 10, 7, 0, 0))
# >>> ValueError: Invalid isoformat string: 'not-a-date'

How to slice a pandas.DatetimeIndex?

What is the best way to get dates between, say, '2019-01-08' and '2019-01-16', from the pandas.DatetimeIndex object dti as constructed below? Ideally, some concise syntax like dti['2019-01-08':'2019-01-16']?
import pandas as pd
dti = pd.bdate_range(start='2019-01-01', end='2019-02-15')
DatetimeIndex(['2019-01-01', '2019-01-02', '2019-01-03', '2019-01-04',
'2019-01-07', '2019-01-08', '2019-01-09', '2019-01-10',
'2019-01-11', '2019-01-14', '2019-01-15', '2019-01-16',
'2019-01-17', '2019-01-18', '2019-01-21', '2019-01-22',
'2019-01-23', '2019-01-24', '2019-01-25', '2019-01-28',
'2019-01-29', '2019-01-30', '2019-01-31', '2019-02-01',
'2019-02-04', '2019-02-05', '2019-02-06', '2019-02-07',
'2019-02-08', '2019-02-11', '2019-02-12', '2019-02-13',
'2019-02-14', '2019-02-15'],
dtype='datetime64[ns]', freq='B')
You can do it with the slice_indexer for DateTimeIndex
pandas.DateTimeIndex.slice_indexer(start, stop, step, [...])
It returns the indexes of the datetime items so you can pass it to dti
Example:
dti[dti.slice_indexer("2019-01-07", "2019-01-17")]
If you read the source code for DatetimeIndex.__getitem__ method, the individual dates in a DatetimeIndex is stored in a DatetimeArray. To support slicing, you need to get the integer indices of the start and stop date in that array. I suggest that you file a feature request with the pandas development team.
Meanwhile, you can monkey-patch it in:
from pandas.core.indexes.datetimes import DatetimeIndex
__old_getitem = DatetimeIndex.__getitem__
def __new_getitem(index, key):
if isinstance(key, slice):
_key = index.slice_indexer(key.start, key.stop, key.step)
else:
_key = key
return __old_getitem(index, _key)
DatetimeIndex.__getitem__ = __new_getitem
# Now you can slice
dti['2019-01-08':'2019-01-16':4]

Change default dateparcer output

I found dateparser as a great way to change natural language into dates. Now, I am trying to manipulate the output of the parser without success.
from dateparser import parse
import datetime
def pars():
n = "in two days"
x = parse(n, settings={'TIMEZONE': 'US/Eastern'})
print (x)
>>> 2016-08-25 00:18:03.268506
t = datetime.datetime(x)
t.strftime('%m/%d/%Y')
print (t)
pars()
I get the error: TypeError: an integer is required (got type datetime.datetime)
Many things are wrong with the code.
dateparser returns datetime.datetime objects not some ints that is what datetime.datetime expects
strftime does not update the datetime.datetime object in place, if you want to keep the string value it produces, assign it to some var.
def pars():
x = parse('in two days')
t = x.strftime('%m/%d/%Y')
print 'datetime', x
print 'strftime', t
>>> pars()
datetime 2016-09-30 23:34:07.863881
strftime 09/30/2016

Passing parameters to strftime method

I'm new to python. my question is how to pass parameter to date.strftime() or a workaround
Below is the code
from datetime import date
dl_date = date.today()
p = '%d%b%Y' # the format may vary %d%B%Y or %d%m%Y or % d%M%Y etc
file_date_format = "{0}/{1}/{2}".format(str(dl_date.strftime('%r')),str(dl_date.strftime('%r').upper())
, str(dl_date.strftime('%r'))) % (p[:2], p[2:4], p[4:6])
print(file_date_format)
Help is much appreciated.
No need to use percent style string formatting here. Just stick the p slices directly in the strftime calls.
from datetime import date
dl_date = date.today()
p = '%d%b%Y' # the format may vary %d%B%Y or %d%m%Y or % d%M%Y etc
file_date_format = "{0}/{1}/{2}".format(
str(dl_date.strftime(p[:2])),
str(dl_date.strftime(p[2:4]).upper()),
str(dl_date.strftime(p[4:6]))
)
print(file_date_format)
Result:
14/NOV/2014

Resources