Convert a timestamp to a DateTime field? - django

I've got a DateTimeField(auto_now_add=True) in my model. However, I wish to update this field, and the format I'm receiving from my API is a UNIX timestamp. Can I somehow convert the format I receive from my API to the correct one? (eg 1640206232 to 2021-12-22 20:50:32).
Using postgres as my db if that matters..

Yes As mentioned by #Sevy in his comment you can use the following
from datetime import datetime
timestamp = 1640206232
dt_object = datetime.fromtimestamp(timestamp, tz='UTC') # Or whatever timezone you want
print("dt_object =", dt_object)
print("type(dt_object) =", type(dt_object))
More info and how to convert the other way can be found here:
https://www.programiz.com/python-programming/datetime/timestamp-datetime

Related

Get max and min formatted date values from queryset in Django

I have a one to many relation between session and camp. Now I have to get the max and min dates of all camps combined for a particular session.
I am able to do it like this:
sess = Session.objects.last()
max_min_dates = sess.camp.aggregate(Min('start_date'), Max('end_date'))
But if I try to send this from HttpResponse then I am getting this error:
TypeError: Object of type 'date' is not JSON serializable
So I need to send the formatted date values in that. How can I modify the above code to get the same?
The default encoder for json.dumps() does not support date encoding (ie. can't convert date into str). You can use django encoder instead, it supports a few more data types see the link for more info.
Django Ref
import json
from django.core.serializers.json import DjangoJSONEncoder
json_str = json.dumps(max_min_dates, cls=DjangoJSONEncoder)

Handling Bad Inbound ISO8601 DateTime Offset with Django Rest Framework

My mobile client is sending up inaccurate datetime offset information. For example:
2019-05-03T17:55:12-0700
The time is actually the correct UTC time however, the offset should read -0000.
I can not currently modify the client to correct the issue causing this. So I need to throw out the offset or change it to -0000.
In the above example, for this user who has their account timezone settings set to PST, it stores the date in validated_data as datetime.datetime(2019, 5, 4, 0, 55, 12, tzinfo=<UTC>)
If client-based time and offset information were synced up, this conversion by DRF would be correct, as it is seven hours off or PST + the current DST. (west coast us is currently -7:00 UTC)
The problem is that by the time I reach my ModelSerializer class, the validated_data already contains what DRF believes is now the correct UTC time.
Where is the appropriate place to mutate this field on the POST body so that by the time DRF attempts to create the DateTime it will build the correct timestamp?
The easiest way to handle this was to modify the DateTime object before it was saved in the model field. So in the create() get the original ISO8601 string from the POST body using self.context['request'].data['created']. Then use dateutil.parser to parse the string into a DateTime, and replace the timezone with a pytz.UTC.
import dateutil.parser
Class MySerializer(serializers.ModelSerializer):
...
def create(self, validated_data):
scan.created = dateutil.parser.parse(self.context['request'].data['created']).replace(tzinfo=pytz.UTC)
It is not a glorious fix, but will work until I can release an updated mobile client.

Python library to access a CalDAV server

I run ownCloud on my webspace for a shared calendar. Now I'm looking for a suitable python library to get read only access to the calendar. I want to put some information of the calendar on an intranet website.
I have tried http://trac.calendarserver.org/wiki/CalDAVClientLibrary but it always returns a NotImplementedError with the query command, so my guess is that the query command doesn't work well with the given library.
What library could I use instead?
I recommend the library, caldav.
Read-only is working really well with this library and looks straight-forward to me. It will do the whole job of getting calendars and reading events, returning them in the iCalendar format. More information about the caldav library can also be obtained in the documentation.
import caldav
client = caldav.DAVClient(<caldav-url>, username=<username>,
password=<password>)
principal = client.principal()
for calendar in principal.calendars():
for event in calendar.events():
ical_text = event.data
From this on you can use the icalendar library to read specific fields such as the type (e. g. event, todo, alarm), name, times, etc. - a good starting point may be this question.
I wrote this code few months ago to fetch data from CalDAV to present them on my website.
I have changed the data into JSON format, but you can do whatever you want with the data.
I have added some print for you to see the output which you can remove them in production.
from datetime import datetime
import json
from pytz import UTC # timezone
import caldav
from icalendar import Calendar, Event
# CalDAV info
url = "YOUR CALDAV URL"
userN = "YOUR CALDAV USERNAME"
passW = "YOUR CALDAV PASSWORD"
client = caldav.DAVClient(url=url, username=userN, password=passW)
principal = client.principal()
calendars = principal.calendars()
if len(calendars) > 0:
calendar = calendars[0]
print ("Using calendar", calendar)
results = calendar.events()
eventSummary = []
eventDescription = []
eventDateStart = []
eventdateEnd = []
eventTimeStart = []
eventTimeEnd = []
for eventraw in results:
event = Calendar.from_ical(eventraw._data)
for component in event.walk():
if component.name == "VEVENT":
print (component.get('summary'))
eventSummary.append(component.get('summary'))
print (component.get('description'))
eventDescription.append(component.get('description'))
startDate = component.get('dtstart')
print (startDate.dt.strftime('%m/%d/%Y %H:%M'))
eventDateStart.append(startDate.dt.strftime('%m/%d/%Y'))
eventTimeStart.append(startDate.dt.strftime('%H:%M'))
endDate = component.get('dtend')
print (endDate.dt.strftime('%m/%d/%Y %H:%M'))
eventdateEnd.append(endDate.dt.strftime('%m/%d/%Y'))
eventTimeEnd.append(endDate.dt.strftime('%H:%M'))
dateStamp = component.get('dtstamp')
print (dateStamp.dt.strftime('%m/%d/%Y %H:%M'))
print ('')
# Modify or change these values based on your CalDAV
# Converting to JSON
data = [{ 'Events Summary':eventSummary[0], 'Event Description':eventDescription[0],'Event Start date':eventDateStart[0], 'Event End date':eventdateEnd[0], 'At:':eventTimeStart[0], 'Until':eventTimeEnd[0]}]
data_string = json.dumps(data)
print ('JSON:', data_string)
pyOwnCloud could be the right thing for you. I haven't tried it, but it should provide a CMDline/API for reading the calendars.
You probably want to provide more details about how you are actually making use of the API but in case the query command is indeed not implemented, there is a list of other Python libraries at the CalConnect website (archvied version, original link is dead now).

Time range query in Mongo db

I'm using django-nonrel and mongodb to develop app. I know that object id is start with a timestamp of the insertion time of object creation. So it's possible to do time range query based on _id field.
How can I generate a minimal object_id based on a given time in python or django?
Here is a much more pythonic version of the other answer here provided by OP, along with documentation:
from bson.objectid import ObjectId
import datetime
def datetime_to_objectid(dt):
# ObjectId is a 12-byte BSON type, constructed using:
# a 4-byte value representing the seconds since the Unix epoch,
# a 3-byte machine identifier,
# a 2-byte process id, and
# a 3-byte counter, starting with a random value.
timestamp = int((dt - datetime.datetime(1970,1,1)).total_seconds())
time_bytes = format(timestamp, 'x') #4 bytes
return ObjectId(time_bytes+'00'*8) #+8 bytes
However, starting with version 1.6 of pymongo, it would be much more elegant to do the following:
from bson.objectid import ObjectId
ObjectId.from_datetime(dt)
from bson.objectid import ObjectId
import time
def get_minimal_object_id_for_int_timestamp(int_timestamp=None):
if not int_timestamp:
int_timestamp=int(time.time())
return ObjectId(hex(int(int_timestamp))[2:]+'0000000000000000')
def get_int_timestamp_from_time_string(time_string=None):
# format "YYYY-MM-DD hh:mm:ss" like '2012-01-05 13:01:51'
if not time_string:
return int(time.time())
return int(time.mktime(time.strptime(time_string, '%Y-%m-%d %H:%M:%S')))
def get_minimal_object_id_for_time_string(time_string=None):
return get_minimal_object_id_for_int_timestamp(get_int_timestamp_from_time_string(time_string=time_string))
I find the solution finally. hope it helps to others.

Google App Engine, parsedatetime and TimeZones

I'm working on a Google App Engine / Django app and I encountered the following problem:
In my html I have an input for time. The input is free text - the user types "in 1 hour" or "tomorrow at 11am". The text is then sent to the server in AJAX, which parses it using this python library: http://code.google.com/p/parsedatetime/. Once parsed, the server returns an epoch timestamp of the time.
Here is the problem - Google App Engine always runs on UTC. Therefore, lets say that the local time is now 11am and the UTC time is 2am. When I send "now" to the server it will return "2am", which is good because I want the date to be received in UTC time. When I send "in 1 hour" the server will return "3am" which is good, again. However, when I send "at noon" the server will return "12pm" because it thinks that I'm talking about noon UTC - but really I need it to return 3am, which is noon for the request sender.. I can pass on the TZ of the browser that sends the request, but that wont really help me - the parsedatetime library wont take a timezone argument (correct me if I'm wrong). Is there a walk around this? Maybe setting the environments TZ somehow?
Thanks!
What you could do is add the difference using a timedelta object (http://docs.python.org/library/datetime.html)
The offset
here's some (very rough) code to give you the idea:
import parsedatetime
import datetime
my_users_timezone = whatever #replace this with a string that will make sense in the offsets dictionary
utc_timezone_offsets_in_hours = {
'utc' : 0,
'pacific' : -8,
# etc
}
parsed_time = parsedatetime.whatever(input_string)
offset_hours = utc_utc_timezone_offsets_in_hours[my_users_timezone]
final_time = parsed_time + datetime.timedelta(hours=offset_hours)
return final_time
parsedatetime's parse routine expects a timetuple() as the sourceTime parameter and should carry over any timezone information you include in it as I don't recall writing any code that overrode it. If it doesn't then it's a bug and let me know.
You can use code like how the answer above suggested for now to add the TZ offset after the parse() routine returns what it has determined the datetime to be:
import parsedatetime as pdt
cal = pdt.Calendar()
start = datetime.datetime.now().timetuple()
parsed, flag = cal.parse('in 1 hr', start)
then you can take the timetuple value of parsed and use timedelta to add your offset hours