import pendulum from datetime import datetime, timedelta _format = "%Y-%m-%d %H:%M:%S" def timestamp_from_days_ago(days_ago: int): """ Returns a timestamp from a number of days ago. """ current_datetime = datetime.now() delta = timedelta(days=days_ago) past_timestamp = current_datetime - delta return int(past_timestamp.timestamp()) def create_new_date(date: datetime | None = None) -> str: """ Creates a new date and time string in the format of "YYYY-MM-DD HH:MM:SS" :return: A string of the current date and time. """ if not date: date = datetime.now() return date.strftime(_format) def timestamp_to_time_passed(timestamp: str | int | float): """ Converts a timestamp to time passed. e.g. 2 minutes ago, 1 hour ago, yesterday, 2 days ago, 2 weeks ago, etc. """ now = datetime.now().timestamp() then = datetime.fromtimestamp(int(timestamp)).timestamp() diff = now - then now = pendulum.now() return now.subtract(seconds=diff).diff_for_humans() def date_string_to_time_passed(prev_date: str) -> str: """ Converts a date string to time passed. e.g. 2 minutes ago, 1 hour ago, yesterday, 2 days ago, 2 weeks ago, etc. """ then = datetime.strptime(prev_date, _format).timestamp() return timestamp_to_time_passed(then) def seconds_to_time_string(seconds: int): """ Converts seconds to a time string. e.g. 1 hour 2 minutes, 1 hour 2 seconds, 1 hour, 1 minute 2 seconds, etc. """ hours = seconds // 3600 minutes = (seconds % 3600) // 60 remaining_seconds = seconds % 60 if hours > 0: if minutes > 0: return f"{hours} hr{'s' if hours > 1 else ''}, {minutes} min{'s' if minutes > 1 else ''}" return f"{hours} hr{'s' if hours > 1 else ''}" if minutes > 0: return f"{minutes} min{'s' if minutes > 1 else ''}" return f"{remaining_seconds} sec" def get_date_range(duration: str, units_ago: int = 0): """ Returns a tuple of dates representing the start and end of a given duration. """ date_range = None seconds_ago = 0 if duration != "alltime": seconds_ago = ( pendulum.now() - pendulum.now().subtract().start_of(duration) ).total_seconds() * units_ago match duration: case "day" | "week" | "month" | "year": date_range = ( pendulum.now() .subtract(seconds=seconds_ago) .start_of(duration) .timestamp(), pendulum.now() # .end_of(duration) .timestamp(), ) case "alltime": date_range = (0, pendulum.now().timestamp()) case _: raise ValueError(f"Invalid duration: {duration}") return (int(date_range[0]), int(date_range[1])) def get_duration_ago(duration: str, units_ago: int = 1) -> int: """ Returns the start of the last duration. """ seconds_in_day = 24 * 60 * 60 now = pendulum.now() match duration: case "day": return int( now.subtract(seconds=seconds_in_day * units_ago).timestamp() ) case "week": return int( now .subtract(seconds=seconds_in_day * 7 * units_ago) .timestamp() ) case "month": return int( now .subtract(seconds=seconds_in_day * 30 * units_ago) .timestamp() ) case "year": return int( now .subtract(seconds=seconds_in_day * 365 * units_ago) .timestamp() ) case _: raise ValueError(f"Invalid duration: {duration}") def get_duration_in_seconds(duration: str) -> int: """ Returns the number of seconds in a given duration. """ match duration: case "week" | "month" | "year": return int(pendulum.now().subtract().start_of(duration).timestamp()) case "alltime": return int(pendulum.now().timestamp()) raise ValueError(f"Invalid duration: {duration}")