To another answer already explained the problems of your code, but there is a catch: if the code runs on the 1st of any month, you will mount a string corresponding to the zero day, and make a mistake.
Also, in your code you created a datetime
, turned into strings, and then turned into strings datetime
again, and then to return a timetuple
and finally get the timestamp.
You can do the same thing just by manipulating the datetime
initial. Just use date.today()
to get today’s date and subtract a timedelta
to get the previous day. Then just use combine
to match the date with a time (using time
to set the time):
from datetime import datetime, date, time, timedelta
# dia de hoje menos 1 dia
d = date.today() - timedelta(days = 1)
# combina o dia com o horário meia-noite
startTimestamp = datetime.combine(d, time(0, 0)).timestamp()
# combina o dia com o horário 23:59
endTimestamp = datetime.combine(d, time(23, 59)).timestamp()
print(startTimestamp) # 1572231600.0
print(endTimestamp) # 1572317940.0
This way, I can change the day and time according to the given rules. In the second case, I set the time to 23, the minute to 59 and the remainder (seconds and fractions of seconds) were omitted and will be zero, because that’s what happens when you do the Parsing of the string you mounted (which does not have the seconds and fractions of a second, then they become zero in the Parsing).
Note that in this case the values of timestamps are shown with a decimal place (1572231600.0
), since they are float
's (for this is the return of method timestamp()
), since it can also have the second fractions (in this case it does not have because in both cases the value is zero). But if you want them to be whole, you can use int
in the final result: int(datetime.combine....)
.
This method is better not only by not "turning around" from converting to string and back to datetime
, but also because it does not fail when the day is 1
. By subtracting a timedelta
, the necessary adjustments are already made in the month and year (for example, if today were January 1, when subtracting 1 day, would need to adjust the month to December and the year to the previous - only subtract 1 from day does not work for all cases - see).
Also, this way it becomes clearer what is happening, and do not need to create strings to then convert back to datetime
, just use the existing types in the module to manipulate the dates directly.
Care for the Timezone
In the examples above, the startTimestamp
is 1572231600
. But remember what the timestamp: is a number representing the number of seconds since the Unix Epoch. This means that the same timestamp value corresponds to a different date and time, depending on the time zone.
For example, the timestamp 1572231600
corresponds to:
- 28/10/2019 at midnight in São Paulo
- 28/10/2019 at noon in Tokyo
- 27/10/2019 at 20:00 in Los Angeles
All 3 above dates and times correspond to the same timestamp (at the same time, at the same point in the timeline).
In this case, the datetime
's created above are "naive" (name the module gives for dates without time zone information). But to get the timestamp, we need to know what time zone it refers to (it’s the 28th to midnight where? ). Like the datetime
does not have such information, Python used the "local time" (in my case, it was the Time of Brasilia). That’s why the returned timestamp corresponds to midnight in São Paulo.
But running that same code on Ideone.com, for example, the return was 1572220800.0
, which corresponds to 10/28/2019 at midnight in UTC (which in turn corresponds to 27/10/2019 at 21h in São Paulo). This is because the Ideone environment is probably configured with UTC (the same happens if we run on the Repl.it).
That is, this code can give a different result, depending on the environment where to run. If you want to control exactly which Timezone the datetime
refers, there are some solutions.
For Python <= 3.8 you can use module pytz
, which has good timezone support:
from datetime import datetime, date, time, timedelta
from pytz import timezone
d = date.today() - timedelta(days = 1)
zone = timezone('America/Sao_Paulo')
startTimestamp = datetime.combine(d, time(0, 0)).astimezone(zone).timestamp()
endTimestamp = datetime.combine(d, time(23, 59)).astimezone(zone).timestamp()
print(startTimestamp) # 1572231600.0
print(endTimestamp) # 1572317940.0
Now I’m using a specific Timezone ("America/Sao_paulo", which corresponds to the Time of Brasilia), and the result will be correct regardless of the settings from where the code is running.
Timezone names (such as "America/Sao_paulo", "Europe/London", etc.) are standardized by IANA, and you can see all available using all_timezones
:
import pytz
print(pytz.all_timezones)
But if you’re gonna use the pytz
, remember to keep it always updated, because the information of timezones changes all the time: only in Brazil, we had a change in 2018 (daylight saving started in November instead of October), and in 2019 we will not have summer time (and this is important because whether or not you are in daylight hours changes the difference with respect to UTC, and consequently changes the value of the timestamp obtained by the codes above). And even if you’re going to use timezones from other countries, it’s just as important, because that kind of thing changes all the time.
As IANA releases new updates (which you can follow by subscribing in this mail-list), the pytz
is also updated.
And from Python 3.9 you can use module zoneinfo
. Its use is similar to pytz
:
from datetime import datetime, date, time, timedelta
from zoneinfo import ZoneInfo
d = date.today() - timedelta(days = 1)
zone = ZoneInfo('America/Sao_Paulo')
startTimestamp = datetime.combine(d, time(0, 0)).astimezone(zone).timestamp()
endTimestamp = datetime.combine(d, time(23, 59)).astimezone(zone).timestamp()
print(startTimestamp) # 1572231600.0
print(endTimestamp) # 1572317940.0
And to check all available timezones, just use zoneinfo.available_timezones()
:
import zoneinfo
print(zoneinfo.available_timezones())
Got it, I thought I had to make another import to use in the variables start and end, thank you very much !!
– Luis Henrique
@Luishenrique It is worth remembering that if the code runs on the 1st of any month, this code no longer works (because it will try to do the Zero Day Stop and will give error): https://ideone.com/HaqTAE - in my reply has an alternative to these cases :-)
– hkotsubo