Pytz convert time to UTC without DST - python-3.x

I've done a quite a bit of research before posting this, but I can't seem to get the conversion right. I have some data which has timestamps, and some have DST applied, and others don't. I thought the correct way to specify that it's without DST is using the is_dst parameter for pytz. All 3 options give the same offset from UTC, which is incorrect. The offset should be +1000. What's the best way to do this conversion, and why does the is_dst parameter not make any difference?
pytz_eastern.localize(datetime(2018, 1, 18, 18, 50), is_dst=None).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1100'
pytz_eastern.localize(datetime(2018, 1, 18, 18, 50), is_dst=False).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1100'
pytz_eastern.localize(datetime(2018, 1, 18, 18, 50), is_dst=True).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1100'

The is_dst parameter is ignored for most timestamps. It is only used during DST transition ambiguous periods to resolve that ambiguity.
You're trying to convert a datetime by ignoring the transition rules. I don't think pytz will support that. Instead you can pick a date in standard time and ask for its offset, then use that.
>>> from datetime import *
>>> import pytz
>>> pytz_eastern = pytz.timezone('Australia/Sydney')
The utcoffset method gives the offset for a particular datetime (and the dst method will also give just the DST offset).
>>> pytz_eastern.dst(datetime(2018, 6, 1))
datetime.timedelta(0)
>>> pytz_eastern.utcoffset(datetime(2018, 6, 1))
datetime.timedelta(0, 36000)
>>> pytz_eastern.dst(datetime(2018, 1, 1))
datetime.timedelta(0, 3600)
>>> pytz_eastern.utcoffset(datetime(2018, 1, 1))
datetime.timedelta(0, 39600)
Take the utcoffset from a date in standard time and set it directly with the tzinfo kwarg of datetime, and only then give it to pytz for conversion.
So here's a datetime that was shown on a clock which was not adjusted for DST:
>>> standard_offset = timezone(pytz_eastern.utcoffset(datetime(2018, 6, 1)))
>>> datetime(2018, 1, 18, 18, 50, tzinfo=standard_offset).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 18:50 +1000'
And here's that same datetime brought back into reality:
>>> datetime(2018, 1, 18, 18, 50, tzinfo=standard_offset).astimezone(pytz_eastern).strftime('%Y-%m-%d %H:%M %z')
'2018-01-18 19:50 +1100'
(The standard offset also seems to be available as ._utcoffset, but that's not documented, so that's a reason to ask for the utcoffset of a specific date, as it's less likely for offsets in the past to ever change.)
In fact, since pytz gives you the computed offset and the current DST value, you could subtract the two to get the standard offset ignoring DST.
def add_forgotten_dst(dt, zoneinfo):
'''Like pytz.localize, but ignores dst.'''
utcoffset = zoneinfo.utcoffset(dt)
dst = zoneinfo.dst(dt)
standard_offset = utcoffset - dst
dt = dt.replace(tzinfo=timezone(standard_offset))
return dt.astimezone(zoneinfo)
>>> naive_time = datetime(2018, 1, 18, 18, 50)
>>> print(pytz_eastern.localize(naive_time))
2018-01-18 18:50:00+11:00
>>> print(add_forgotten_dst(naive_time, pytz_eastern))
2018-01-18 19:50:00+11:00

Related

Python datetime day light saving issue?

I am wondering why the delta is 3601 seconds when it should be 1 second:
from datetime import datetime
from dateutil import tz
# Create eastern timezone
eastern = tz.gettz('America/New_York')
# 2017-03-12 01:59:59 in Eastern Time (EST)
spring_ahead_159am = datetime(2017, 3, 12, 1, 59, 59, tzinfo = eastern)
# 2017-03-12 03:00:00 in Eastern Time (EDT)
spring_ahead_3am = datetime(2017, 3, 12, 3, 0, 0, tzinfo = eastern)
(spring_ahead_3am - spring_ahead_159am).seconds
3601
Please explain me what I am doing wrong? Why it's not giving me 1 second diff?
P.S:
Please explain why this will do work easily:
Let:
EST = timezone(timedelta(hours=-5))
EDT = timezone(timedelta(hours=-4))
spring_ahead_159am = datetime(2017, 3, 12, 1, 59, 59, tzinfo = EST)
spring_ahead_3am = datetime(2017, 3, 12, 3, 0, 0, tzinfo = EDT)
(spring_ahead_3am - spring_ahead_159am).seconds
1
This is a little quirk of datetime objects. Quoting from the documentation:
Subtraction of a datetime from a datetime is defined only if both operands are naive, or if both are aware. If one is aware and the other is naive, TypeError is raised.
If both are naive, or both are aware and have the same tzinfo attribute, the tzinfo attributes are ignored, and the result is a timedelta object t such that datetime2 + t == datetime1. No time zone adjustments are done in this case.
You can certain get what you want by subtracting their DST components:
>>> spring_ahead_3am - spring_ahead_3am.dst() - spring_ahead_159am + spring_ahead_159am.dst()
datetime.timedelta(seconds=1)
Update
Consider using this function, which does the Right Thing across timezones and DST changes:
def datesub( dt1, dt2 ):
return datetime.timedelta( seconds=dt2.timestamp()-dt1.timestamp() )

What is the timezone used in chrome://webrtc-internal stats?

I have been analyzing the JSON file generated using chrome://webrtc-internal, while running webrtc.
I'm trying to find the matching timezone of the startTime in the following result:
'RTCVideoSource_6-width': {
'startTime': '2021-04-14T07:09:33.163Z',
'endTime': '2021-04-14T07:14:12.161Z',
'values': '[1920,1920,1920,1920,1920,1920,1920,1920,1920]'},
I tried UTC timezone to find the corresponding timestamp in my timezone but didn't succeed.
yourdate = dateutil.parser.parse(RTCVideoSource_6-width['startTime'])
startTime_utc = yourdate.replace(tzinfo=pytz.UTC)
startTime_hk=startTime_utc.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
#since 1970
startAge_utc = datetime.datetime(1970,1,1).replace(tzinfo=pytz.UTC)
startAge_hk=startAge_utc.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
start_in_seconds = int((startTime_hk- startAge_hk).total_seconds())
When I compared now() as a timestamp in seconds, I got values with a relatively big difference,
1618384173 and 1618383543.
What is the timezone used in chrome://webrtc-internal stats?
Is my conversion method correct?
See ISO8601: you have UTC date/time (Z = zulu = UTC). See How do I parse an ISO 8601-formatted date? how to parse. Unix time (seconds since 1970-01-01) on the other hand always (should) refer to UTC (e.g. startTime_utc and startTime_hk must give the same timestamp!). Note: datetime objects have a timestamp method.
EX:
from datetime import datetime
from zoneinfo import ZoneInfo # Python 3.9+
d = {'startTime': '2021-04-14T07:09:33.163Z',
'endTime': '2021-04-14T07:14:12.161Z',
'values': '[1920,1920,1920,1920,1920,1920,1920,1920,1920]'}
startTime_utc = datetime.fromisoformat(d['startTime'].replace('Z', '+00:00'))
print(repr(startTime_utc))
# datetime.datetime(2021, 4, 14, 7, 9, 33, 163000, tzinfo=datetime.timezone.utc)
print(startTime_utc.timestamp())
# 1618384173.163
startTime_HK = startTime_utc.astimezone(ZoneInfo('Asia/Hong_Kong'))
print(repr(startTime_HK))
# datetime.datetime(2021, 4, 14, 15, 9, 33, 163000, tzinfo=zoneinfo.ZoneInfo(key='Asia/Hong_Kong'))
print(startTime_HK.timestamp())
# 1618384173.163

How can i print year,month as 0 in datetime less than 30day? or 1year?

i am trying to get the month and year of this and it raises error
from datetime import datetime
x = datetime(2020, 9, 8, 19, 42, 39, 264658) - datetime.fromtimestamp(1598192097.728026)
print(x.year) or (x.month) #AttributeError: 'datetime.timedelta' object has no attribute 'year'
how i can get month , year as 0 ? any ideas without use exception?
Besides that 'datetime.timedelta' object has no attribute 'year' - note that time spans greater than a week are ambiguous; e.g. the number of days in a months varies.
What you could use here is dateutil's relativdelta:
from datetime import datetime
from dateutil.relativedelta import relativedelta
timestamp = 1598192097.728026
dtobj = datetime(2020, 9, 8, 19, 42, 39, 264658)
x = relativedelta(dtobj, datetime.fromtimestamp(timestamp))
print(x.years, x.months)
# 0 0
your x variable does not have an attribute year or month here x stores the difference between the two times it can only return the difference. You have performed arithmetic operation the two and x is a class date type known as date.timedelta. And as for your needs you want it to return zero years and zero months. You can convert x to string and use if statement to check for years and months.
from datetime import datetime
x = datetime(2020, 9, 8, 19, 42, 39, 264658) -
datetime.fromtimestamp(1598192097.728026)
print(type(x))
print(x)
if 'month' in str(x):
if 'year' in str(x):
print(x)
else:
print(f'0 years {x}')
else:
if 'year' in str(x):
print(x)
else:
print(f' 0 years 0 months {x}')

Find timezone time difference using pytz

I am creating a naive datetime object which contains no timezone information, but I know that it is always in UTC. I want to calculate the time difference between local time and UTC for any timezone I define, which would take into account DST as well.
What I am thus doing is the following:
from datetime import datetime, timedelta
now = datetime(2018,3,27,15,20) #Create a naive datetime object
now_utc = timezone("UTC").localize(now) # Add UTC timezone information to it
now_madrid = now_utc.astimezone(timezone("Europe/Madrid")) # convert to Madrid timezone
Normally, if I was to calculate the time difference between two datetime objects I would subtract them. But when I try diff = now_utc - now_madrid , the result is the following:
In [275]: now_utc-now_madrid
Out[275]: datetime.timedelta(0)
Can anyone please tell me, how I could find the timezone difference in this case? Thank you in advance :)
Time delta is "0" because Madrid is 2 hours head of UTC.
now_utc-now_madrid
When you subtract it like this means it's in another timezone behind UTC.
There maybe a more efficient methods out there but this is how I would do it.
>>> import pytz
>>> import datetime
>>> utc_now = pytz.utc.localize(datetime.datetime.utcnow ())
>>> utc_now
datetime.datetime(2018, 3, 27, 19, 11, 19, 659257, tzinfo=<UTC>)
>>> madrid_now = utc_now.astimezone(pytz.timezone ('Europe/Madrid'))
>>> madrid_now
datetime.datetime(2018, 3, 27, 21, 11, 19, 659257, tzinfo=<DstTzInfo 'Europe/Madrid' CEST+2:00:00 DST>)
As you can see, the timezone conversion is already provided by tzinfo CEST+2:00:00 DST.
If you need to do any arithmetic on that value then try:
>>> utc_now + timedelta (hours = 2) # Since Madrid is +2:00:00 hours
datetime.datetime(2018, 3, 27, 21, 11, 19, 659257, tzinfo=<UTC>)
Or extract the offset timezone differences from strftime.
>>> madrid_now.strftime ('%z')
'+0200'
You can find more reading here:
http://pytz.sourceforge.net/

Is there a function in Python/Pandas to get business time Delta between two date times?

I've got a pandas dataframe with two datetime columns and I would like to calculate the timedelta between the columns in "business minutes". It's easy to add business timedeltas using the offsets method, but I can't seem to find something built in that returns a timedelta in business days, hours, minutes, seconds. I'm very new to Python so it's very likely I'm missing something.
Thanks,
Nick
I don't think there's a way in numpy/pandas, but you can do it with python lib businesstime:
>>> datetime(2013, 12, 26, 5) - datetime(2013, 12, 23, 12)
datetime.timedelta(2, 61200)
>>> bt = businesstime.BusinessTime(holidays=businesstime.holidays.usa.USFederalHolidays())
>>> bt.businesstimedelta(datetime(2013, 12, 23, 12), datetime(2013, 12, 26, 5))
datetime.timedelta(1, 18000)

Resources