1+ from datetime import datetime , timedelta
12from random import randint
2- from datetime import timedelta as td , datetime as dt ,date ,time
3-
4-
5- START_DT = date (1950 , 1 , 1 )
6- END_DT = dt .now ().date ()
7- MY_FORMAT = "%d-%m-%Y %H:%M:%S"
8-
9- def validate (start_year ,text ): # Function to validate and correct the user-supplied arguments
10- try :
11- start_year = int (start_year )
12- start_year = (1950 ,start_year ) [start_year >= 1950 ]
13- except :
14- start_year = 1950
15- global START_DT
16- START_DT = date (start_year , 1 , 1 )
17- if text not in [True ,False ]:
18- text = True
19- return start_year ,text
20-
21- def accesstime (date1 , date2 ): # Function which generates random datetime object
22- n = randint (0 , int ((date2 - date1 ).days )+ 1 )
23- date1 = date1 + td (n )
24- hour = randint (0 ,23 )
25- minute = randint (0 ,59 )
26- second = randint (0 ,59 )
27- tm = time (hour ,minute ,second )
28- return dt .combine (date1 ,tm )
29-
30- def gettime ():
31- return accesstime (START_DT ,END_DT )
32-
33-
34- def randomtimestamp (start_year = 1950 ,text = True ): # Main function that is invoked by the user
35- start_year ,text = validate (start_year ,text )
36- tst = gettime ()
37- if text == True :
38- return tst .strftime (MY_FORMAT )
39- else :
40- return tst
3+ from typing import Tuple
4+
5+ DEFAULT_FORMAT = "%d-%m-%Y %H:%M:%S"
6+
7+
8+ def validate (
9+ start_year : int ,
10+ end_year : int ,
11+ text : bool ,
12+ start : datetime ,
13+ end : datetime
14+ ) -> Tuple [datetime , datetime ]:
15+ """
16+ Validate user supplied arguments.
17+ - Check type validity.
18+ - Check value ranges.
19+
20+ Not to be imported.
21+
22+ Order of resolution:
23+ - text
24+ - start/end
25+ - start_year/end_year
26+ """
27+ start_datetime = end_datetime = None
28+
29+ if text not in {True , False }:
30+ # 'text' must be boolean
31+ error = "'text' can only be True/False"
32+ raise TypeError (error )
33+
34+ if start is not None :
35+ if isinstance (start , datetime ):
36+ # 'start' given
37+ if end is not None :
38+ if isinstance (end , datetime ):
39+ # 'end' given
40+ if start > end :
41+ # 'start' <= 'end' required
42+ # raise ValueError
43+ error = "'start' <= 'end' required"
44+ raise ValueError (error )
45+ else :
46+ # both 'start' & 'end' are valid
47+ start_datetime , end_datetime = start , end
48+ else :
49+ # 'end' is not a valid datetime object
50+ # raise TypeError
51+ error = "'end' must be an instance of datetime"
52+ raise TypeError (error )
53+ else :
54+ # 'end' not given, use now() as default
55+ start_datetime = start
56+ end_datetime = datetime .now ().replace (microsecond = 0 )
57+ if start_datetime > end_datetime :
58+ # 'start' < now() required
59+ # raise ValueError
60+ error = "'end' not given, 'start' < now() required"
61+ raise ValueError (error )
62+ else :
63+ # 'start_datetime' & 'end_datetime' are assigned
64+ # the function can return
65+ pass
66+ else :
67+ # 'start' is not a valid datetime object
68+ # raise TypeError
69+ error = "'start' must be an instance of datetime"
70+ raise TypeError (error )
71+
72+ elif start_year is not None :
73+ if isinstance (start_year , int ):
74+ # 'start_year' given
75+
76+ if not 1 <= start_year <= 9999 :
77+ # 1 <= 'start_year' <= 9999 required
78+ # raise ValueError
79+ error = "1 <= 'start_year' <= 9999 required"
80+ raise ValueError (error )
81+
82+ if end_year is not None :
83+ if isinstance (end_year , int ):
84+ # 'end_year' given
85+ if not 1 <= end_year <= 9999 :
86+ # 1 <= 'end_year' <= 9999 required
87+ # raise ValueError
88+ error = "1 <= 'end_year' <= 9999 required"
89+ raise ValueError (error )
90+
91+ if start_year > end_year :
92+ # 'start_year' <= 'end_year' required
93+ # raise ValueError
94+ error = "'start_year' <= 'end_year' required"
95+ raise ValueError (error )
96+ else :
97+ # 'start_year' & 'end_year' are valid
98+ # generate datetime for both and return
99+ start_datetime = datetime (start_year , 1 , 1 , 0 , 0 , 0 )
100+ end_datetime = datetime (end_year , 12 , 31 , 0 , 0 , 0 )
101+ else :
102+ # 'end_year' is not int
103+ # raise TypeError
104+ error = "'end_year' must be an integer."
105+ raise TypeError (error )
106+ else :
107+ # 'end_year' not given, use now().year as default
108+ # thus 'start_year' <= now().year required
109+ # otherwise raise ValueError
110+ end_datetime = datetime .now ().replace (microsecond = 0 )
111+ if start_year > end_datetime .year :
112+ # 'start_year' < now().year required
113+ # raise ValueError
114+ error = "'start_year' < now().year required"
115+ raise ValueError (error )
116+ else :
117+ # 'start_year' is valid, using for start_datetime
118+ # datetime(start_year, 1, 1, 0, 0, 0) <= range <= now()
119+ start_datetime = datetime (start_year , 1 , 1 , 0 , 0 , 0 )
120+ else :
121+ # 'start_year' is not int
122+ # raise TypeError
123+ error = "'start_year' must be an integer."
124+ raise TypeError (error )
125+ else :
126+ # Both 'start' & 'start_datetime' are None
127+ # datetime(1950, 1, 1, 0, 0, 0) <= default range <= datetime.now()
128+
129+ start_datetime = datetime (1950 , 1 , 1 , 0 , 0 , 0 )
130+ end_datetime = datetime .now ().replace (microsecond = 0 )
131+
132+ return start_datetime , end_datetime
133+
134+
135+ # Function which generates random datetime object
136+ def gettime (start_datetime : datetime , end_datetime : datetime ) -> datetime :
137+ """
138+ Core function to generate a random timestamp between two datetime objects.
139+ Should not be imported.
140+ """
141+ gap_seconds = (end_datetime - start_datetime ).total_seconds ()
142+ random_gap_seconds = randint (0 , gap_seconds )
143+ random_datetime = start_datetime + timedelta (seconds = random_gap_seconds )
144+ return random_datetime
0 commit comments