Comparing datetime with minutes interval

Asked

Viewed 1,740 times

2

I need to compare 2 dates, these dates are in format %d/%m/%Y %H:%M:%S and one is obtained through the internet, and the other locally, however I am not able to compare the two with an interval of 2 minutes, in which in up to 2 minutes difference, must return true in one condition.

Code:

import time, os
import ntplib
from datetime import datetime
from pytz import timezone
client = ntplib.NTPClient()
response = client.request('pool.ntp.org')
webtime = time.strftime('%d/%m/%Y %H:%M:%S',time.localtime(response.tx_time))
print(webtime)

data_e_hora_atuais = datetime.now()
fuso_horario = timezone('America/Sao_Paulo')
data_e_hora_sao_paulo = data_e_hora_atuais.astimezone(fuso_horario)
localtime = data_e_hora_sao_paulo.strftime('%d/%m/%Y %H:%M:%S')
print(localtime)

How could I do this, with a 2 minute interval between locally obtained and web dates?

  • You want it to return true if the difference between a "datetime" and another is less than or equal to 2 minutes, correct?

  • Yes @Gustavosampaio

  • Is it necessary to compare only with dates of the human way (day, month, year etc)? It seems much simpler to work with only in seconds.

  • It is not necessary to compare the given in the human way, as long as they are compared all right.

  • @Giovanninunes In fact, in this case it seems easier to work with values in seconds than to create dates. Anyway, I left the 2 options below...

2 answers

2


Date format

To generate the variables webtime and localtime, you are using respectively time.strftime and datetime.strftime, which are 2 methods that return strings, and not dates.

Dates and times have no format. A date is simply a value (actually a set of values: day, month and year) that represents a specific point in the calendar, and a time is another set of values (time, minute, second, fractions of a second) that represents a specific moment of a day.

These values can be represented in many different ways. For example, the date of "1 February 2018" has 3 values: day 1, month 2 and year 2018. But this same date can be represented in several different ways:

  • 01/02/2018 - common format in several countries
  • 1 February 2018 - in good Portuguese
  • 2018-02-01 - format ISO 8601
  • Feb 1st, 2018 - common format in the USA
  • 2018 年 2 月 1 日 - in japanese

Although all these formats (all these strings) are different, they all represent the same date.

So, if you want to calculate the difference between two dates, don’t turn them into strings (only do this if you want to show the date in a specific format). To do calculations and other manipulations with the dates, use them directly - and in your case, as you are already using the module datetime, use the types it offers.


Difference between dates

To calculate the difference between the dates, we first need to get them as a datetime.

I see you’re wearing time.localtime. This method receives a timestamp in seconds (the number of seconds since the Unix Epoch) and converts to the "local" date and time (ie the corresponding day and time on the machine Timezone where the code is running).

But then you get the current date on a specific Timezone (America/Sao_Paulo), then I suggest that both dates are in the same Timezone so that we can compare them.

Using datetime, you can convert the timestamp to a date and time in a specific Timezone, using datetime.fromtimestamp (passing the timestamp and Timezone), and can get the current date/time on the same Timezone, using datetime.now and passing Timezone as parameter. Then you can subtract the datetimes directly, obtaining a timedelta:

from datetime import datetime
from pytz import timezone

fuso_horario = timezone('America/Sao_Paulo')

# usando o timestamp e o fuso horário
webdate = datetime.fromtimestamp(response.tx_time, tz=fuso_horario)

# data/hora atual no mesmo timezone usado acima
agora = datetime.now(tz=fuso_horario)

# diferença é um timedelta
diferenca = agora - webdate

# diferença maior ou igual a 2 minutos
if diferenca.total_seconds() >= 120:
    print("diferença maior ou igual a 2 minutos")

In the documentation says that if one date has Timezone and another does not, the calculation of the difference between them launches a TypeError. So I created both with a Timezone.


Note: from Python 3.9 you can use module zoneinfo, the operation of which is very similar to pytz:

from datetime import datetime
from zoneinfo import ZoneInfo

fuso_horario = ZoneInfo('America/Sao_Paulo')

# usando o timestamp e o fuso horário
webdate = datetime.fromtimestamp(response.tx_time, tz=fuso_horario)
# data/hora atual no mesmo timezone usado acima
agora = datetime.now(tz=fuso_horario)

# diferença é um timedelta
diferenca = agora - webdate

# diferença maior ou igual a 2 minutos
if diferenca.total_seconds() >= 120:
    print("diferença maior ou igual a 2 minutos")

Simplifying

Although, in your case, as you receive from the web the value of timestamp in seconds, just get the value of the current timestamp (also in seconds) using time.time() and subtract from each other:

import time

# diferença, em segundos, entre o instante atual e o recebido da web
diferenca = time.time() - response.tx_time
if diferenca >= 120:
    print("diferença maior ou igual a 2 minutos")

Timestamp is a "universal" value (it is the same all over the world, all computers that run time.time() at the same time they will have the same result). So I don’t even need to convert it to a date and time in a specific Timezone, since we just want to know the difference between them.

Create datetimes in a specific Timezone will be useful if you need to manipulate the dates afterwards (or show them on the screen, for example using strftime). Otherwise, for this specific case, it seems simpler to use only timestamps.


It was unclear if you want to know if the value of the web is in the past or future compared to the current date. If it does, you can get the absolute value of the difference (without the signal) using abs:

diferenca = abs(time.time() - response.tx_time)

Or, if using the above solution with timedelta, do if abs(diferenca.total_seconds()) >= 120.

If you only want to know if the web date is in the future (2 minutes after the current date), just flip and do response.tx_time - time.time() (and see if it is greater than or equal to 120).

2

If you just want to compare two dates with a certain time tolerance between them the best alternative is to work with them in seconds and not with human format with day, month, year, hour, minute etc.

from __future__ import print_function
import time

from ntplib import NTPClient


TIME_GAP = 2 * 60 * 1000  # 2 minutos * 60


def get_internet_time(server="pool.ntp.org"):
    """ retorna a hora, via NTP, em segundos. """
    client = NTPClient()
    response = client.request(server)
    return response.tx_time


def check_times(first_time, second_time, gap=TIME_GAP):
    """ verifica datas em `first_time` e `second_time` aplicando uma
    tolerância de tempo `gap` entre elas. """
    return (first_time // gap) == (second_time // gap)


def main():
    """ função principal """
    internet_time = get_internet_time()
    local_time = time.time()
    wrong_time = local_time + TIME_GAP * 2

    print(internet_time, local_time, wrong_time)
    print(check_times(internet_time, local_time))
    print(check_times(internet_time, wrong_time))


if __name__ == "__main__":
    main()

I separated in functions to be simpler to understand but the whole idea is to divide the values of the two dates in seconds by the desired tolerance (the variable TIME_GAP in this case). If in the band the dates can be considered equal:

1544888407.6483665 1544888407.783229 1545128407.783229
True
False

In the variable example code wrong_time is artificially inflated to show the difference. :)

(note, in the original version I made confusion between seconds and milliseconds, but the above version is already corrected).

  • I know it’s not in the question, but in case I wanted to check with 15 days interval, between a date and another, returned True if you were within these 15 days, how would I do? I tried using os.path.getctime("project.exe") however did not result in the expected, always returning True. I used TIME_GAP_DAYS = 1000 * 60 * 60 * 24 * 15 getting print(check_times(local_time, os.path.getctime("project.exe"), gap=TIME_GAP_DAYS)) I’d appreciate it if you could clear that doubt.

  • I was also curious but after thinking a little I realized that what I wrote already answered, you have to take the 1000 because if you are working with seconds and not milliseconds (just put the audio of Chaves saying "stupid, give zero to him!" here).

  • By the way, I found an even more elegant solution to check dates, the timehash -- https://github.com/abeusher/timehash

Browser other questions tagged

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