How to add two offset in python? - python

I am getting a offset form the pytz library from the following line:
offset = datetime.datetime.now(pytz.timezone(timezone)).strftime('%z')
First i pass the US/Eastern in timezone variable
and then i pass the Asia/Kolkata in timezone variable which prints the following value
local_utc = -0400
user_utc = +0530
After getting these values i converted it from string to int by following code:
local_utc = int(local_utc)
user_urc = int(user_utc)
Apart from this i have a timetuple also:
hour, minute,days = (timezone_tuple.tm_hour, timezone_tuple.tm_min,
timezone_tuple.tm_mday)
I want to add the difference of local_utc and user_utc to above tuple such as -0400: 04 such as hour and 00 as minutes.
For example: difference will be : 0930. And 09 will be add to timezone_tuple.tm_hour and 30 will be add to timezone_tuple.tm_min
I didn't found any situation. how can it be possible?
Is there any way to do with spilit method

Your post showed how to find local_utc and user_utc as integers. You could just take the difference local_utc-user_utc to determine the relative offset.
However, datetime, time and pytz should give you all the tools you need to manipulate times without having to parse offsets and do such calculations "manually".
For example,
import pytz
import datetime as dt
import time
eastern = pytz.timezone('US/Eastern')
kolkata = pytz.timezone('Asia/Kolkata')
naive_timetuple = time.localtime(0)
print(naive_timetuple)
# time.struct_time(tm_year=1969, tm_mon=12, tm_mday=31, tm_hour=19, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=365, tm_isdst=0)
Above, I defined a naive timetuple. Below, I "localize" it to US/Eastern time -- that is, make it a timezone-aware datetime:
naive_datetime = dt.datetime(*naive_timetuple[:6])
print(naive_datetime)
# 1969-12-31 19:00:00
localized_datetime = eastern.localize(naive_datetime)
print(localized_datetime)
# 1969-12-31 19:00:00-05:00
Now to convert a timezone-aware datetime to any other timezone, use the astimezone method:
kolkata_datetime = localized_datetime.astimezone(kolkata)
print(kolkata_datetime)
# 1970-01-01 05:30:00+05:30
And if you need to convert a datetime back to a timetuple, use the timetuple method:
kolkata_timetuple = kolkata_datetime.timetuple()
print(kolkata_timetuple)
# time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=5, tm_min=30, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)

Related

Python convert timestamp to unix

I know these questions have been asked before but I'm struggling to convert a timestamp string to a unix time and figuring out whether the datetime objects are naive or aware
For example, to convert the time "2021-05-19 12:51:47" to unix:
>>> from datetime import datetime as dt
>>> dt_obj = dt.strptime("2021-05-19 12:51:47", "%Y-%m-%d %H:%M:%S")
>>> dt_obj
datetime.datetime(2021, 5, 19, 12, 51, 47)
is dt_obj naive or aware and how would you determine this? The methods on dt_obj such as timetz, tzinfo, and tzname don't seem to indicate anything - does that mean that dt_obj is naive?
Then to get unix:
>>> dt_obj.timestamp()
1621421507.0
However when I check 1621421507.0 on say https://www.unixtimestamp.com then it tells me that gmt for the above is Wed May 19 2021 10:51:47 GMT+0000, ie 2 hours behind the original timestamp?
since Python's datetime treats naive datetime as local time by default, you need to set the time zone (tzinfo attribute):
from datetime import datetime, timezone
# assuming "2021-05-19 12:51:47" represents UTC:
dt_obj = datetime.fromisoformat("2021-05-19 12:51:47").replace(tzinfo=timezone.utc)
Or, as #Wolf suggested, instead of setting the tzinfo attribute explicitly, you can also modify the input string by adding "+00:00" which is parsed to UTC;
dt_obj = datetime.fromisoformat("2021-05-19 12:51:47" + "+00:00")
In any case, the result
dt_obj.timestamp()
# 1621428707.0
now converts as expected on https://www.unixtimestamp.com/:
As long as you don't specify the timezone when calling strptime, you will produce naive datetime objects. You may pass time zone information via %z format specifier and +00:00 added to the textual date-time representation to get a timezone aware datetime object:
from datetime import datetime
dt_str = "2021-05-19 12:51:47"
print(dt_str)
dt_obj = datetime.strptime(dt_str+"+00:00", "%Y-%m-%d %H:%M:%S%z")
print(dt_obj)
print(dt_obj.timestamp())
The of above script is this:
2021-05-19 12:51:47
2021-05-19 12:51:47+00:00
1621428707.0
datetime.timestamp()
Naive datetime instances are assumed to represent local time and this method relies on the platform C mktime() function to perform the conversion.
So using this does automatically apply yours machine current timezone, following recipe is given to calculate timestamp from naive datetime without influence of timezone:
timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)

How to properly format timestamp

I have the following info for timestamp from the database:
time_format: str = "%d/%b/%Y %H:%M %Z"
timestamp = '2020-11-03T21:32:19.722012+00:00'
timezone = 'America/New_York'
How can I use datetime to format this information to look as follows:
11/03/2020 17:32EST
I was able to get this far:
datetime.datetime.now().fromisoformat(timestamp_utc).strftime(time_format)
But can't figure out how to replace datetime.now() with any time and then display the desired timezone in place of "UTC"
As python doens't have fantastic timezone support out of the box I'd recommend the pytz library for this use case.
from datetime import datetime
import pytz
# Input
datetime_str = '2020-11-03T21:32:19.722012+00:00'
timezone_str = 'America/New_York'
output_format = '%m/%d/%Y %H:%M %Z'
# Convert input datetime str to python datetime obj
# this datetime is timezone aware, with tz=UTC
utc_datetime = datetime.fromisoformat(datetime_str)
# Convert input timezone str to a pytz timezone object
new_timezone = pytz.timezone(timezone_str)
# Adjust the UTC datetime to use the new timezone
new_timezone_datetime = utc_datetime.astimezone(new_timezone)
# Print in the desired output format
print(new_timezone_datetime.strftime(output_format))
If I run the above code, I get the following...
11/03/2020 16:32 EST
EDIT: The reason it is 16:32 instead of 17:32 is because American/New_York is the same as US/Eastern, in that they use EST/EDT at different points during the year (daylight savings). 2020-11-03 happens to fall in EST.

How to parse datetime and time from strings and how to add these parsed datetime and time values in Python

I am parsing datetime objects from strings,
In these situation I faced a problem where I have to add datetime object with time object together to create combined timestamp.
I know there is a datetime.combine method but unfortunately I could not use it in this situation
e.g. there are two strings, one contains formatted datetime and other has formatted time like below
dt_str = "2018/11/27 14:12:32"
tm_str = "1:23:45.678" # 1 hour 23 minutes 11 seconds and 750 micro seconds
dt_str = "2018/11/27 14:12:32"
tm_str = "1:23:45.678"
First we need to import from python's standard libraries i.e. datetime, time and timedelta
import datetime, time
from datetime import timedelta
Then we will parse dt_str as datetime object and tm_str as time object
dt = datetime.datetime.strptime(dt_str, "%Y/%m/%d %H:%M:%S")
tm = time.strptime(tm_str, "%H:%M:%S.%f")
Now we will use timedelta class to add hours, minutes and seconds to the datetime object from time object
timestamp = dt + timedelta(hours=tm.tm_hour) + \
timedelta(minutes=tm.tm_min) + timedelta(seconds=tm.tm_sec)
Results
print("dt:", dt)
print("tm:", tm)
print("timestamp: ", timestamp)
Note: You can not add microseconds value, at least I do not know the method. If someone knows better way to do above operations please put your solutions below
dt: 2018-11-27 14:12:32
tm: time.struct_time(tm_year=1900, tm_mon=1, tm_mday=1, tm_hour=1, tm_min=23, tm_sec=45, tm_wday=0, tm_yday=1, tm_isdst=-1)
timestamp: 2018-11-27 15:36:17

Why does tzinfo break creating an epoch time in python?

Why does the following happen?
from datetime import datetime
import pytz
d = pytz.utc.localize(datetime.utcnow())
print float(d.strftime('%s')) - float(d.replace(tzinfo=None).strftime('%s')) # 3600.0
Why is it off by one hour whether or not tzinfo is included? I'm assuming it has to do with DST, but... UTC does not have DST.
d.timetuple()
# time.struct_time(tm_year=2013, tm_mon=10, tm_mday=21, tm_hour=17, tm_min=44, tm_sec=40, tm_wday=0, tm_yday=294, tm_isdst=0)
d.replace(tzinfo=None).timetuple()
# time.struct_time(tm_year=2013, tm_mon=10, tm_mday=21, tm_hour=17, tm_min=44, tm_sec=40, tm_wday=0, tm_yday=294, tm_isdst=-1)
So, the difference is tm_isdst is 0 or -1. Both seem very "No DST-ish".
Just not thrilled with the workaround.
Update:
After reading some docs (http://docs.python.org/2/library/time.html#time.mktime) It appears mktime() outputs "localtime" not UTC as I had thought. Which confuses everything.
.strftime('%s') is not supported by Python. Do not use it.
On systems where it works, it interprets the datetime object as time in local timezone i.e., datetime.now().strftime('%s') might return value near time.time().
To find out utc offset or whether DST is in effect for a given local time, you could call d.utcoffset(), d.dst() where d is a datetime object with pytz timezone.
>>> import pytz
>>> d = datetime.now(pytz.utc)
>>> d.utcoffset()
datetime.timedelta(0)
>>> d.dst()
datetime.timedelta(0)
As expected UTC offset is zero for UTC timezone and there is no DST transitions so .dst() is always zero all year round.

How to *change* a struct_time object?

When dealing with times and dates in python, you will stumble across the time.struct_time object:
st = time.strptime("23.10.2012", "%d.%m.%Y")
print st
time.struct_time(tm_year=2012, tm_mon=10, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
Now as this struct does not support item assignment (i.e. you cannot do something like st[1]+=1) how else is it possible to increase, say, the number of the month.
Solutions suggest to convert this time_struct into seconds and add the corresponding number of seconds, but this does not look nice. You also need to know how many days are in a month, or if the year is a leap year or not. I want an easy way to obtain a time_struct to be e.g.
time.struct_time(tm_year=2012, tm_mon=11, tm_mday=23, tm_hour=0, tm_min=0,
tm_sec=0, tm_wday=1, tm_yday=297, tm_isdst=-1)
with just the month increased by one. Creating a time_struct from scratch would be fineā€”but how? What ways are there?
Use the datetime module instead, which has a far richer set of objects to handle date(time) arithmetic:
import datetime
adate = datetime.datetime.strptime("23.10.2012", "%d.%m.%Y").date()
adate + datetime.timedelta(days=30)
You can use the excellent python-dateutil add-on module to get an ever richer set of options for dealing with deltas:
from dateutil.relativedelta import relativedelta
adate + relativedelta(months=1)
relativedelta knows about leap years, month lengths, etc. and will do the right thing when adding a month to, say, January 30th (you end up with February 28th or 29th, it won't cross month boundaries).
So... the schema for the tuple underlying time_struct is given in the documentation here:
http://docs.python.org/2/library/time.html#time.struct_time
And even though it's read-only as a time_struct, you can use casting to list() to get at that tuple directly (remembering to wrap-around your month after you increment it, and keep the end range in 1-12 rather than 0-11). Then the time.struct_time() function will convert a valid 9-tuple back into a time_struct:
st = time.strptime("23.10.2012", "%d.%m.%Y")
st_writable = list(st)
st_writable[1] = (st_writable[1] + 1)%12 + 1
st = time.struct_time(tuple(st_writable))
You can first convert it to datetime, then add a timedelta offset to it:
from time import mktime
from datetime import datetime
dt = datetime.fromtimestamp(mktime(struct))
timedelta = datetime.timedelta(seconds=10)
dt = dt + timedelta
References:
How do you convert a Python time.struct_time object into a datetime object?
http://docs.python.org/library/datetime.html
If you want to avoid datetime all together and stick with time, you can convert to unix timestamp and then subtract the number of seconds you need. To get a time object for 24 hours ago:
time.gmtime(time.mktime(time.gmtime()) - 86400)
However, as OP pointed out this is not good for working with months and should be reserved for seconds, hours, and days.

Categories