@@ -26,35 +26,22 @@ def datetime_to_timestamp(dt: Union[dtdate, datetime]) -> int:
26
26
return timegm (dt .timetuple ())
27
27
28
28
29
+ def convert_timestamp_to_datetime (timestamp : Union [int , float ], tzinfo : TzInfo ) -> datetime :
30
+ import datetime as dt
31
+
32
+ if timestamp >= 0 :
33
+ return dt .datetime .fromtimestamp (timestamp , tzinfo )
34
+ else :
35
+ return dt .datetime (1970 , 1 , 1 , tzinfo = tzinfo ) + dt .timedelta (seconds = int (timestamp ))
36
+
37
+
29
38
def timestamp_to_datetime (timestamp : Union [int , float ], tzinfo : Optional [TzInfo ]) -> datetime :
30
39
if tzinfo is None :
31
40
pick = convert_timestamp_to_datetime (timestamp , tzlocal ())
32
41
return pick .astimezone (tzutc ()).replace (tzinfo = None )
33
42
return convert_timestamp_to_datetime (timestamp , tzinfo )
34
43
35
44
36
- def get_now_date_time (
37
- start_date : Optional [DateParseType ], end_date : Optional [DateParseType ], tzinfo : Optional [TzInfo ]
38
- ) -> datetime :
39
- if isinstance (start_date , datetime ) and not isinstance (end_date , datetime ):
40
- now = start_date
41
- elif isinstance (end_date , datetime ) and not isinstance (start_date , datetime ):
42
- now = end_date
43
- else :
44
- now = datetime .now (tzinfo )
45
- return now
46
-
47
-
48
- def get_now_date (start_date : Optional [DateParseType ], end_date : Optional [DateParseType ]) -> dtdate :
49
- if isinstance (start_date , dtdate ) and not isinstance (end_date , dtdate ):
50
- now = start_date
51
- elif isinstance (end_date , dtdate ) and not isinstance (start_date , dtdate ):
52
- now = end_date
53
- else :
54
- now = dtdate .today ()
55
- return now
56
-
57
-
58
45
def change_year (current_date : dtdate , year_diff : int ) -> dtdate :
59
46
"""
60
47
Unless the current_date is February 29th, it is fine to just subtract years.
@@ -1839,6 +1826,132 @@ def _rand_seconds(self, start_datetime: int, end_datetime: int) -> float:
1839
1826
1840
1827
regex = re .compile (timedelta_pattern )
1841
1828
1829
+ @classmethod
1830
+ def _is_absolute (cls , obj : Optional [DateParseType ]) -> bool :
1831
+ if obj is None :
1832
+ return False
1833
+ if isinstance (obj , (datetime , dtdate , int )):
1834
+ return True
1835
+ elif isinstance (obj , timedelta ):
1836
+ return False
1837
+ elif isinstance (obj , str ):
1838
+ if obj in ("today" , "now" ):
1839
+ return False
1840
+ return cls .regex .fullmatch (obj ) is None
1841
+ return False
1842
+
1843
+ @classmethod
1844
+ def _get_reference_date_time (
1845
+ cls , start_date : Optional [DateParseType ], end_date : Optional [DateParseType ], tzinfo : Optional [TzInfo ]
1846
+ ) -> datetime :
1847
+ """
1848
+ Return Which datetime is absolute, or now if both are relative.
1849
+ If both are absolute, return the most recent one.
1850
+ If both are None, return now.
1851
+ """
1852
+ min_ = datetime_to_timestamp (datetime .min )
1853
+ now = datetime .now (tzinfo )
1854
+ if start_date is None and end_date is None :
1855
+ return now
1856
+
1857
+ start_int = cls ._parse_date_time (start_date , now ) if start_date is not None else min_
1858
+ end_int = cls ._parse_date_time (end_date , now ) if end_date is not None else min_
1859
+ if not cls ._is_absolute (start_date ) and not cls ._is_absolute (end_date ):
1860
+ return now
1861
+ if cls ._is_absolute (start_date ) and cls ._is_absolute (end_date ):
1862
+ reference = max ([start_int , end_int ])
1863
+ elif cls ._is_absolute (start_date ) and not cls ._is_absolute (end_date ):
1864
+ reference = start_int
1865
+ elif cls ._is_absolute (end_date ) and not cls ._is_absolute (start_date ):
1866
+ reference = end_int
1867
+ return timestamp_to_datetime (reference , tzinfo )
1868
+
1869
+ @classmethod
1870
+ def _get_reference_date (cls , start_date : Optional [DateParseType ], end_date : Optional [DateParseType ]) -> dtdate :
1871
+ reference = cls ._get_reference_date_time (start_date , end_date , None )
1872
+ return reference .date ()
1873
+
1874
+ @classmethod
1875
+ def _parse_start_datetime (cls , now : datetime , value : Optional [DateParseType ]) -> int :
1876
+ if value is None :
1877
+ return 0
1878
+
1879
+ return cls ._parse_date_time (value , now )
1880
+
1881
+ @classmethod
1882
+ def _parse_end_datetime (cls , now : datetime , value : Optional [DateParseType ]) -> int :
1883
+ if value is None :
1884
+ return datetime_to_timestamp (now )
1885
+
1886
+ return cls ._parse_date_time (value , now )
1887
+
1888
+ @classmethod
1889
+ def _parse_date_string (cls , value : str ) -> Dict [str , float ]:
1890
+ parts = cls .regex .match (value )
1891
+ if not parts :
1892
+ raise ParseError (f"Can't parse date string `{ value } `" )
1893
+ parts = parts .groupdict ()
1894
+ time_params : Dict [str , float ] = {}
1895
+ for name_ , param_ in parts .items ():
1896
+ if param_ :
1897
+ time_params [name_ ] = int (param_ )
1898
+
1899
+ if "years" in time_params :
1900
+ if "days" not in time_params :
1901
+ time_params ["days" ] = 0
1902
+ time_params ["days" ] += 365.24 * time_params .pop ("years" )
1903
+ if "months" in time_params :
1904
+ if "days" not in time_params :
1905
+ time_params ["days" ] = 0
1906
+ time_params ["days" ] += 30.42 * time_params .pop ("months" )
1907
+
1908
+ if not time_params :
1909
+ raise ParseError (f"Can't parse date string `{ value } `" )
1910
+ return time_params
1911
+
1912
+ @classmethod
1913
+ def _parse_timedelta (cls , value : Union [timedelta , str , float ]) -> Union [float , int ]:
1914
+ if isinstance (value , timedelta ):
1915
+ return value .total_seconds ()
1916
+ if isinstance (value , str ):
1917
+ time_params = cls ._parse_date_string (value )
1918
+ return timedelta (** time_params ).total_seconds () # type: ignore
1919
+ if isinstance (value , (int , float )):
1920
+ return value
1921
+ raise ParseError (f"Invalid format for timedelta { value !r} " )
1922
+
1923
+ @classmethod
1924
+ def _parse_date_time (cls , value : DateParseType , now : datetime , tzinfo : Optional [TzInfo ] = None ) -> int :
1925
+ if isinstance (value , (datetime , dtdate )):
1926
+ return datetime_to_timestamp (value )
1927
+ if isinstance (value , timedelta ):
1928
+ return datetime_to_timestamp (now + value )
1929
+ if isinstance (value , str ):
1930
+ if value == "now" :
1931
+ return datetime_to_timestamp (datetime .now (tzinfo ))
1932
+ time_params = cls ._parse_date_string (value )
1933
+ return datetime_to_timestamp (now + timedelta (** time_params )) # type: ignore
1934
+ if isinstance (value , int ):
1935
+ return value
1936
+ raise ParseError (f"Invalid format for date { value !r} " )
1937
+
1938
+ @classmethod
1939
+ def _parse_date (cls , value : DateParseType , today : dtdate ) -> dtdate :
1940
+ if isinstance (value , datetime ):
1941
+ return value .date ()
1942
+ elif isinstance (value , dtdate ):
1943
+ return value
1944
+ if isinstance (value , timedelta ):
1945
+ return today + value
1946
+ if isinstance (value , str ):
1947
+ if value in ("today" , "now" ):
1948
+ return today
1949
+ time_params = cls ._parse_date_string (value )
1950
+ return today + timedelta (** time_params ) # type: ignore
1951
+ if isinstance (value , int ):
1952
+ return today + timedelta (value )
1953
+ raise ParseError (f"Invalid format for date { value !r} " )
1954
+
1842
1955
def unix_time (
1843
1956
self ,
1844
1957
end_datetime : Optional [DateParseType ] = None ,
@@ -1852,7 +1965,7 @@ def unix_time(
1852
1965
1853
1966
:example: 1061306726.6
1854
1967
"""
1855
- now = get_now_date_time (start_datetime , end_datetime , tzinfo = None )
1968
+ now = self . _get_reference_date_time (start_datetime , end_datetime , tzinfo = None )
1856
1969
start_datetime = self ._parse_start_datetime (now , start_datetime )
1857
1970
end_datetime = self ._parse_end_datetime (now , end_datetime )
1858
1971
return float (self ._rand_seconds (start_datetime , end_datetime ))
@@ -1905,7 +2018,7 @@ def date_time_ad(
1905
2018
# simply change that class method to use this magic number as a
1906
2019
# default value when None is provided.
1907
2020
1908
- now = get_now_date_time (start_datetime , end_datetime , tzinfo )
2021
+ now = self . _get_reference_date_time (start_datetime , end_datetime , tzinfo )
1909
2022
start_time = - 62135596800 if start_datetime is None else self ._parse_start_datetime (now , start_datetime )
1910
2023
end_datetime = self ._parse_end_datetime (now , end_datetime )
1911
2024
@@ -1971,87 +2084,6 @@ def time_object(self, end_datetime: Optional[DateParseType] = None) -> dttime:
1971
2084
"""
1972
2085
return self .date_time (end_datetime = end_datetime ).time ()
1973
2086
1974
- @classmethod
1975
- def _parse_start_datetime (cls , now : datetime , value : Optional [DateParseType ]) -> int :
1976
- if value is None :
1977
- return 0
1978
-
1979
- return cls ._parse_date_time (value , now )
1980
-
1981
- @classmethod
1982
- def _parse_end_datetime (cls , now : datetime , value : Optional [DateParseType ]) -> int :
1983
- if value is None :
1984
- return datetime_to_timestamp (now )
1985
-
1986
- return cls ._parse_date_time (value , now )
1987
-
1988
- @classmethod
1989
- def _parse_date_string (cls , value : str ) -> Dict [str , float ]:
1990
- parts = cls .regex .match (value )
1991
- if not parts :
1992
- raise ParseError (f"Can't parse date string `{ value } `" )
1993
- parts = parts .groupdict ()
1994
- time_params : Dict [str , float ] = {}
1995
- for name_ , param_ in parts .items ():
1996
- if param_ :
1997
- time_params [name_ ] = int (param_ )
1998
-
1999
- if "years" in time_params :
2000
- if "days" not in time_params :
2001
- time_params ["days" ] = 0
2002
- time_params ["days" ] += 365.24 * time_params .pop ("years" )
2003
- if "months" in time_params :
2004
- if "days" not in time_params :
2005
- time_params ["days" ] = 0
2006
- time_params ["days" ] += 30.42 * time_params .pop ("months" )
2007
-
2008
- if not time_params :
2009
- raise ParseError (f"Can't parse date string `{ value } `" )
2010
- return time_params
2011
-
2012
- @classmethod
2013
- def _parse_timedelta (cls , value : Union [timedelta , str , float ]) -> Union [float , int ]:
2014
- if isinstance (value , timedelta ):
2015
- return value .total_seconds ()
2016
- if isinstance (value , str ):
2017
- time_params = cls ._parse_date_string (value )
2018
- return timedelta (** time_params ).total_seconds () # type: ignore
2019
- if isinstance (value , (int , float )):
2020
- return value
2021
- raise ParseError (f"Invalid format for timedelta { value !r} " )
2022
-
2023
- @classmethod
2024
- def _parse_date_time (cls , value : DateParseType , now : datetime , tzinfo : Optional [TzInfo ] = None ) -> int :
2025
- if isinstance (value , (datetime , dtdate )):
2026
- return datetime_to_timestamp (value )
2027
- if isinstance (value , timedelta ):
2028
- return datetime_to_timestamp (now + value )
2029
- if isinstance (value , str ):
2030
- if value == "now" :
2031
- return datetime_to_timestamp (datetime .now (tzinfo ))
2032
- time_params = cls ._parse_date_string (value )
2033
- return datetime_to_timestamp (now + timedelta (** time_params )) # type: ignore
2034
- if isinstance (value , int ):
2035
- return value
2036
- raise ParseError (f"Invalid format for date { value !r} " )
2037
-
2038
- @classmethod
2039
- def _parse_date (cls , value : DateParseType , today : dtdate ) -> dtdate :
2040
- if isinstance (value , datetime ):
2041
- return value .date ()
2042
- elif isinstance (value , dtdate ):
2043
- return value
2044
- if isinstance (value , timedelta ):
2045
- return today + value
2046
- if isinstance (value , str ):
2047
- if value in ("today" , "now" ):
2048
- return today
2049
- time_params = cls ._parse_date_string (value )
2050
- return today + timedelta (** time_params ) # type: ignore
2051
- if isinstance (value , int ):
2052
- return today + timedelta (value )
2053
- raise ParseError (f"Invalid format for date { value !r} " )
2054
-
2055
2087
def date_time_between (
2056
2088
self ,
2057
2089
start_date : DateParseType = "-30y" ,
@@ -2068,7 +2100,10 @@ def date_time_between(
2068
2100
:example: datetime('1999-02-02 11:42:52')
2069
2101
:return: datetime
2070
2102
"""
2071
- now = get_now_date_time (start_date , end_date , tzinfo )
2103
+ if end_date is None :
2104
+ end_date = "now"
2105
+
2106
+ now = self ._get_reference_date_time (start_date , end_date , tzinfo )
2072
2107
start_date = self ._parse_date_time (start_date , now , tzinfo = tzinfo )
2073
2108
end_date = self ._parse_date_time (end_date , now , tzinfo = tzinfo )
2074
2109
if end_date - start_date <= 1 :
@@ -2090,7 +2125,10 @@ def date_between(self, start_date: DateParseType = "-30y", end_date: DateParseTy
2090
2125
:example: Date('1999-02-02')
2091
2126
:return: Date
2092
2127
"""
2093
- today = get_now_date (start_date , end_date )
2128
+
2129
+ if end_date is None :
2130
+ end_date = "now"
2131
+ today = self ._get_reference_date (start_date , end_date )
2094
2132
start_date = self ._parse_date (start_date , today )
2095
2133
end_date = self ._parse_date (end_date , today )
2096
2134
return self .date_between_dates (date_start = start_date , date_end = end_date )
@@ -2164,7 +2202,7 @@ def date_time_between_dates(
2164
2202
:example: datetime('1999-02-02 11:42:52')
2165
2203
:return: datetime
2166
2204
"""
2167
- today = get_now_date (datetime_start , datetime_end )
2205
+ today = self . _get_reference_date (datetime_start , datetime_end )
2168
2206
now = datetime .combine (today , datetime .min .time (), tzinfo )
2169
2207
datetime_start_ = (
2170
2208
datetime_to_timestamp (datetime .now (tzinfo ))
@@ -2425,7 +2463,9 @@ def time_series(
2425
2463
``distrib`` is a callable that accepts ``<datetime>`` and returns ``<value>``
2426
2464
2427
2465
"""
2428
- now = get_now_date_time (start_date , end_date , tzinfo )
2466
+ if end_date is None :
2467
+ end_date = "now"
2468
+ now = self ._get_reference_date_time (start_date , end_date , tzinfo )
2429
2469
start_date_ = self ._parse_date_time (start_date , now , tzinfo = tzinfo )
2430
2470
end_date_ = self ._parse_date_time (end_date , now , tzinfo = tzinfo )
2431
2471
@@ -2530,12 +2570,3 @@ def date_of_birth(
2530
2570
dob = self .date_time_ad (tzinfo = tzinfo , start_datetime = start_date , end_datetime = end_date ).date ()
2531
2571
2532
2572
return dob if dob != start_date else dob + timedelta (days = 1 )
2533
-
2534
-
2535
- def convert_timestamp_to_datetime (timestamp : Union [int , float ], tzinfo : TzInfo ) -> datetime :
2536
- import datetime as dt
2537
-
2538
- if timestamp >= 0 :
2539
- return dt .datetime .fromtimestamp (timestamp , tzinfo )
2540
- else :
2541
- return dt .datetime (1970 , 1 , 1 , tzinfo = tzinfo ) + dt .timedelta (seconds = int (timestamp ))
0 commit comments