Need help formatting datetime timezone for Google API - python

I've retrieved a datetime from a bigquery record (using the google.cloud.bigquery library) and need to send it to the google admin sdk reports API in rfc 3339 format according to the 'startTime' parameter of this api method. The API is expecting the datetime to look like this:
2010-10-28T10:26:35.000Z
Which is normally possible by creating a python datetime without tzinfo and calling isoformat like this:
>>> now = datetime.utcnow()
>>> now = now.isoformat("T") + "Z"
>>> now
'2017-06-01T13:05:32.586760Z'
The problem I'm having is that the timestamp coming from BigQuery includes a tzinfo object, and that's causing isoformat to return text that the Google API can't process.
>>> timestamp_from_bigquery
'datetime.datetime(2017, 5, 31, 16, 13, 26, 252000, tzinfo=<UTC>)'
>>> timestamp_from_bigquery.isoformat("T") + "Z"
'2017-05-31T16:13:26.252000+00:00Z'
Specifically, the +00:00 is not accepted by Google's API as startTime. If I manually remove +00:00 from the string the API call works, but I'm not sure how to do this in python without an ugly string hack. Is there some clean way to remove this from the datetime object?
I've also tried this, but results in the same:
>>> timestamp_from_bigquery.replace(tzinfo=None)
'2017-05-31T16:13:26.252000+00:00Z'

Use datetime.datetime.strftime():
datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ')
timestamp_from_bigquery.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
Of course make sure the datetimes are in the correct timezone.

Related

Python - convert string type to datetime type

I have a two variables that i want to compare. When printed, this is what they look like:
2020-05-20 13:01:30
2020-05-20 14:49:03
However, one is a string type, and the other a datetime type.
If I want to convert the string one into date type so I can compare them, is the only way to use strptime? Because this seems a little redundant to me, since the string already has the exact format I want it to have. Basically, is there a function that does the same as strptime, but without re-formating it? As you can imagine, googling this problem is impossible, as all I'm getting is people trying to format any kind of string into datetime, so all the answers are just pointing at strptime.
If you work with Python 3.7+, for ISO 8601 compatible strings, use datetime.fromisoformat() as this is considerably more efficient than strptime or dateutil's parser. Ex:
from datetime import datetime
dtobj = datetime.fromisoformat('2020-05-20 13:01:30')
print(repr(dtobj))
# datetime.datetime(2020, 5, 20, 13, 1, 30)
You can find a benchmark vs. strptime etc. here or here.
You can use parser provided by dateutil
from dateutil import parser
date_object = parser.parse("2020-05-20 13:01:30")
print(repr(date_object))
# datetime.datetime(2020, 5, 20, 13, 1, 30)
print(type(date_object))
# <class 'datetime.datetime'>
print(date_object)
# 2020-05-20 13:01:30
From the docs:
This module offers a generic date/time string parser which is able to parse most known formats to represent a date and/or time.
Documentation: https://dateutil.readthedocs.io/en/stable/parser.html

How to get the value of a DateTimeField in peewee

class Test(Model):
time = DateTimeField()
# ...
row = Test.select()[0]
test.time
This returns a string that looks like this: 2017-01-23 01:01:39+01:00. How can I get it as a datetime object instead? Do I have to parse it manually?
Also I would be interested if there is any documentation on how to use the DateTimeField. The official documentation doesn't have anything on it.
Are you using SQLite? If so, SQLite doesn't have a dedicated datetime type, so datetimes are stored as strings in the DB. What peewee will do is recognize certain datetime formats coming out of the DB and convert them to datetime objects. What you need to do is ensure that either:
When you create/save your object, that you assign a datetime object to the field.
When reading back pre-existing data, that the data is in a recognized format.
The formats peewee supports out-of-the-box for datetime field are:
YYYY-mm-dd HH:MM:SS.ffffff
YYYY-mm-dd HH:MM:SS
YYYY-mm-dd
It looks like your has zone info. I'd suggest converting to UTC and dropping the zone info. That should fix it.
Have you tried adding a default like this?
time = DateTimeField(default=datetime.datetime.now())
Or when adding an entry add it as a datetime.datetime object directly:
test = Test(....., time=datetime.datetime.strptime("2018-3-15", '%Y-%m-%d'))
In the second case you don't need to specify anything in the class definition...

Filtering on DateTime in Django doesn't work

I have an SQLite database with a timestamp column defined as a DateTime field. It contains values like 2014-10-14T14:51:07.558
My Django model has the following field:
timestamp = models.DateTimeField(db_column='timestamp', blank=False)
Then, when I run the following code, I get an empty set as a result:
Model.objects.filter(timestamp=Model.objects.all()[0].timestamp)
or
edit: removed a 'contains' call
Querying
Model.objects.all()[0].timestamp
returns
datetime.datetime(2014, 10, 14, 14, 51, 7, 558000, tzinfo=<UTC>)
Why can't I filter?
Datetimes are not strings; a datetime is a single object, so it can't 'contain' anything other than itself exactly. According to the django docs though , sqlite doesn't have a native datetime type, and django uses strings instead, but in python datetimes are not strings.
The docs aren't clear about what should happen filtering datetime fields using __contains, but it doesn't make much sense to me to do so. If you are trying to check whether a specific datetime falls within a range, use __range.
That said, you tried a straight = filter, and it didn't have any effect. Try filtering against str(<datetime>) since it will be a string in sqlite.

python: how to handle timestamps (ISO8601)

I have to deal in python with strings representing iso8601 timestamps.
My timestamps string are therefore in the following form:
timestamp = "2011-08-18T10:29:47+03:00"
Currently I'm converting them in python using:
timestamp = timestamp[:-6]
timestamp = datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S")
But in this way I lose all the information about the time zone.
I have seen many examples here on s-o about timestamps and python, unfortunately no one was preserving the timezone as well, or just recover the time zone delay using:
delay = timestamp[-6:]
I have also tried:
timestamp = "2011-08-18T10:29:47+03:00"
timestamp = datetime.datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S%z")
but it returned
ValueError: 'z' is a bad directive in format '%Y-%m-%dT%H:%M:%S%z'
Can you give some insight?
The python iso8601 module is built with a wonderful parse_date method that can handle timezone info :
>>> import iso8601
>>> iso8601.parse_date("2007-01-25T12:00:00Z")
datetime.datetime(2007, 1, 25, 12, 0, tzinfo=<iso8601.iso8601.Utc ...>)
>>> iso8601.parse_date("2011-08-18T10:29:47+03:00")
datetime.datetime(2011, 8, 18, 10, 29, 47, tzinfo=<FixedOffset '+03:00'>)
If you want to convert it in another timezone, use the astimezone(tz) method
If you need to get the UTC datetime you can use the utctimetuple() method.
You'll need to add an external module that provides timezone support; the pytz module provides you with the necessary timezone database.
You'll either need to parse the timezone by hand to construct a pytz timezone, or use a package like zc.iso8601 or iso8601 to do the parsing for you:
from zc.iso8601.parse import datetimetz
datetimetz(timestamp)

User specified date time

I need to parse a date/time string from user input, and convert to UTC based on timzeone info not available in the string for datetime.strptime() (any suggestions?). Is there a straightforward way of doing this?
Ideally, on google app engine i'd like to grab local time with tzinfo from the browser if possible also.
timezone_string = "GMT-0800"
fields = ("eventstartmonth","eventstartday", "eventstartyear", "eventstarttimehour", "eventstarttimeampm")
date_string = '_'.join(map(lambda x: self.request.get(x), fields))
# date_string = "01_11_2000_1:35_PM"
dt = datetime.datetime.strptime(date_string, "%m_%d_%Y_%I:%M_%p")
# how to convert dt into a tz-aware datetime, and then to UTC
While searching for similar information I came across a demo app engine app (with source included) that demonstrates how to convert timezones in a way that's similar to what you've requested. Unfortunately, though, you'll need to create custom tzinfo classes (explanation/code in the demo app linked above) for each timezone you'll be converting.
If you need to be able to handle any timezone and/or want to take the easy route, I'd recommend using the pytz module. However, keep in mind, pytz is a rather bulky module that you'd have to upload to your GAE instance.

Categories