Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Error: The given time 'in 30 seconds' is in the past." despite time given being in the future. #100

Open
th0mcat opened this issue Nov 16, 2022 · 4 comments
Labels
bug Something isn't working

Comments

@th0mcat
Copy link
Contributor

th0mcat commented Nov 16, 2022

I'm getting the "Error: The given time 'in 30 seconds' is in the past." from the bot if the time frame requested is between 0 and 8 minutes 59 seconds. At 9 minutes (or 540 seconds), the bot seems to work just fine.

image

Made sure my server's time was correct, tried again, still no success.

sudo ntpdate -q 0.de.pool.ntp.org
server 217.144.135.10, stratum 3, offset 0.011434, delay 0.13306
server 135.181.32.222, stratum 2, offset 0.008365, delay 0.14697
server 80.151.186.5, stratum 2, offset 0.014610, delay 0.15591
server 141.98.136.83, stratum 3, offset 0.023213, delay 0.13100
16 Nov 07:57:08 ntpdate[76979]: adjust time server 135.181.32.222 offset 0.008365 sec
@spantaleev
Copy link

Seems like it's a problem with time determination.

I believe the current _get_datetime_now is faulty.. It's weird to work with timezones using offsets. It may not be what's causing the problem right now, but.. you should ask your date/time library "what is the time now in this specific timezone", instead of trying to determine an offset in seconds and trying to use that.

I thought that a way to simplify _get_datetime_now is to use something like this:

def _get_datetime_now(self, tz: str) -> datetime:
    """Returns a timezone-aware datetime object of the current time"""
    now = dateparser.parse('now', settings={"PREFER_DATES_FROM": "future", "TIMEZONE": tz, "RETURN_AS_TIMEZONE_AWARE": True})

    # Round to the nearest second for nicer display
    return now.replace(microsecond=0)

There may be a smarter way which doesn't rely on datepraser.parse, but.. using this means it's consistent with the other part of this script (which actually uses dateparser.parse). Doing things the same way ensures we're comparing apples to apples.

RETURN_AS_TIMEZONE_AWARE is potentially False in the other place.

For the server that I saw to exhibit "date is in the past" errors (TZ=Europe/Stockholm, running in a container) this patch didn't really help.. So I suppose there's more to it. I haven't had time to investigate more yet, but just wanted to post the progress here.

@HarHarLinks HarHarLinks added the bug Something isn't working label Dec 30, 2023
@HarHarLinks
Copy link
Collaborator

This might also have been #127 - the pytz time zone library defaults to local mean time, which is "sun-based" instead of "clock-based". perhaps you can check if you're on the other end of the wave as #127 and #145 fixes your issue as well?

@gabrc52
Copy link

gabrc52 commented Feb 14, 2024

Can reproduce even with more time such as 2 minutes.

Using the following distilled version of the code to debug:

Click to see Python code
from datetime import datetime, timedelta, timezone
import pytz
import dateparser

TIMEZONE = "America/New_York"

def _get_datetime_now(tz: str) -> datetime:
    """Returns a timezone-aware datetime object of the current time"""
    # Get a datetime with no timezone information
    no_timezone_datetime = datetime(2009, 9, 1)

    # Create a datetime.timezone object with the correct offset from UTC
    offset = timezone(pytz.timezone(tz).utcoffset(no_timezone_datetime))

    # Get datetime.now with that offset
    now = datetime.now(offset)

    # Round to the nearest second for nicer display
    return now.replace(microsecond=0)


def _parse_str_to_time(time_str: str, tz_aware: bool = True) -> datetime:
    """Converts a human-readable, future time string to a datetime object

    Args:
        time_str: The time to convert
        tz_aware: Whether the returned datetime should have associated timezone
            information

    Returns:
        datetime: A datetime if conversion was successful

    Raises:
        CommandError: if conversion was not successful, or time is in the past.
    """
    time = dateparser.parse(
        time_str,
        settings={
            "PREFER_DATES_FROM": "future",
            "TIMEZONE": TIMEZONE,
            "RETURN_AS_TIMEZONE_AWARE": tz_aware,
        },
    )
    print(f'{time=}')
    if not time:
        raise Exception(f"The given time '{time_str}' is invalid.")

    # Disallow times in the past
    tzinfo = pytz.timezone(TIMEZONE)
    now =_get_datetime_now(TIMEZONE)
    
    print(f'{now=}')

    if time.replace(tzinfo=tzinfo) < now:
        raise Exception(f"The given time '{time_str}' is in the past.")

    # Round datetime object to the nearest second for nicer display
    time = time.replace(microsecond=0)

    return time


if __name__ == "__main__":
    _parse_str_to_time("in 5 min")
(venv) rgabriel@thinkpad:~/Projects/uplink/matrix-reminder-bot$ date
Tue Feb 13 11:15:36 PM EST 2024
(venv) rgabriel@thinkpad:~/Projects/uplink/matrix-reminder-bot$ python parse_test.py
time=datetime.datetime(2024, 2, 13, 23, 20, 37, 717068, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
now=datetime.datetime(2024, 2, 14, 0, 15, 37, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))

@HarHarLinks
Copy link
Collaborator

@gabrc52 could you check if you can still repro with the update from #145 and #147 ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants