2023-05-15 17:55:54 +00:00
|
|
|
import re
|
2023-05-14 07:28:59 +00:00
|
|
|
from datetime import datetime, timezone
|
2023-05-14 08:45:07 +00:00
|
|
|
from typing import Optional
|
2023-05-14 07:28:59 +00:00
|
|
|
|
2023-05-18 05:07:22 +00:00
|
|
|
import arrow
|
|
|
|
|
2023-09-04 04:57:11 +00:00
|
|
|
from freqtrade.constants import DATETIME_PRINT_FORMAT
|
|
|
|
|
2023-05-14 07:28:59 +00:00
|
|
|
|
|
|
|
def dt_now() -> datetime:
|
|
|
|
"""Return the current datetime in UTC."""
|
|
|
|
return datetime.now(timezone.utc)
|
|
|
|
|
|
|
|
|
2023-05-14 15:36:53 +00:00
|
|
|
def dt_utc(year: int, month: int, day: int, hour: int = 0, minute: int = 0, second: int = 0,
|
|
|
|
microsecond: int = 0) -> datetime:
|
|
|
|
"""Return a datetime in UTC."""
|
|
|
|
return datetime(year, month, day, hour, minute, second, microsecond, tzinfo=timezone.utc)
|
|
|
|
|
|
|
|
|
2023-05-14 08:45:07 +00:00
|
|
|
def dt_ts(dt: Optional[datetime] = None) -> int:
|
2023-05-14 09:02:11 +00:00
|
|
|
"""
|
|
|
|
Return dt in ms as a timestamp in UTC.
|
|
|
|
If dt is None, return the current datetime in UTC.
|
|
|
|
"""
|
2023-05-14 08:45:07 +00:00
|
|
|
if dt:
|
|
|
|
return int(dt.timestamp() * 1000)
|
2023-05-14 08:43:06 +00:00
|
|
|
return int(dt_now().timestamp() * 1000)
|
|
|
|
|
|
|
|
|
2023-09-04 05:08:23 +00:00
|
|
|
def dt_ts_def(dt: Optional[datetime], default: int = 0) -> int:
|
|
|
|
"""
|
|
|
|
Return dt in ms as a timestamp in UTC.
|
2024-02-15 18:50:56 +00:00
|
|
|
If dt is None, return the given default.
|
2023-09-04 05:08:23 +00:00
|
|
|
"""
|
|
|
|
if dt:
|
|
|
|
return int(dt.timestamp() * 1000)
|
|
|
|
return default
|
|
|
|
|
2024-02-15 19:45:16 +00:00
|
|
|
|
2024-02-15 18:50:56 +00:00
|
|
|
def dt_ts_none(dt: Optional[datetime]) -> Optional[int]:
|
|
|
|
"""
|
|
|
|
Return dt in ms as a timestamp in UTC.
|
|
|
|
If dt is None, return the given default.
|
|
|
|
"""
|
|
|
|
if dt:
|
|
|
|
return int(dt.timestamp() * 1000)
|
|
|
|
return None
|
|
|
|
|
2023-09-04 05:08:23 +00:00
|
|
|
|
2023-05-14 09:02:11 +00:00
|
|
|
def dt_floor_day(dt: datetime) -> datetime:
|
|
|
|
"""Return the floor of the day for the given datetime."""
|
|
|
|
return dt.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
|
|
|
|
|
|
2023-05-14 07:28:59 +00:00
|
|
|
def dt_from_ts(timestamp: float) -> datetime:
|
|
|
|
"""
|
|
|
|
Return a datetime from a timestamp.
|
|
|
|
:param timestamp: timestamp in seconds or milliseconds
|
|
|
|
"""
|
|
|
|
if timestamp > 1e10:
|
|
|
|
# Timezone in ms - convert to seconds
|
|
|
|
timestamp /= 1000
|
|
|
|
return datetime.fromtimestamp(timestamp, tz=timezone.utc)
|
2023-05-15 17:55:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
def shorten_date(_date: str) -> str:
|
|
|
|
"""
|
|
|
|
Trim the date so it fits on small screens
|
|
|
|
"""
|
|
|
|
new_date = re.sub('seconds?', 'sec', _date)
|
|
|
|
new_date = re.sub('minutes?', 'min', new_date)
|
|
|
|
new_date = re.sub('hours?', 'h', new_date)
|
|
|
|
new_date = re.sub('days?', 'd', new_date)
|
|
|
|
new_date = re.sub('^an?', '1', new_date)
|
|
|
|
return new_date
|
2023-05-18 05:07:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
def dt_humanize(dt: datetime, **kwargs) -> str:
|
|
|
|
"""
|
|
|
|
Return a humanized string for the given datetime.
|
|
|
|
:param dt: datetime to humanize
|
|
|
|
:param kwargs: kwargs to pass to arrow's humanize()
|
|
|
|
"""
|
|
|
|
return arrow.get(dt).humanize(**kwargs)
|
2023-07-06 18:27:49 +00:00
|
|
|
|
|
|
|
|
2023-09-04 04:57:11 +00:00
|
|
|
def format_date(date: Optional[datetime]) -> str:
|
|
|
|
"""
|
|
|
|
Return a formatted date string.
|
|
|
|
Returns an empty string if date is None.
|
|
|
|
:param date: datetime to format
|
|
|
|
"""
|
|
|
|
if date:
|
|
|
|
return date.strftime(DATETIME_PRINT_FORMAT)
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
2023-07-06 18:27:49 +00:00
|
|
|
def format_ms_time(date: int) -> str:
|
|
|
|
"""
|
|
|
|
convert MS date to readable format.
|
|
|
|
: epoch-string in ms
|
|
|
|
"""
|
|
|
|
return datetime.fromtimestamp(date / 1000.0).strftime('%Y-%m-%dT%H:%M:%S')
|