How to print the UTC UNIX Epoch/timestamp? - python

When I print the unix epoch, with something like time.time() it seems to print the timestamp in my local timezone. Especially from what converters like: https://www.epochconverter.com tell me.
Does anyone know how I can print the UNIX Epoch/timestamp but actually in UTC time? Thank you so much.

There's no such thing as "UTC UNIX Epoch time". There's UNIX Epoch time, period. It's the same all over the world. It is timezone independent. As long as your computer's clock is set correctly, time.time() will give you the correct UNIX epoch time. datetime.datetime.now().timestamp() will give you the same UNIX Epoch time. You don't need to convert anything and there's nothing to convert.
Now, to address the comment by Deepak, which I think is important:
I do get different responses for datetime.now() vs datetime.utcnow() corresponding to my local time vs UTC. Accordingly, the seconds elapsed has a difference of 19800s (+5:30 for my time zone) for me.
This is a known pitfall with datetime.utcnow and is in fact addressed in the manual:
Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).
To unpack this a bit:
When you call datetime.now(), it returns you a naïve datetime object (meaning it has no tzinfo timezone attached) for your current local time:
>>> datetime.now()
datetime.datetime(2021, 4, 16, 9, 50, 3, 571235)
The time represents my current wall clock time, but it does not know what timezone it's in. So this timestamp could really represent about two dozen different absolute timestamps on this planet, depending on what timezone you take it as.
When using this object's timestamp() method to convert it to an absolute UNIX timestamp, some timezone must be assumed. Python will assume your computer's local timezone for the conversion. Which is fine for datetime.now(), because this timestamp was created with my local time anyway:
>>> datetime.now().timestamp()
1618559403.571235
This is the correct UNIX timestamp at the time of writing. Not "for my local timezone", but globally. At the time of writing, it's 1618559403 everywhere in the world.
Now, if you use datetime.utcnow(), it will give you a naïve timestamp for the current UTC time:
>>> datetime.utcnow()
datetime.datetime(2021, 4, 16, 7, 50, 3, 571235)
Note how it's off by 2 hours from the previous datetime.now(), which is fine, because that's the current local time in the UTC timezone. But since this timestamp is still naïve, when converting it to a UNIX timestamp, Python must assume some timezone, and will assume my local timezone. So it's giving me the UNIX timestamp for 7:50:03 of my local time:
>>> datetime.utcnow().timestamp()
1618552203.571235
Which is not the current UNIX time. It's off by two hours. It's the UNIX time of two hours ago.
If we'd do this properly, by creating an aware timestamp and taking its UNIX time, we'd get the correct UNIX time:
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 4, 16, 7, 50, 3, 571235, tzinfo=datetime.timezone.utc)
>>> datetime.now(timezone.utc).timestamp()
1618559403.571235
Note how the human readable time is the same as we got for datetime.utcnow(), but the UNIX timestamp is correctly the one we got for datetime.now().timestamp(). Which is also the same as we'd get for time.time():
>>> from time import time
>>> time()
1618559403.571235
When pasting this into https://www.epochconverter.com, which you reference:
GMT: Friday, 16 April 2021 07:50:03.571
Your time zone: Friday, 16 April 2021 09:50:03.571 GMT+02:00 DST
Which is correct. In UTC/GMT, this UNIX timestamp represents 7:50am, and in my local timezone it's 9:50am.
If we take the incorrect naïve datetime.utcnow() timestamp 1618552203.571235, the result is:
GMT: Friday, 16 April 2021 05:50:03.571
Your time zone: Friday, 16 April 2021 07:50:03.571 GMT+02:00 DST
Which is incorrect. That was 2 hours ago, not now.

Related

Python: Created datetime in my timezones from timestamp and convert [duplicate]

When I print the unix epoch, with something like time.time() it seems to print the timestamp in my local timezone. Especially from what converters like: https://www.epochconverter.com tell me.
Does anyone know how I can print the UNIX Epoch/timestamp but actually in UTC time? Thank you so much.
There's no such thing as "UTC UNIX Epoch time". There's UNIX Epoch time, period. It's the same all over the world. It is timezone independent. As long as your computer's clock is set correctly, time.time() will give you the correct UNIX epoch time. datetime.datetime.now().timestamp() will give you the same UNIX Epoch time. You don't need to convert anything and there's nothing to convert.
Now, to address the comment by Deepak, which I think is important:
I do get different responses for datetime.now() vs datetime.utcnow() corresponding to my local time vs UTC. Accordingly, the seconds elapsed has a difference of 19800s (+5:30 for my time zone) for me.
This is a known pitfall with datetime.utcnow and is in fact addressed in the manual:
Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).
To unpack this a bit:
When you call datetime.now(), it returns you a naïve datetime object (meaning it has no tzinfo timezone attached) for your current local time:
>>> datetime.now()
datetime.datetime(2021, 4, 16, 9, 50, 3, 571235)
The time represents my current wall clock time, but it does not know what timezone it's in. So this timestamp could really represent about two dozen different absolute timestamps on this planet, depending on what timezone you take it as.
When using this object's timestamp() method to convert it to an absolute UNIX timestamp, some timezone must be assumed. Python will assume your computer's local timezone for the conversion. Which is fine for datetime.now(), because this timestamp was created with my local time anyway:
>>> datetime.now().timestamp()
1618559403.571235
This is the correct UNIX timestamp at the time of writing. Not "for my local timezone", but globally. At the time of writing, it's 1618559403 everywhere in the world.
Now, if you use datetime.utcnow(), it will give you a naïve timestamp for the current UTC time:
>>> datetime.utcnow()
datetime.datetime(2021, 4, 16, 7, 50, 3, 571235)
Note how it's off by 2 hours from the previous datetime.now(), which is fine, because that's the current local time in the UTC timezone. But since this timestamp is still naïve, when converting it to a UNIX timestamp, Python must assume some timezone, and will assume my local timezone. So it's giving me the UNIX timestamp for 7:50:03 of my local time:
>>> datetime.utcnow().timestamp()
1618552203.571235
Which is not the current UNIX time. It's off by two hours. It's the UNIX time of two hours ago.
If we'd do this properly, by creating an aware timestamp and taking its UNIX time, we'd get the correct UNIX time:
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 4, 16, 7, 50, 3, 571235, tzinfo=datetime.timezone.utc)
>>> datetime.now(timezone.utc).timestamp()
1618559403.571235
Note how the human readable time is the same as we got for datetime.utcnow(), but the UNIX timestamp is correctly the one we got for datetime.now().timestamp(). Which is also the same as we'd get for time.time():
>>> from time import time
>>> time()
1618559403.571235
When pasting this into https://www.epochconverter.com, which you reference:
GMT: Friday, 16 April 2021 07:50:03.571
Your time zone: Friday, 16 April 2021 09:50:03.571 GMT+02:00 DST
Which is correct. In UTC/GMT, this UNIX timestamp represents 7:50am, and in my local timezone it's 9:50am.
If we take the incorrect naïve datetime.utcnow() timestamp 1618552203.571235, the result is:
GMT: Friday, 16 April 2021 05:50:03.571
Your time zone: Friday, 16 April 2021 07:50:03.571 GMT+02:00 DST
Which is incorrect. That was 2 hours ago, not now.

datetime not matching with epoch timestamp [duplicate]

When I print the unix epoch, with something like time.time() it seems to print the timestamp in my local timezone. Especially from what converters like: https://www.epochconverter.com tell me.
Does anyone know how I can print the UNIX Epoch/timestamp but actually in UTC time? Thank you so much.
There's no such thing as "UTC UNIX Epoch time". There's UNIX Epoch time, period. It's the same all over the world. It is timezone independent. As long as your computer's clock is set correctly, time.time() will give you the correct UNIX epoch time. datetime.datetime.now().timestamp() will give you the same UNIX Epoch time. You don't need to convert anything and there's nothing to convert.
Now, to address the comment by Deepak, which I think is important:
I do get different responses for datetime.now() vs datetime.utcnow() corresponding to my local time vs UTC. Accordingly, the seconds elapsed has a difference of 19800s (+5:30 for my time zone) for me.
This is a known pitfall with datetime.utcnow and is in fact addressed in the manual:
Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).
To unpack this a bit:
When you call datetime.now(), it returns you a naïve datetime object (meaning it has no tzinfo timezone attached) for your current local time:
>>> datetime.now()
datetime.datetime(2021, 4, 16, 9, 50, 3, 571235)
The time represents my current wall clock time, but it does not know what timezone it's in. So this timestamp could really represent about two dozen different absolute timestamps on this planet, depending on what timezone you take it as.
When using this object's timestamp() method to convert it to an absolute UNIX timestamp, some timezone must be assumed. Python will assume your computer's local timezone for the conversion. Which is fine for datetime.now(), because this timestamp was created with my local time anyway:
>>> datetime.now().timestamp()
1618559403.571235
This is the correct UNIX timestamp at the time of writing. Not "for my local timezone", but globally. At the time of writing, it's 1618559403 everywhere in the world.
Now, if you use datetime.utcnow(), it will give you a naïve timestamp for the current UTC time:
>>> datetime.utcnow()
datetime.datetime(2021, 4, 16, 7, 50, 3, 571235)
Note how it's off by 2 hours from the previous datetime.now(), which is fine, because that's the current local time in the UTC timezone. But since this timestamp is still naïve, when converting it to a UNIX timestamp, Python must assume some timezone, and will assume my local timezone. So it's giving me the UNIX timestamp for 7:50:03 of my local time:
>>> datetime.utcnow().timestamp()
1618552203.571235
Which is not the current UNIX time. It's off by two hours. It's the UNIX time of two hours ago.
If we'd do this properly, by creating an aware timestamp and taking its UNIX time, we'd get the correct UNIX time:
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 4, 16, 7, 50, 3, 571235, tzinfo=datetime.timezone.utc)
>>> datetime.now(timezone.utc).timestamp()
1618559403.571235
Note how the human readable time is the same as we got for datetime.utcnow(), but the UNIX timestamp is correctly the one we got for datetime.now().timestamp(). Which is also the same as we'd get for time.time():
>>> from time import time
>>> time()
1618559403.571235
When pasting this into https://www.epochconverter.com, which you reference:
GMT: Friday, 16 April 2021 07:50:03.571
Your time zone: Friday, 16 April 2021 09:50:03.571 GMT+02:00 DST
Which is correct. In UTC/GMT, this UNIX timestamp represents 7:50am, and in my local timezone it's 9:50am.
If we take the incorrect naïve datetime.utcnow() timestamp 1618552203.571235, the result is:
GMT: Friday, 16 April 2021 05:50:03.571
Your time zone: Friday, 16 April 2021 07:50:03.571 GMT+02:00 DST
Which is incorrect. That was 2 hours ago, not now.

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.

Unix to Timezone Conversion, Offset element

I converted a UNIX timestamp to a human format (sorry I do not know the exact name of it) in a specific timezone (Africa/Algeria) and it evaluated to this: 2020-06-05 19:45:21+01:00. I looked into the datetime module documentation and from what I understood the +01:00, it is the +/-HH:MM offset from the UTC.
What I do not understand is why it is returned with the datetime object given it is already converted to the indicated timezone?
Could someone explain it to me?
Thanks.
POSIX timestamps (Unix time) represent time in seconds since the epoch, 1970-01-01 UTC. No time zone issues involved here. datetime objects on the other hand can be naive (not contain any time zone information) or time zone aware. What you have is a time zone aware datetime object - its string representation prints out as "2020-06-05 19:45:21+01:00". If it had been naive, it would only print "2020-06-05 19:45:21". The repr should also show you a specific time zone, e.g.
print(repr(dt_obj))
>>> datetime.datetime(2020, 6, 5, 19, 45, 21, tzinfo=tzfile('Africa/Algiers'))
The important point is that 2020-06-05 19:45:21+01:00 can be converted back to POSIX timestamp without ambiguity:
from datetime import datetime
datetime.fromisoformat("2020-06-05 19:45:21+01:00").timestamp()
# 1591382721.0
If it wasn't for the +01:00 (no tzinfo), Python would assume that the datetime object belongs in local time, i.e. OS setting; meaning that machines in different time zones would get a different timestamp. I'm on UTC+2, so I would get:
datetime.fromisoformat("2020-06-05 19:45:21").timestamp()
# 1591379121.0
which gives the same timestamp as
datetime.fromisoformat("2020-06-05 19:45:21+02:00").timestamp()
# 1591379121.0
The difference is that with the "+02:00" (tzinfo defined), it is obvious what is happening.

Getting the correct timezone offset in Python using local timezone

Ok let me first start by saying my timezone is CET/CEST. The exact moment it changes from CEST to CET (back from DST, which is GMT+2, to normal, which GMT+1, thus) is always the last Sunday of October at 3AM. In 2010 this was 31 October 3AM.
Now note the following:
>>> import datetime
>>> import pytz.reference
>>> local_tnz = pytz.reference.LocalTimezone()
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 31, 2, 12, 30))
datetime.timedelta(0, 3600)
This is wrong as explained above.
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 30, 2, 12, 30))
datetime.timedelta(0, 7200)
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 31, 2, 12, 30))
datetime.timedelta(0, 7200)
Now it is suddenly correct :/
I know there are several questions about this already, but the solution given is always "use localize", but my problem here is that the LocalTimezone does not provide that method.
In fact, I have several timestamps in milliseconds of which I need the utcoffset of the local timezone (not just mine, but of anyone using the program). One of these is 1288483950000 or Sun Oct 31 2010 02:12:30 GMT+0200 (CEST) in my timezone.
Currently I do the following to get the datetime object:
datetime.datetime.fromtimestamp(int(int(millis)/1E3))
and this to get the utcoffset in minutes:
-int(local_tnz.utcoffset(date).total_seconds()/60)
which, unfortunately, is wrong in many occasions :(.
Any ideas?
Note: I'm using python3.2.4, not that it should matter in this case.
EDIT:
Found the solution thanks to #JamesHolderness:
def datetimeFromMillis(millis):
return pytz.utc.localize(datetime.datetime.utcfromtimestamp(int(int(millis)/1E3)))
def getTimezoneOffset(date):
return -int(date.astimezone(local_tz).utcoffset().total_seconds()/60)
With local_tz equal to tzlocal.get_localzone() from the tzlocal module.
According to Wikipedia, the transition to and from Summer Time occurs at 01:00 UTC.
At 00:12 UTC you are still in Central European Summer Time (i.e. UTC+02:00), so the local time is 02:12.
At 01:12 UTC you are back in the standard Central European Time (i.e. UTC+01:00), so the local time is again 02:12.
When changing from Summer Time back to standard time, the local time goes from 02:59 back to 02:00 and the hour repeats itself. So when asking for the UTC offset of 02:12 (local time), the answer could truthfully be either +01:00 or +02:00 - it depends which version of 02:12 you are talking about.
On further investigation of the pytz library, I think your problem may be that you shouldn't be using the pytz.reference implementation, which may not deal with these ambiguities very well. Quoting from the comments in the source code:
Reference tzinfo implementations from the Python docs.
Used for testing against as they are only correct for the years
1987 to 2006. Do not use these for real code.
Working with ambiguous times in pytz
What you should be doing is constructing a timezone object for the appropriate timezone:
import pytz
cet = pytz.timezone('CET')
Then you can use the utcoffset method to calculate the UTC offset of a date/time in that timezone.
dt = datetime.datetime(2010, 10, 31, 2, 12, 30)
offset = cet.utcoffset(dt)
Note, that the above example will throw an AmbiguousTimeError exception, because it can't tell which of the two versions of 02:12:30 you meant. Fortunately pytz will let you specify whether you want the dst version or the standard version by setting the is_dst parameter. For example:
offset = cet.utcoffset(dt, is_dst = True)
Note that it doesn't harm to set this parameter on all calls to utcoffset, even if the time wouldn't be ambiguous. According to the documentation, it is only used during DST transition ambiguous periods to resolve that ambiguity.
How to deal with timestamps
As for dealing with timestamps, it's best you store them as UTC values for as long as possible, otherwise you potentially end up throwing away valuable information. So first convert to a UTC datetime with the datetime.utcfromtimestamp method.
dt = datetime.datetime.utcfromtimestamp(1288483950)
Then use pytz to localize the time as UTC, so the timezone is attached to the datetime object.
dt = pytz.utc.localize(dt)
Finally you can convert that UTC datetime into your local timezone, and obtain the timezone offset like this:
offset = dt.astimezone(cet).utcoffset()
Note that this set of calculations will produce the correct offsets for both 1288483950 and 1288487550, even though both timestamps are represented by 02:12:30 in the CET timezone.
Determining the local timezone
If you need to use the local timezone of your computer rather than a fixed timezone, you can't do that from pytz directly. You also can't just construct a pytz.timezone object using the timezone name from time.tzname, because the names won't always be recognised by pytz.
The solution is to use the tzlocal module - its sole purpose is to provide this missing functionality in pytz. You use it like this:
import tzlocal
local_tz = tzlocal.get_localzone()
The get_localzone() function returns a pytz.timezone object, so you should be able to use that value in all the places I've used the cet variable in the examples above.
Given a timestamp in milliseconds you can get the utc offset for the local timezone using only stdlib:
#!/usr/bin/env python
from datetime import datetime
millis = 1288483950000
ts = millis * 1e-3
# local time == (utc time + utc offset)
utc_offset = datetime.fromtimestamp(ts) - datetime.utcfromtimestamp(ts)
If we ignore time around leap seconds then there is no ambiguity or non-existent times.
It supports DST and changes of the utc offset for other reasons if OS maintains a historical timezone db e.g., it should work on Ubuntu for any past/present date but might break on Windows for past dates that used different utc offset.
Here's the same using tzlocal module that should work on *nix and Win32 systems:
#!/usr/bin/env python
from datetime import datetime
from tzlocal import get_localzone # pip install tzlocal
millis = 1288483950000
ts = millis * 1e-3
local_dt = datetime.fromtimestamp(ts, get_localzone())
utc_offset = local_dt.utcoffset()
See How to convert a python utc datetime to a local datetime using only python standard library?
To get the utc offset in minutes (Python 3.2+):
from datetime import timedelta
minutes = utc_offset / timedelta(minutes=1)
Don't use pytz.reference.LocalTimezone(), it is only for tests.
import pytz, datetime
tz = timezone('CET')
tz.utcoffset(datetime.datetime.now()).total_seconds()
7200.0

Categories