Python datetime weird behavior - python

I trying this in Python. What is the difference of those:
>>> a = datetime.fromtimestamp(1373576406)
>>> a.replace(tzinfo=tzutc())
datetime.datetime(2013, 7, 12, 0, 0, 6, tzinfo=tzutc())
>>> a.strftime('%s')
'1373576406'
and
>>> datetime.fromtimestamp(1373576406).replace(tzinfo=tzutc()).strftime('%s')
'1373580006'
I don't really understand why this is happening. Shouldn't both timestamps be equal?
I tried these in both Python 3.3.2 and Python 2.7.1

datetime.replace returns a new datetime instance.
In your first example you are ignoring the return value of datetime.replace and are then doing datetime.strftime on your old datetime instance.
This causes the inequality you are experiencing.
To make both examples equal you would have to edit the verbose one to look like:
>>> a = datetime.fromtimestamp(1373576406)
>>> a = a.replace(tzinfo=tzutc())
>>> a.strftime('%s')
'1373576406

Related

How to print only if specific time starts with x in Python

Hi I'm a newbie learning python and I want to print something only if current time starts with x (for example, if current time starts with = 4, print "hi", time = 4:18), this is the code I made, it says attribute error:
import datetime
local = datetime.datetime.now().time().replace(microsecond=0)
if local.startswith('16'):
print("Hi! It's ", local)
The .replace() method returns a date object. date objects don't have a .startswith() method. That method is only for str.
Try converting your date to a string first:
if str(local).startswith('16'):
print("Hi! It's ", local)
The documentation lists all of the methods available on a date object.
You need to first convert it to a string, as datetime objects have no startswith() method. Use strftime, example:
import datetime
t = datetime.datetime(2012, 2, 23, 0, 0)
t2 = t.strftime('%m/%d/%Y')
will yield:
'02/23/2012'. Once it's converted, you can use t2.startswith().
https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
You can get the hour of the time and check if it is 16:
if local.hour == 16:
print("Hi! It's ",local)
If you need to use startswith() then you can convert it to a string like this:
if str(local).startswith('16'):
print("Hi! It's ", local)
That's not a good way. Check the time as int is the better solution here.
replace() has 2 needed str arguments. You use a named attribute which doesn't exist.

Datetime string format alignment

In Python 2.7 I want to print datetime objects using string formatted template. For some reason using left/right justify doesn't print the string correctly.
import datetime
dt = datetime.datetime(2013, 6, 26, 9, 0)
l = [dt, dt]
template = "{0:>25} {1:>25}" # right justify
print template.format(*l) #print items in the list using template
This will result:
>25 >25
Instead of
2013-06-26 09:00:00 2013-06-26 09:00:00
Is there some trick to making datetime objects print using string format templates?
It seems to work when I force the datetime object into str()
print template.format(str(l[0]), str(l[1]))
but I'd rather not have to do that since I'm trying to print a list of values, some of which are not strings. The whole point of making a string template is to print the items in the list.
Am I missing something about string formatting or does this seem like a python bug to anyone?
SOLUTION
#mgilson pointed out the solution which I missed in the documentation. link
Two conversion flags are currently supported: '!s' which calls str()
on the value, and '!r' which calls repr().
Some examples:
"Harold's a clever {0!s}" # Calls str() on the argument first
"Bring out the holy {name!r}" # Calls repr() on the argument first
The problem here is that datetime objects have a __format__ method which is basically just an alias for datetime.strftime. When you do the formatting, the format function gets passed the string '>25' which, as you've seen, dt.strftime('>25') just returns '>25'.
The workaround here it to specify that the field should be formatted as a string explicitly using !s:
import datetime
dt = datetime.datetime(2013, 6, 26, 9, 0)
l = [dt, dt]
template = "{0!s:>25} {1!s:>25} "
out = template.format(*l)
print out
(tested on both python2.6 and 2.7).
datetime.datetime has format method. You need to convert it str.
>>> '{:%Y/%m/%d}'.format(dt)
'2013/06/26'
>>> '{:>20}'.format(dt)
'>20'
>>> '{:>20}'.format(str(dt))
' 2013-06-26 09:00:00'
>>> import datetime
>>> dt = datetime.datetime(2013, 6, 26, 9, 0)
>>> l = [dt, dt]
>>> template = "{0:>25} {1:>25}"
>>> print template.format(*l)
>25 >25
>>> print template.format(*map(str, l))
2013-06-26 09:00:00 2013-06-26 09:00:00
Try this:
print template.format(*map(str, l))
=> 2013-06-26 09:00:00 2013-06-26 09:00:00
It works by first converting the datetime objects to a string, which then can be formatted with the format method without problems.

Comparing time in a datetime object python

I am having a weird problem.
I am running a django app and in one of my models I have a method to compare the time that the user gives and the time that is stored in the model db
So, for debugging purposes, I do this.
print self.start
print start
print self.start.time < start.time
And the output is:
2012-10-15 01:00:00+00:00
2012-10-22 01:01:00+00:00
False
HOW IS THIS POSSIBLE?!?!?!
I tried this in the django shell and in the python cli! Both give me True! With the same values.
Thanks guys.
.time is a method, not a property.
>>> import datetime
>>> a = datetime.datetime(2012, 10, 15, 1, 0, 0)
>>> a.time
<built-in method time of datetime.datetime object at 0x10049f508>
>>> a.time()
datetime.time(1, 0)
Therefore, the correct code would be if self.start.time() < start.time().

Convert a datetime.date object into a datetime.datetime object with zeros for any missing time attributes

Is there a built-in function that converts a datetime.date object into a datetime.datetime object with 0's for the missing stuff? For example, suppose
tdate = datetime.date(2012,1,31)
I want to write something like either of these
tdatetime = datetime.date.datetime()
tdatetime = datetime.datetime(tdate)
and I want the output to be
datetime.datetime(2012, 1, 31, 0, 0)
But neither works. There is a builtin function to go from datetime.datetime to datetime.date, but I'm looking for the reverse operation.
One very poor solution would be to write:
datetime.datetime(tdate.year(), tdate.month(), tdate.day(), 0, 0)
I specifically want to avoid this bad way of doing it.
I've already written my own small function to do this, but I think it should be provided in the module. It's cluttering up some system-wide imports to use my function. It's workable, just not very Pythonic.
I'm just asking to see if anyone knows whether there is an efficient way to do it using only datetime module functions.
Use .combine(date, time) with an empty time instance:
>>> import datetime
>>> tdate = datetime.date(2012,1,31)
>>> datetime.datetime.combine(tdate, datetime.time())
datetime.datetime(2012, 1, 31, 0, 0)
If you like to use a constant instead, use time.min:
>>> datetime.datetime.combine(tdate, datetime.time.min)
datetime.datetime(2012, 1, 31, 0, 0)

How do I serialize a Python dictionary into a string, and then back to a dictionary?

How do I serialize a Python dictionary into a string, and then back to a dictionary? The dictionary will have lists and other dictionaries inside it.
It depends on what you're wanting to use it for. If you're just trying to save it, you should use pickle (or, if you’re using CPython 2.x, cPickle, which is faster).
>>> import pickle
>>> pickle.dumps({'foo': 'bar'})
b'\x80\x03}q\x00X\x03\x00\x00\x00fooq\x01X\x03\x00\x00\x00barq\x02s.'
>>> pickle.loads(_)
{'foo': 'bar'}
If you want it to be readable, you could use json:
>>> import json
>>> json.dumps({'foo': 'bar'})
'{"foo": "bar"}'
>>> json.loads(_)
{'foo': 'bar'}
json is, however, very limited in what it will support, while pickle can be used for arbitrary objects (if it doesn't work automatically, the class can define __getstate__ to specify precisely how it should be pickled).
>>> pickle.dumps(object())
b'\x80\x03cbuiltins\nobject\nq\x00)\x81q\x01.'
>>> json.dumps(object())
Traceback (most recent call last):
...
TypeError: <object object at 0x7fa0348230c0> is not JSON serializable
Pickle is great but I think it's worth mentioning literal_eval from the ast module for an even lighter weight solution if you're only serializing basic python types. It's basically a "safe" version of the notorious eval function that only allows evaluation of basic python types as opposed to any valid python code.
Example:
>>> d = {}
>>> d[0] = range(10)
>>> d['1'] = {}
>>> d['1'][0] = range(10)
>>> d['1'][1] = 'hello'
>>> data_string = str(d)
>>> print data_string
{0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], '1': {0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 1: 'hello'}}
>>> from ast import literal_eval
>>> d == literal_eval(data_string)
True
One benefit is that the serialized data is just python code, so it's very human friendly. Compare it to what you would get with pickle.dumps:
>>> import pickle
>>> print pickle.dumps(d)
(dp0
I0
(lp1
I0
aI1
aI2
aI3
aI4
aI5
aI6
aI7
aI8
aI9
asS'1'
p2
(dp3
I0
(lp4
I0
aI1
aI2
aI3
aI4
aI5
aI6
aI7
aI8
aI9
asI1
S'hello'
p5
ss.
The downside is that as soon as the the data includes a type that is not supported by literal_ast you'll have to transition to something else like pickling.
Use Python's json module, or simplejson if you don't have python 2.6 or higher.
If you fully trust the string and don't care about python injection attacks then this is very simple solution:
d = { 'method' : "eval", 'safe' : False, 'guarantees' : None }
s = str(d)
d2 = eval(s)
for k in d2:
print k+"="+d2[k]
If you're more safety conscious then ast.literal_eval is a better bet.
One thing json cannot do is dict indexed with numerals. The following snippet
import json
dictionary = dict({0:0, 1:5, 2:10})
serialized = json.dumps(dictionary)
unpacked = json.loads(serialized)
print(unpacked[0])
will throw
KeyError: 0
Because keys are converted to strings. cPickle preserves the numeric type and the unpacked dict can be used right away.
pyyaml should also be mentioned here. It is both human readable and can serialize any python object.
pyyaml is hosted here:
https://pypi.org/project/PyYAML
While not strictly serialization, json may be reasonable approach here. That will handled nested dicts and lists, and data as long as your data is "simple": strings, and basic numeric types.
A new alternative to JSON or YaML is NestedText. It supports strings that are nested in lists and dictionaries to any depth. It conveys nesting through the use of indenting, and so has no need for either quoting or escaping. As such, the result tends to be very readable. The result looks like YaML, but without all the special cases. It is especially appropriate for serializing code snippets. For example, here is an a single test case extracted from a much larger set that was serialized with NestedText:
base tests:
-
args: --quiet --config test7 files -N configs/subdir
expected:
> Archive: test7-\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d
> «TESTS»/configs/subdir/
> «TESTS»/configs/subdir/file
Be aware, that integers, floats, and bools are converted to strings.
If you are trying to only serialize then pprint may also be a good option. It requires the object to be serialized and a file stream.
Here's some code:
from pprint import pprint
my_dict = {1:'a',2:'b'}
with open('test_results.txt','wb') as f:
pprint(my_dict,f)
I am not sure if we can deserialize easily. I was using json to serialize and deserialze earlier which works correctly in most cases.
f.write(json.dumps(my_dict, sort_keys = True, indent = 2, ensure_ascii=True))
However, in one particular case, there were some errors writing non-unicode data to json.

Categories

Resources