Capture time range in UNIX

Asked

Viewed 120 times

2

I am trying to capture in UNIX data format the 1 day time range:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import datetime
from datetime import datetime

now = datetime.now()

dateNow = '' + str(now.day - 1) + '/' + str(now.month) + '/' \
    + str(now.year) + ''

start = '' + dateNow + ' 00:00'
end = '' + dateNow + ' 23:59'

print(start)

startTimestamp = int(time.mktime(datetime.datetime.strptime(start,
                     '%d/%m/%Y %H:%M').timetuple()))

endTimestamp = int(time.mktime(datetime.datetime.strptime(end,
                   '%d/%m/%Y %H:%M').timetuple()))

print(startTimestamp)

Exit:

28/10/2019 00:00
Traceback (most recent call last):
  File "main.py", line 17, in <module>    startTimestamp = int(time.mktime(datetime.datetime.strptime(start,AttributeError: type object 'datetime.datetime' has no attribute 'datetime'

2 answers

1


Luis, you did the import of datetime twice, even generating the Warning redefinition.

One way to fix it would just be to remove the first import of datetime, and also correct lines using the method strptime:

import time
from datetime import datetime

now = datetime.now()

dateNow = '' + str(now.day - 1) + '/' + str(now.month) + '/' \
    + str(now.year) + ''

start = '' + dateNow + ' 00:00'
end = '' + dateNow + ' 23:59'

print(start)

startTimestamp = int(time.mktime(datetime.strptime(start,
                     '%d/%m/%Y %H:%M').timetuple()))

endTimestamp = int(time.mktime(datetime.strptime(end,
                   '%d/%m/%Y %H:%M').timetuple()))

print(startTimestamp)
  • Got it, I thought I had to make another import to use in the variables start and end, thank you very much !!

  • 1

    @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 :-)

1

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())
  • 1

    Man, simply fantastic your answer, your programming logic is very good, turned the monster I wrote into few lines, congratulations and thanks for explaining in detail !!

  • Just a question, if I wanted to turn this into a 7-day time range, what would the variables look like ? would have to do ( start - 60 * 60 * 7) ?

  • 1

    @Luishenrique If you want to subtract 7 days, do it date.today() - timedelta(days = 7). The timedelta It’s just so you don’t have to do these math

  • But he will capture in a period of 7 days or 7 days ago ?

  • 1

    This code above subtracts, so the result is a date 7 days ago.

  • I understood, in case my doubt was what I would look like to get in a period of 7 days, I think I expressed myself badly, sorry!

  • 1

    If this is the case, just ask another question... But depending on what you need, you may already have on the site, do a search before :)

  • Okay, mtt thank you!!

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.