Get timestamp for hour of current day - python

Ok, I need a way to get the timestamp for the current day but at a certain time.
So for example, I want the unix timestamp for today at 7:30PM - what would I do to get that value? In PHP it's possible with the strtotime() but I'm not sure how to do this in Python.
Edit: To clarify, I mean the current day not a statically written day. So if I ran this script tomorrow it would return the timestamp for 7:30PM tomorrow.

from datetime import datetime
now = datetime.utcnow() # Current time
then = datetime(1970,1,1) # 0 epoch time
ts = now - then
ts = ts.days * 24 * 3600 + ts.seconds
# alternatively, per Martijn Pieters
ts = int(ts.total_seconds())

you can use the time module :
from datetime import datetime
from time import mktime
# like said Ashoka
ts = datetime.strptime("2014-7-7 7:30","%Y-%m-%d %H:%M")
#you have now your datetime object
print mktime(ts.timetuple())
# print 1404711000.0
print int(mktime(ts.timetuple()))
# print 1404711000
be careful mktime don't care of time zone so if you want to have a UTC time zone and still use time , convert date before:
import pytz
fr = pytz.timezone('Europe/Paris')
#localize
ts = fr.localize(ts)
#timestamp in UTC
mktime(ts.astimezone(pytz.UTC).timetuple())

calendar.timegm method returns a timestamp out of passed time tuple:
import calendar
from datetime import datetime
d = datetime(year=2014, month=7, day=8, hour=7, minute=30)
calendar.timegm(d.utctimetuple())
# 1404804600
datetime.utcfromtimestamp(calendar.timegm(d.utctimetuple()))
# datetime.datetime(2014, 7, 8, 7, 30)
The important things are utctimetuple and utcfromtimestamp. You would certainly want a UTC timestamp, and not one in your local timezone.
import calendar
from datetime import datetime
from pytz import timezone, utc
tz = timezone('Europe/Warsaw')
aware = datetime(year=2014, month=7, day=8, hour=7, minute=30)
aware = tz.localize(aware)
# datetime.datetime(2014, 7, 8, 7, 30, tzinfo=<DstTzInfo 'Europe/Warsaw' CEST+2:00:00 DST>)
stamp = calendar.timegm(aware.utctimetuple())
# 1404797400
d = datetime.utcfromtimestamp(stamp)
# datetime.datetime(2014, 7, 8, 5, 30)
d = d.replace(tzinfo=utc)
d.astimezone(tz)
# datetime.datetime(2014, 7, 8, 7, 30, tzinfo=<DstTzInfo 'Europe/Warsaw' CEST+2:00:00 DST>)

Related

Python datetime timedelta object with timezone

I have a datetime timedelta object, which I parse from received UTC seconds like this which is an offset from todays midnight:
datetime.timedelta(seconds=seconds)
This is in UTC, but I want to add timezone awareness to it.
So for example now, the seconds=18600 reports 5:10:00 which is correct in UTC.
I want to add a fixed timezone to it, like 'Europe/Budapest', so it will show 6:10:00 or 7:10:00 (based on daytime-saving time).
Is it somehow possible if I don't have a full datetime object, only a timedelta?
Thanks!
Assuming those seconds you get represent the offset since midnight UTC today (or any other particular day), then calculate them exactly as that:
>>> from datetime import datetime, timedelta, timezone
>>> import pytz
>>> midnight = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0)
datetime.datetime(2022, 4, 8, 0, 0, tzinfo=datetime.timezone.utc)
>>> timestamp = midnight + timedelta(seconds=seconds)
datetime.datetime(2022, 4, 8, 5, 10, tzinfo=datetime.timezone.utc)
>>> local_timestamp = timestamp.astimezone(pytz.timezone('Europe/Budapest'))
datetime.datetime(2022, 4, 8, 7, 10, tzinfo=<DstTzInfo 'Europe/Budapest' CEST+2:00:00 DST>)
Perhaps you would like to offset the timedelta by the UTC offset?
import datetime
import pytz
nowtz = datetime.datetime.now(pytz.timezone("Europe/Budapest"))
seconds = 18600 + nowtz.utcoffset().total_seconds()
x = datetime.timedelta(seconds=seconds)
>>> x
7:10:00
Or if you wanted a datetime
# This is a datetime object
>>> nowtz + x
datetime.datetime(2022, 4, 8, 21, 29, 2, 328802, tzinfo=<DstTzInfo 'Europe/Budapest' CEST+2:00:00 DST>)
# This is the above datetime formatted as a string
>>> (nowtz+x).strftime("%F %r")
'2022-04-08 09:27:31 PM'

How to get correct timestamp from UTC datetime

In my program, I need to use a datetime object that is in utc time not my local time, and I also need the timestamp (seconds since epoch) of that datetime object.
import datetime
my_time = datetime.datetime.utcnow()
timestamp = my_time.timestamp()
However, the timestamp was wrong. It was the timestamp when my local time is my_time, not the correct timestamp when the utc time is my_time. How can I get the correct timestamp? I don't want to create another datetime object because there might be microseconds of difference.
Edit
Example:
import datetime
utc_time = datetime.datetime.utcnow()
local_time = datetime.datetime.now()
utc_timestamp = utc_time.timestamp()
local_timestamp = local_time.timestamp()
print(utc_timestamp)
print(local_timestamp)
My result:
1633133103.945903
1633161903.945903
The two are different by 8 hours, because I live in UTC+08:00 time zone, and the first one is not "seconds since epoch". I want to get the correct timestamp from utc_time because technically those two object were not created at the same time.
use aware datetime,
from datetime import datetime, timezone
t_loc = datetime.now().astimezone() # local time, as set in my OS (tz Europe/Berlin)
t_utc = datetime.now(timezone.utc)
print(repr(t_loc))
print(repr(t_utc))
# e.g.
# datetime.datetime(2021, 10, 2, 11, 10, 26, 920792, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200), 'CEST'))
# datetime.datetime(2021, 10, 2, 9, 10, 26, 920809, tzinfo=datetime.timezone.utc)
This will give you correct Unix time as well:
t_loc_unix = t_loc.timestamp()
t_utc_unix = t_utc.timestamp()
print(t_loc_unix, t_utc_unix)
# 1633165826.920792 1633165826.920809
Unix timestamps are now equal as it should be since Unix time always (should) refers to UTC.

Python How do I calibrate to a specific time?

There is a web series starting on 2017-01-11 19:00 Warsaw time. I want to make a list of time zones for major cities to help people figure out when to tune in. How can I tell Python that the date variable is related to the time in Warsaw?
import datetime
from pytz import timezone
from pytz import common_timezones
# warsaw time
s = '2017-01-11 19:00:00.801000'
format = '%Y-%m-%d %H:%M:%S.%f'
date = datetime.datetime.strptime(s, format)
fmt = "%Y-%m-%d %H:%M:%S %Z%z"
warsaw_time = date
print(warsaw_time.strftime(fmt))
for zone in common_timezones:
print( zone + str(warsaw_time.astimezone(timezone(zone))) )
If I understand correctly, you are trying to set the date to Warsaw's local time (CET). Which you can do like this:
>>> warsaw = pytz.timezone("CET")
>>> dt = datetime.datetime(2017, 1, 11, 19, 0, 0, 0, warsaw)
>>> dt
datetime.datetime(2017, 1, 11, 19, 0, tzinfo=<DstTzInfo 'CET' CET+1:00:00 STD>)

How to find next day's Unix timestamp for same hour, including DST, in Python?

In Python, I can find the Unix time stamp of a local time, knowing the time zone, like this (using pytz):
>>> import datetime as DT
>>> import pytz
>>> mtl = pytz.timezone('America/Montreal')
>>> naive_time3 = DT.datetime.strptime('2013/11/03', '%Y/%m/%d')
>>> naive_time3
datetime.datetime(2013, 11, 3, 0, 0)
>>> localized_time3 = mtl.localize(naive_time3)
>>> localized_time3
datetime.datetime(2013, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>)
>>> localized_time3.timestamp()
1383451200.0
So far, so good. naive_time is not aware of the time zone, whereas localized_time knows its midnight on 2013/11/03 in Montréal, so the (UTC) Unix time stamp is good. This time zone is also my local time zone and this time stamp seems right:
$ date -d #1383451200
Sun Nov 3 00:00:00 EDT 2013
Now, clocks were adjusted one hour backward November 3rd at 2:00 here in Montréal, so we gained an extra hour that day. This means that there were, here, 25 hours between 2013/11/03 and 2013/11/04. This shows it:
>>> naive_time4 = DT.datetime.strptime('2013/11/04', '%Y/%m/%d')
>>> localized_time4 = mtl.localize(naive_time4)
>>> localized_time4
datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EST-1 day, 19:00:00 STD>)
>>> (localized_time4.timestamp() - localized_time3.timestamp()) / 3600
25.0
Now, I'm looking for an easy way to get the localized_time4 object from localized_time3, knowing I want to get the next localized day at the same hour (here, midnight). I tried timedelta, but I believe it's not aware of time zones or DST:
>>> localized_time4td = localized_time3 + DT.timedelta(1)
>>> localized_time4td
datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>)
>>> (localized_time4td.timestamp() - localized_time3.timestamp()) / 3600
24.0
My purpose is to get informations about log entries that are stored with their Unix timestamp for each local day. Of course, if I use localized_time3.timestamp() and add 24 * 3600 here (which will be the same as localized_time4td.timestamp()), I will miss all log entries that happened between localized_time4td.timestamp() and localized_time4td.timestamp() + 3600.
In other words, the function or method I'm looking for should know when to add 25 hours, 24 hours or 23 hours sometimes to a Unix time stamp, depending on when DST shifts happen.
Without using a new package:
def add_day(x):
d = x.date()+DT.timedelta(1)
return mtl.localize(x.replace(year=d.year, month=d.month, day=d.day, tzinfo=None))
Full script:
import datetime as DT
import pytz
import calendar
mtl = pytz.timezone('America/Montreal')
naive_time3 = DT.datetime.strptime('2013/11/03', '%Y/%m/%d')
print repr(naive_time3)
#datetime.datetime(2013, 11, 3, 0, 0)
localized_time3 = mtl.localize(naive_time3)
print repr(localized_time3)
#datetime.datetime(2013, 11, 3, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EDT-1 day, 20:00:00 DST>)
print calendar.timegm(localized_time3.utctimetuple())
#1383451200.0
def add_day(x):
d = x.date()+DT.timedelta(1)
return mtl.localize(x.replace(year=d.year, month=d.month, day=d.day, tzinfo=None))
print repr(add_day(localized_time3))
#datetime.datetime(2013, 11, 4, 0, 0, tzinfo=<DstTzInfo 'America/Montreal' EST-1 day, 19:00:00 STD>)
(calendar is for Python2.)
I gradually provide several solutions with the most robust solution at the very end of this answer that tries to handle the following issues:
utc offset due to DST
past dates when the local timezone might have had different utc offset due to reason unrelated to DST. dateutil and stdlib solutions fail here on some systems, notably Windows
ambiguous times during DST (don't know whether Arrow provides interface to handle it)
non-existent times during DST (the same)
To find POSIX timestamp for tomorrow's midnight (or other fixed hour) in a given timezone, you could use code from How do I get the UTC time of “midnight” for a given timezone?:
from datetime import datetime, time, timedelta
import pytz
DAY = timedelta(1)
tz = pytz.timezone('America/Montreal')
tomorrow = datetime(2013, 11, 3).date() + DAY
midnight = tz.localize(datetime.combine(tomorrow, time(0, 0)), is_dst=None)
timestamp = (midnight - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
dt.date() method returns the same naive date for both naive and timezone-aware dt objects.
The explicit formula for timestamp is used to support Python version before Python 3.3. Otherwise .timestamp() method could be used in Python 3.3+.
To avoid ambiguity in parsing input dates during DST transitions that are unavoidable for .localize() method unless you know is_dst parameter, you could use Unix timestamps stored with the dates:
from datetime import datetime, time, timedelta
import pytz
DAY = timedelta(1)
tz = pytz.timezone('America/Montreal')
local_dt = datetime.fromtimestamp(timestamp_from_the_log, tz)
tomorrow = local_dt.date() + DAY
midnight = tz.localize(datetime.combine(tomorrow, time(0, 0)), is_dst=None)
timestamp = (midnight - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
To support other fixed hours (not only midnight):
tomorrow = local_dt.replace(tzinfo=None) + DAY # tomorrow, same time
dt_plus_day = tz.localize(tomorrow, is_dst=None)
timestamp = dt_plus_day.timestamp() # use the explicit formula before Python 3.3
is_dst=None raises an exception if the result date is ambiguous or non-existent. To avoid exception, you could choose the time that is closest to the previous date from yesterday (same DST state i.e., is_dst=local_dt.dst()):
from datetime import datetime, time, timedelta
import pytz
DAY = timedelta(1)
tz = pytz.timezone('America/Montreal')
local_dt = datetime.fromtimestamp(timestamp_from_the_log, tz)
tomorrow = local_dt.replace(tzinfo=None) + DAY
dt_plus_day = tz.localize(tomorrow, is_dst=local_dt.dst())
dt_plus_day = tz.normalize(dt_plus_day) # to detect non-existent times
timestamp = (dt_plus_day - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
.localize() respects given time even if it is non-existent, therefore .normalize() is required to fix the time. You could raise an exception here if normalize() method changes its input (non-existent time detected in this case) for consistency with other code examples.
(Thanks to #rdodev for pointing me to Arrow).
Using Arrow, this operation becomes easy:
>>> import arrow
>>> import datetime as DT
>>> lt3 = arrow.get(DT.datetime(2013, 11, 3), 'America/Montreal')
>>> lt3
<Arrow [2013-11-03T00:00:00-04:00]>
>>> lt4 = arrow.get(DT.datetime(2013, 11, 4), 'America/Montreal')
>>> lt4
<Arrow [2013-11-04T00:00:00-05:00]>
>>> lt4.timestamp - (lt3.replace(days=1).timestamp)
0
>>> (lt3.replace(days=1).timestamp - lt3.timestamp) / 3600
25.0
Using Arrow's replace method, singular unit names replace that property while plural adds to it. So lt3.replace(days=1) is November 4th, 2013 while lt3.replace(day=1) is November 1st, 2013.
Here an alternative based on dateutil:
>>> # In Spain we changed DST 10/26/2013
>>> import datetime
>>> import dateutil.tz
>>> # tzlocal gets the timezone of the computer
>>> dt1 = datetime.datetime(2013, 10, 26, 14, 00).replace(tzinfo=dateutil.tz.tzlocal())
>>> print dt1
2013-10-26 14:00:00+02:00
>>> dt2 = dt1 + datetime.timedelta(1)
>>> print dt2
2013-10-27 14:00:00+01:00
# see if we hace 25 hours of difference
>>> import time
>>> (time.mktime(dt2.timetuple()) - time.mktime(dt1.timetuple())) / 3600.0
25.0
>>> (float(dt2.strftime('%s')) - float(dt1.strftime('%s'))) / 3600 # the same
25.0

python - datetime with timezone to epoch

In the code below, I am calculating now epoch and beginning of current day epoch.
import time
import pytz
from datetime import datetime
tz1 = pytz.timezone('CST6CDT')
utc = pytz.timezone('UTC')
now = pytz.UTC.localize(datetime.utcnow())
now_tz = now.astimezone(tz1)
print now_tz
print now_tz.strftime('%s')
begin_day = now_tz.replace(hour=0, minute=0, second=0)
print begin_day
print begin_day.strftime('%s')
print statements:
2012-08-28 13:52:21.595718-05:00
1346187141
2012-08-28 00:00:00.595718-05:00
1346137200
Converting epochs to timestamp with CDT timezone:
1346187141 - Aug 28 2012 15:52:21,
1346137200 - Aug 28 2012 02:00:00
I'd like the second epoch to be beginning of the day but it's 2 am. It looks like it is still using local timezone PST when converting to epoch.
What am I doing wrong ? or can this be done a different way?
Thanks!
To convert a datetime with timezone to epoch (POSIX timestamp):
from datetime import datetime
import pytz
tz = pytz.timezone('CST6CDT')
# a datetime with timezone
dt_with_tz = tz.localize(datetime(2012, 8, 28, 19, 33, 50), is_dst=None)
# get timestamp
ts = (dt_with_tz - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
# -> 1346200430.0
It is how datetime.timestamp method is implemented for timezone-aware datetime objects in Python 3.
To get "now epoch":
from datetime import datetime
now_epoch = (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()
Or (assuming time uses POSIX epoch):
import time
now_epoch = time.time()
Getting "beginning of current day epoch" is more complex because current day may be different in different timezones:
from datetime import datetime, time
import pytz
tz = pytz.timezone('CST6CDT')
# get current date in given timezone
today = datetime.now(tz).date()
# -> datetime.date(2013, 6, 22)
# get beginning of current day in given timezone as a datetime with timezone
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
# -> datetime.datetime(2013, 6, 22, 0, 0, tzinfo=<DstTzInfo 'CST6CDT'...>)
# get timestamp
ts = (midnight - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
# -> 1371877200.0
See How do I get the UTC time of “midnight” for a given timezone?.
To get "beginning of current day epoch" assuming UTC date:
from datetime import datetime, date
# get current date in UTC
utc_date = datetime.utcnow().date()
# -> datetime.date(2013, 6, 23)
# get timestamp
ts = (utc_date - date(1970, 1, 1)).days * 86400
# -> 1371945600
See Converting datetime.date/datetime.datetime to UTC timestamp in Python.
NOTE: My answer is flat-out wrong. (I'd like to delete it, but am unable to do so until the accept flag is removed.)
Please see J.F.Sebastian's answer.
Here is code demonstrating a value of now_tz for which our two methods produce different results.
import calendar
import pytz
import datetime as dt
tz1 = pytz.timezone('US/Eastern')
utc = pytz.timezone('UTC')
now = utc.localize(dt.datetime(2002, 10, 28), is_dst=None)
now_tz = now.astimezone(tz1)
now_epoch = calendar.timegm(now_tz.utctimetuple())
begin_day = tz1.normalize(now_tz.replace(hour=0, minute=0, second=0))
midnight = tz1.localize(dt.datetime.combine(now_tz, dt.time(0, 0)), is_dst=None)
if begin_day != midnight:
print(begin_day)
# 2002-10-27 01:00:00-04:00 # my result -- is not midnight
print(midnight)
# 2002-10-27 00:00:00-04:00 # J.F.Sebastian's result is correct
(Original answer redacted)
the latest release of simple-date (version 0.2 on pypi) will manage the details for you:
>>> from simpledate import *
>>> now_utc = SimpleDate(tz='UTC')
>>> now_tz = now_utc.convert(tz='CST6CDT')
>>> begin_day = now_tz.replace(hour=0, minute=0, second=0, microsecond=0)
>>> now_utc.timestamp
1371950295.777453
>>> now_tz.timestamp
1371950295.777453
>>> begin_day.timestamp
1371877200.0
we can go backwards to check the timestamps (although it's clear above that switching timezone didn't change the epoch, while moving to start of day did):
>>> SimpleDate(1371877200.0, tz='CST6CDT')
SimpleDate('2013-06-22 00:00:00.000000 CDT', tz='CST6CDT')
>>> SimpleDate(1371877200.0, tz='UTC')
SimpleDate('2013-06-22 05:00:00.000000 UTC')

Categories