Python - convert naive datetime to UTC - python

I have date that I get in specific timezone time, but system deals with it as UTC and later it converts it back in that timezone, messing time.
For example like this:
I get this time: 2014-05-05 10:50:30. its datetime object. It has no timezone info, but I can get timezone info from user that uses that time. The thing is this time is showed as 'Europe/Vilnius' time, but system deals with it as UTC and when it outputs time to user it adds +3 hours showing wrong time. It does not matter if I change timezone to users timezone on that datetime object, it still outputs with +3 hours.
For example (snippet of code):
from datetime import datetime
import pytz
create_date = datetime.strptime(stage_log.create_date, "%Y-%m-%d %H:%M:%S")
tz = pytz.timezone(self.user_id.tz)
create_date = create_date.replace(tzinfo=pytz.utc)
This does not do anything and I still get wrong time.
Is there a way to move time to be correct UTC time(so then system correctly convert to users timezone) like this:
2014-05-05 10:50:30 -> convert to UTC. If timezone is 'Europe/Vilnius', it should convert that time to 2014-05-05 07:50:30. Then when system automatically does conversions it would correctly display 2014-05-05 10:50:30, because thats the time it should display.
Also if there is a way to just get number of hours that given timezone differs from UTC, then I could just do as simple as that:
create_date.replace(hour=create_date.hour-timezone_difference)

While this question does not specifically reference odoo, hopefully the following may help others:
Odoo - convert datetime to UTC:
(note: in this example self.start_date is a fields.Date)
start_date = fields.Datetime.to_string(pytz.timezone(self.env.context['tz']).localize(fields.Datetime.from_string(self.start_date), is_dst=None).astimezone(pytz.utc))
similar but with +24 hrs
end_date = fields.Datetime.to_string(pytz.timezone(self.env.context['tz']).localize(fields.Datetime.from_string(self.end_date), is_dst=None).astimezone(pytz.utc) + timedelta(hours=24))
This was used because the passed values (self.start_date) were field.Date and therefor did not get affected by timezones, while the target stored fields were fields.Datetime and therefor stored in UTC.
start_date/end_date which are now in UTC can then be used in a self.env[''].search([])

Related

same code,different answers on windows and ubuntu [duplicate]

I have the following code:
import datetime
dt = 1546955400
print(datetime.datetime.fromtimestamp(dt))
When I run this code on my local machine, I get the correct (expected) time which is
2019-01-08 15:50:00.
However I tried running this exact same code on a VM and the result was
2019-01-08 13:50:00 (two hours earlier). Why is this is happening and how can I fix it so that I always get the first one regardless of where the code is running?
datetime.datetime.fromtimestamp() returns local time. From the documentation:
Return the local date and time corresponding to the POSIX timestamp, such as is returned by time.time(). If optional argument tz is None or not specified, the timestamp is converted to the platform’s local date and time, and the returned datetime object is naive.
The timestamp value is an offset in seconds from the UNIX epoch value, midnight 1 January 1970, in the UTC timezone. The local time is a system-wide configured offset from UTC, the local timezone.
If your VM is producing unexpected results, you need to configure the timezone of the OS.
Alternatively, ignore timezones and only deal with time in the UTC timezone. For timestamps, that means using the datetime.datetime.utcfromtimestamp() function.
Your specific timestamp is 13:50 UTC:
>>> dt = 1546955400
>>> from datetime import datetime
>>> datetime.utcfromtimestamp(dt)
datetime.datetime(2019, 1, 8, 13, 50)
>>> print(_)
2019-01-08 13:50:00
so your VM is either set to the UTC or the GMT timezone (the latter is currently at UTC+0, until the switch to the UK daylight saving timezone BST). Your local system is in a UTC+2 timezone, given your stated location from your profile that'd be EEE, Easter European Time.
Another option is to create a timezone-aware timestamp by passing in a tz argument. If you have a specific UTC offset, just create a datetime.timezone() instance for that offset:
utcplus2 = datetime.timezone(datetime.timedelta(hours=2))
datetime.datetime.fromtimestamp(dt, utcplus2)
However, it is usually better to store and operate on UTC datetime instances everywhere, and only convert to specific timezones when displaying information to users. This simplifies datetime handling as it lets you avoid a number of timezone corner cases and problems, such as mixing datetime information from different timezones and timezones with a summer and winter time distinction.

python: utcfromtimestamp vs fromtimestamp, when the timestamp is based on utcnow()

Pretty sure it's an easy one but I don't get it.
My local TZ is currently GMT+3, and when I take timestamp from datetime.utcnow().timestamp() it is indeed giving me 3 hours less than datetime.now().timestamp()
During another process in my flow, I take that utc timestamp and need to turn it into datetime.
When I'm doing fromtimestamp I get the right utc hour, but when I'm using utcfromtimestamp I get another 3 hours offset.
The documentation, though, asks me to use fromtimestamp for local timezone, and utcfromtimestamp for utc usages.
What am I missing ? is the initial assumption for both funcs is that the timestamp is given in local timezone ?
Thank you :)
The key thing to notice when working with datetime objects and their POSIX timestamps (Unix time) at the same time is that naive datetime objects (the ones without time zone information) are assumed by Python to refer to local time (OS setting). In contrast, a POSIX timestamp (should) always refer to seconds since the epoch UTC. You can unambiguously obtain that e.g. from time.time(). In your example, not-so-obvious things happen:
datetime.now().timestamp() - now() gives you a naive datetime object that resembles local time. If you call for the timestamp(), Python converts the datetime to UTC and calculates the timestamp for that.
datetime.utcnow().timestamp() - utcnow() gives you a naive datetime object that resembles UTC. However, if you call timestamp(), Python assumes (since naive) that the datetime is local time - and converts to UTC again before calculating the timestamp! The resulting timestamp is therefore off from UTC by twice your local time's UTC offset.
A code example. Let's make some timestamps. Note that I'm on UTC+2 (CEST), so offset is -7200 s.
import time
from datetime import datetime, timezone
ts_ref = time.time() # reference POSIX timestamp
ts_utcnow = datetime.utcnow().timestamp() # dt obj UTC but naive - so also assumed local
ts_now = datetime.now().timestamp() # dt obj naive, assumed local
ts_loc_utc = datetime.now(tz=timezone.utc).timestamp() # dt obj localized to UTC
print(int(ts_utcnow - ts_ref))
# -7200 # -> ts_utcnow doesn't refer to UTC!
print(int(ts_now - ts_ref))
# 0 # -> correct
print(int(ts_loc_utc - ts_ref))
# 0 # -> correct
I hope this clarifies that if you call datetime.utcfromtimestamp(ts_utcnow), you get double the local time's UTC offset. Python assumes (which I think is pretty sane) that the timestamp refers to UTC - which in fact, it does not.
My suggestion would be to use timezone-aware datetime objects; like datetime.now(tz=timezone.utc). If you're working with time zones, the dateutil library or Python 3.9's zoneinfo module are very helpful. And if you want to dig deep, have a look at the datetime src code.

How to remove the tzinfo completely from the time after converting to UTC in Python?

I came across this exact issue, and I can't figure out how to achieve the solution in my case.
Guido says
The solution is to remove the tzinfo completely from the time after
converting to UTC.
This is what I have tried:
date_time = parser.parse(i.pubDate.text)
news.publication_date = date_time.replace(tzinfo=None).date()
And I get the same error:
NotImplementedError: DatetimeProperty publication_date_time can only support UTC. Please derive a new Property to support alternative timezones.
So it seems I have to convert the date to UTC first. And here my research has failed me.
I came across this solution:
The solution suggested is this:
def date_time_to_utc(date_time):
tz = pytz.timezone('???')
return tz.normalize(tz.localize(date_time)).astimezone(pytz.utc)
But I don't have the timezone. I am scraping the date from a html source. So the timezone could really be from anywhere in the world. Is there no easy and reliable way to convert a date time to UTC?
I could use both dateutil and pytz to achieve this. Many Thanks.
UPDATE
It has been a really long day. I have misread the stack trace. However the question remains valid.
date_time = (datetime}2015-01-13 18:13:26+00:00
news.publication_date_time = date_time
This caused the crash. And it seems by doing this, I pass the unit test:
news.publication_date_time = date_time.replace(tzinfo=None)
Is this the correct way converting a GMT 0 datetime to UTC datetime? Or in fact any timezone to UTC?
Is this the correct way converting a GMT 0 datetime to UTC datetime? Or in fact any timezone to UTC?
If aware datetime object is already in UTC (+0000) then your formula works:
naive_utc = aware_utc.replace(tzinfo=None)
where aware_utc is a timezone-aware datetime object that represents time in UTC.
But if aware datetime object is not in UTC; it fails. You should take into account a (possibly) non-zero UTC offset in the general case:
assert aware.tzinfo is not None and aware.utcoffset() is not None
# local time = utc time + utc offset (by definition)
# -> utc = local - offset
naive_utc = aware.replace(tzinfo=None) - aware.utcoffset()
where aware is a timezone-aware datetime object in an arbitrary timezone.
But I don't have the timezone. I am scraping the date from a html
source. So the timezone could really be from anywhere in the world. Is
there no easy and reliable way to convert a date time to UTC? I could
use both dateutil and pytz to achieve this. Many Thanks.
No. dateutil, pytz won't help you unless the date string itself contains the timezone (or at least its utc offset).
Remember: It is always noon somewhere on Earth i.e., if you collect date/time strings from different places on Earth then you can't compare them unless you attach the corresponding timezones. You can't convert it to UTC, you can't get a valid POSIX timestamp if you don't know the source timezone for the date.
I'm an idiot and it's late here, this time I read the question.
tstmp= date_time.replace(tzinfo=utc).total_seconds()
naive_date = datetime.utcfromtimestamp(tstmp)
First answer will just give you the current naive time
Try this:
dateTime = dateTime.replace(tzinfo=None)
dtUtcAware = pytz.UTC.localize(dateTime)

Python / Mongoengine - Timezone missing when saved to database?

I'm having some trouble saving a date object to Mongo using MongoEngine. Here is my code:
print isodate
>>> 2014-07-01T20:00:00.000Z
import pytz
from dateutil import parser
tz = pytz.timezone('Europe/London')
start = parser.parse(isodate).replace(tzinfo=None)
start = tz.localize(start)
print start
>>> 2014-07-01 20:00:00+01:00
Localizing the date seems to work fine, but when saving to Mongo:
f = Fixture(
start=start
)
The following strangeness is happening when I look at the Mongo document created:
{
_id: ObjectId("53b1dfbde20b47102c824a8f"),
start: ISODate("2014-07-01T19:00:00Z")
}
Is there any reason why the time is off by two hours, and the timezone is no longer present?
I feel you misunderstood date time format. Refer to W3C Date and Time Formats:
Times are expressed in UTC (Coordinated Universal Time), with a special UTC designator ("Z").
Times are expressed in local time, together with a time zone offset in hours and minutes. A time zone offset of "+hh:mm" indicates that the date/time uses a local time zone which is "hh" hours and "mm" minutes ahead of UTC. A time zone offset of "-hh:mm" indicates that the date/time uses a local time zone which is "hh" hours and "mm" minutes behind UTC.
"2014-07-01T20:00:00.000Z" should equal to "2014-07-01 21:00:00+01:00". So it went wrong in localizing datetime, not in saving to Mongo.
If you want to convert "....T....Z" to local time, you can try this:
print isodate
>>> 2014-07-01T20:00:00.000Z
import pytz
from dateutil import parser
local_tz = pytz.timezone('Europe/London')
local_time = parser.parse(isodate).astimezone(local_tz)
print local_time
>>> 2014-07-01 21:00:00+01:00
If you need to perform date arithmetic on local times, do one more step (refer: pytz doc):
local_tz.normalize(local_time)
Actually you can directly save "....T....Z" ISODate into Mongo without converting to local time. Since it already contains timezone info, converting is unnecessary.

Python Django: Time Zone Conversion

I'm parsing an XML file that has the dates in GMT time. It's my first time working with timezones so I'm having some difficulty displaying the right time. In the XML file the date is like this.
2015-06-29 23:05
I set up my model with a basic datetime field like this:
date = models.DateTimeField()
...my settings.py has:
USE_TZ = True
TIME_ZONE = 'America/Toronto'
However when I display the time via views it shows 3:05. Not exactly sure what I'm suppost to do next.
Well, there is no way to determine the time zone of the date time you provided. If you know that it is always GMT, then convert from GMT to your local time zone which is "America/Toronto" in your case.
If possible, I'd recommend changing the date format in your XML. Use UTC, as it provides time zone info.
Check this link out: Python - Convert UTC datetime string to local datetime
Readings I recommend for dealing with time.
UTC: http://www.w3.org/TR/NOTE-datetime
Django Time Zone Docs: https://docs.djangoproject.com/en/1.8/topics/i18n/timezones/

Categories