Are datetime timestamps updated after pickling? - python

I'm creating a timestamp using datetime.date.today().day. Later in the code, this one shall be compared to another (current) timestamp, but just on the day-level: "If the current day is not the day of the former timestamp, do stuff".
To do this, I'm saving the first timestamp using pickle. Now I wonder, if the datetime-object will be auto-updated after pickle.load, if the loading date is not the "dumping" date. After all, the function is named "today"... I hope, this is not a stupid question and I managed to explain my issue properly.

The method datetime.datetime.today() creates a new datetime.datetime object of the current moment. The object itself doesn't know how it was created, i.e. neither the function nor the function's intention. It only know when it was created, and this is what will be stored.
If you look at the documentation of the function (e.g. via help(datetime.datetime.today), it provides this:
Current date or datetime: same as self.__class__.fromtimestamp(time.time())
Now, time.time() provides the current timestamp, e.g. 1468585949.653488. This is a plain number (float or int), which is constant once created. This number is then simply fed to datetime.datetime.fromtimestamp. For any given timestamp, this will always give you the same datetime [1].
In [12]: datetime.datetime.fromtimestamp(1468585949.653488)
Out[12]: datetime.datetime(2016, 7, 15, 14, 32, 29, 653487)
If you dump this object, you get a regular datetime.datetime object. It's just the plain class datetime.datetime and its data, no function or method reference such as datetime.datetime.today.
In [3]: print(pickle.dumps(datetime.datetime.fromtimestamp(1468585949.653488),protocol=0))
# cdatetime # class datetime.\
# datetime # datetime
# p0 # push last object (datetime.datetime) to stack as p0
# (S'\x07\xe0\x07\x0f\x0e \x1d\t\xf8\xb0' # group '(' start, string 'S' from binary ('\x07...')
# p1 # push last object (string) to stack as p1
# tp2 # create tuple from last stack group, push to stack as p2
# Rp3 # call p0(*p2)
# . # done
So, what does this piece of junk do? It looks up the object datetime.datetime as p0, stores the string '\x07\xe0\x07\x0f\x0e \x1d\t\xf8\xb0' as p1, creates the tuple p2 = tuple((p1,)), then calls p0(*p2).
Or in other words, datetime.datetime('\x07\xe0\x07\x0f\x0e \x1d\t\xf8\xb0') is returned. Note that the argument to datetime.datetime is a constant string. This will always give you the original datetime:
In [30]: datetime.datetime('\x07\xe0\x07\x0f\x0e \x1d\t\xf8\xb0')
Out[30]: datetime.datetime(2016, 7, 15, 14, 32, 29, 653488)
[1] Baring differences in timezones etc.

It doesn't autoupdate after loading. To demonstrate it, check this small example:
import pickle
import datetime
today1 = datetime.datetime.today()
pickle.dump(today1, open('today','wb') )
sleep(5)
today2 = pickle.load(open('today','r'))
# today1 => datetime.datetime(2016, 7, 15, 18, 6, 6, 578041)
# today2 => datetime.datetime(2016, 7, 15, 18, 6, 6, 578041)
You can see that even after a lag of 5 seconds, there is NO change in attributes (year, month, day, hour, sec .. etc) of datetime objects: today1 and today2
Hope it helps : )

Related

conditional python; Time format newer than 30 minutes

I have a variable that has a stored created date as:
2022-09-01T19:40:17.268980742Z
In python, if i wanted to look at that time and say if 'created' is within than the last 30 minutes, do X.
EDIT
I have another command I can use (working within Palo XSOAR), that will give me the current date time in ISO.
So really want I'm trying to do is say:
if created is within the last 30 minutes:
do X
Assume I have to capture current time as ISO variable (can do)
Set a variable less than 30 minutes of the current time (not sure)
then if create time is between those two values do X (not sure)
Any help is appreciated -
Thanks,
You can use datetime.now() to get the current datetime. We can then coerce your datetime string into a datetime object, too. Then, we can look at the difference and apply some logic.
import datetime
some_string = '2022-09-01T19:40:17.268980742Z'
some_string = some_string.split('.')[0]
timestamp = datetime.datetime.fromisoformat(some_string)
current_time = datetime.datetime.now()
if (current_time - timestamp) < timedelta(minutes=30):
print('x')
else:
print('y')
Here are how the variables look:
>>> print(timestamp)
datetime.datetime(2022, 9, 1, 19, 40, 17)
>>> print(current_time)
datetime.datetime(2022, 9, 5, 4, 26, 14, 345147)
>>> print(current_time - timestamp)
datetime.timedelta(days=3, seconds=31557, microseconds=345147)
Note, I wasn't able to convert the provided timestamp of 2022-09-01T19:40:17.268980742Z to a datetime object using the fromisoformat. Trimming down the microseconds six decimal places worked fine, but seven throws an error. This is expected for datetime objects as the permissable resolution is Between 0 and 999999 inclusive (src: https://docs.python.org/3/library/datetime.html).
This is why I split the string.
Works:
some_string = '2022-09-01T19:40:17.268980'
timestamp = datetime.datetime.fromisoformat(some_string)
Error:
some_string = '2022-09-01T19:40:17.2689801'
timestamp = datetime.datetime.fromisoformat(some_string)

Django ORM Syntax for 'LIKE' queries with respect to Datetime

I have this table which has column "date" in the format "2021-03-12 08:12:44.350176".
I want to compare a external date such as "2021-03-12 08:12:44"
I have tried this
new_date = datetime.datetime(2021, 3, 12, 8, 12, 44, tzinfo=<UTC>)
obj = Test.objects.filter(date__contains=new_date).all()
But it doesn't work, it returns empty sets.
My goal is to fetch all the records against the new_date.
Is there a way to remove milliseconds or way to compare the two dates?
It seems you want to compare datetimes upto the second while truncating the milliseconds. You can do that (and similar) by using either Trunc [Django docs] or one of it's subclasses. For truncating to the seconds you can use TruncSecond for your purpose:
import datetime
from django.db.models.functions import TruncSecond
from django.utils import timezone
new_date = datetime.datetime(2021, 3, 12, 8, 12, 44, tzinfo=timezone.utc)
obj = Test.objects.annotate(
trunc_date=TruncSecond(
'date',
tzinfo=timezone.utc
)
).filter(trunc_date=new_date)
according to [Django Docs]:
date
For datetime fields, casts the value as date. Allows chaining additional field lookups. Takes a date value.
date means a datetime.date object.
so you can use __date for datetime fields.

Adding a timedelta to a skyfield Time

The skyfield Almanach documentation
uses this code to define the points in time between which to compute sunrise & sunset:
t0 = ts.utc(2018, 9, 12, 4)
t1 = ts.utc(2018, 9, 13, 4)
What if I just wanted to use one (start) date and set the next date to be exactly one day after? I can't just add one to the day argument since this would not be correct at the end of the month.
Using Python's datetime I could do this using
from datetime import datetime, timedelta
datetime(2019, 1, 31, 12) + timedelta(days=1)
# datetime.datetime(2019, 2, 1, 12, 0)
but I can't find anything like timedelta in the skyfield API documentation.
What if I just wanted to use one (start) date and set the next date to be exactly one day after? I can't just add one to the day argument since this would not be correct at the end of the month.
Happily, you can just add one to the day! As the documentation says:
https://rhodesmill.org/skyfield/time.html
"you are free to provide out-of-range values and leave it to Skyfield to work out the correct result"
>>> from skyfield.api import load
>>> ts = load.timescale()
[#################################] 100% deltat.data
>>> t = ts.utc(2018, 2, 28 + 1)
>>> t.utc_jpl()
'A.D. 2018-Mar-01 00:00:00.0000 UT'
You can use datetime's timedelta and convert back between datetime and skyfield's Time objects like this:
t0 = ts.utc(2019, 1, 31, 12)
t1 = ts.utc(t0.utc_datetime() + timedelta(days=1))
# Print
t1.utc_iso()
# '2019-02-01T12:00:00Z'
While certainly not beautiful, this allows you to use all the features of Python's datetime.

Mystery times conversion (pandas and datetime)

Can anyone explain this?
import pandas as pd
import datetime
pd.to_datetime(1532329236726000, unit="us")
returns Timestamp('2018-07-23 07:00:36.726000')
datetime.datetime(2018, 7, 23, 8, 0, 36, 726000).timestamp() * 10**6
returns 1532329236726000.0.
So, is 1532329236726000 2018-07-23 07:00:36 or 2018-07-23 08:00:36 ?
This will depend on the timezone info of the datetime object you create. YOu are in fact creating a naive timezone object in both cases which does not have a specific timezone set
datetime.datetime() objects may assume a local timezone as opposed to UTC which your pd.to_datetime() assumes
datetime.datetime(2018, 7, 23, 7, 0, 36, 726000).replace(tzinfo=pytz.utc).timestamp() * 10**6 returns the same epoch time you put into your original question
From the python docs
"A naive object does not contain enough information to unambiguously locate itself relative to other date/time objects. Whether a naive object represents Coordinated Universal Time (UTC), local time, or time in some other timezone is purely up to the program, just like it is up to the program whether a particular number represents metres, miles, or mass. Naive objects are easy to understand and to work with, at the cost of ignoring some aspects of reality."
https://docs.python.org/3/library/datetime.html
You can explicitly tell both functions in your answer to use UTC with a kwarg to the constructors (and without using pytz as below)
datetime.datetime(2018, 7, 23, 7, 0, 36, 726000, tzinfo=datetime.timezone.utc)
pd.to_datetime(1532329236726000, unit="us", utc=True)

Difference between the time objects in python?

What is the difference between the 2 statements:
import datetime
print datetime.datetime.now()
datetime.datetime(2015, 1, 28, 12, 32, 9, 762118)
from datetime import *
>> datetime.time(datetime.now())
datetime.time(12, 33, 3, 693084)
Actually I want to compare TimeField of a django model with the current day's 1 hour less time. My code snippet for the same:
Mymodel.objects.filter(
follow_up_date=datetime.datetime.now().date,
# commented now
# preferred_time__lt=(
# datetime.datetime.now() - datetime.timedelta(hours=1)),
preferred_time__lt=(datetime.time(datetime.now()) - datetime.timedelta(hours=1)),
)
Mymodel:
class Mymodel(models.Model):
follow_up_date = models.DateField("Follow up Date",null=True,blank=True)
preferred_time = models.TimeField(_("Preferred time"),default=now,
null=True,blank=True)
I am trying to extract all the instances which are scheduled for the day, whose preferred time has elapsed just 1 hour back. Which should be the correct filter for the 'preferred_time'? I got wrong results for the commented code. I am not clear.
This is a cron job i.e management command to be run every 1 hour in django
In the first instance:
datetime.datetime(2015, 1, 28, 12, 32, 9, 762118)
You have a datetime object. It has both the date (first three numbers) and the time (last four numbers).
The second object you mention:
datetime.time(12, 33, 3, 693084)
This is just the time component.
To compare a TimeField, you need just the time component; for a DateField, just the date component.
In your code, you have the following datetime.datetime.now().date this is just the name of the built-in function date. You need to call it:
>>> datetime.datetime.now().date
<built-in method date of datetime.datetime object at 0xb74ac9b0>
>>> datetime.datetime.now().date()
datetime.date(2015, 1, 28)
You also cannot do datetime.time(datetime.datetime.now()), datetime.time() is a constructor method, it is not a way to covert other objects.
You also cannot subtract timedelta from a time object:
To get the correct result, you need to subtract one hour from the datetime object, then convert it to time:
>>> (datetime.datetime.now() - datetime.timedelta(hours=1)).time()
datetime.time(9, 27, 16, 93746)
In the end, your filter would look like:
filter_date = datetime.datetime.now().date()
filter_time = (datetime.datetime.now() - datetime.timedelta(hours=1)).time()
Mymodel.objects.filter(follow_up_date=filter_date,
preferred_time__lt=filter_time)
datetime.now() given date and time information.
datetime.time() give only time information.
e.g
>>> from datetime import *
>>> datetime.now()
datetime.datetime(2015, 1, 28, 12, 52, 35, 164500)
>>> datetime.time(datetime.now())
datetime.time(12, 52, 41, 97521)
>>>

Categories