Python unix timestamp conversion and timezone - python

Hey all! Ive got timezone troubles.
I have a time stamp of 2010-07-26 23:35:03
What I really want to do is subtract 15 minutes from that time.
My method was going to be a simple conversion to unix time, subtract the seconds and convert back. Simple right?
My problem is that python adjusts the returned unix time using my local timezone, currently eastern daylight savings time which I believe is GMT -4.
So when I do this:
# packet[20] holds the time stamp
unix_time_value = (mktime(packet[20].timetuple()))
I get 1280201703 which is Tue, 27 Jul 2010 03:35:03. I can do this:
unix_time_value = (mktime(packet[20].timetuple())) - (4 * 3600)
but now I have to check for eastern standard time which is -5 GMT and adjust the (4 * 3600) to (5 * 3600). Is there any way to tell python to not use my local timezone and just convert the darn timestamp OR is there an easy way to take packet[20] and subtract 15 minutes?

Subtract datetime.timedelta(seconds=15*60).

The online docs have a handy table (what you call "unix time" is more properly called "UTC", for "Universal Time Coordinate", and "seconds since the epoch" is a "timestamp" as a float...):
Use the following functions to convert
between time representations:
From To Use
seconds since the epoch struct_time in UTC gmtime()
seconds since the epoch struct_time in local time localtime()
struct_time in UTC seconds since the epoch calendar.timegm()
struct_time in local time seconds since the epoch mktime()
where the unqualified function names come from the time module (since that's where the docs are;-). So, since you apparently start with a struct_time in UTC, use calendar.timegm() to get the timestamp (AKA "seconds since the epoch"), subtract 15 * 60 = 900 (since the units of measure are seconds), and put the resulting "seconds since the epoch" back into a struct_time in UTC with time.gmtime. Or, use time.mktime and time.localtime if you prefer to work in local times (but that might give problem if the 15 minutes can straddle the instant in which it switches to DST or back -- always working in UTC is much sounder).
Of course, to use calendar.timegm, you'll need an import calendar in your code (imports are usually best placed at the top of the script or module).

Scroll down and read about subtracting from a date: http://pleac.sourceforge.net/pleac_python/datesandtimes.html

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.

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.

Converting strings to datetime while changing timezone

I have many strings of dates and times (or both), like these:
'Thu Jun 18 19:30:21 2015'
'21:07:52'
I want to convert these times to the proper datetime format while also changing the timezone to UTC. The current timezone is 4 hours behind UTC. Is there a way that I can tell python to add 4 hours while converting the formats? Can it also take care of the date in UTC such that when the hour goes past 24 the date changes and time resets?
I will ultimately be inserting these into a mysql table into fields with the 'datetime' and 'time' data type, but they all need to be in UTC.
I would approach this with time.strptime() to parse the source time string, time.mktime() to convert the resulting time vector into an epoch time (seconds since 1970-01-01 00:00:00), and time.strftime() to format the time as you like.
For the timezone adjustment, you could add 4*3600 to the epoch time value or, more generally, append a timezone string to the source and use %Z to parse it.

Convert Cocoa timestamp in Python

I have a Cocoa timestamp (zero time of January 1st, 2001 00:00:00 UTC) that I need to convert in Python. When I use the following code it assumes a Unix timestamp input. Besides adding 31 years in seconds (Just under a billion seconds...) what's the best way to convert the time?
import datetime
print(datetime.datetime.fromtimestamp(int("495759456")).strftime('%Y-%m-%d %H:%M:%S'))
The output for this line of code is '1985-09-16 16:12:03'
Would something like this work for you:
from datetime import datetime
unix = datetime(1970, 1, 1) # UTC
cocoa = datetime(2001, 1, 1) # UTC
delta = cocoa - unix # timedelta instance
timestamp = datetime.fromtimestamp(int("495759456")) + delta
print(timestamp.strftime('%Y-%m-%d %H:%M:%S'))
I didn't specify timezone information for the two starts of time as they're in the same zone so I assume it shouldn't matter which is used when computing the difference. For converting the timestamp string, you may need to adjust for your timezone if it's different than the one in which the string was generated.
The above code produces 2016-09-16 15:57:36
One thing to be careful on when doing the conversion with the above solution, is to make sure that the Cocoa timestamp's unit is the same as the one you'd want in the unix timestamp. I've noticed that at many instance the cocoa timestamp is stored in nano seconds.
Unless you want your Unix timestamp to also be represented as nano seconds, make sure to do divide the cocoa timestamp by the appropriate number before conversion. e.g. Divide by 1000000000 to convert nano seconds to seconds etc...
Source

Categories