Skip to content

Commit ef53c5d

Browse files
committed
feature: support year/datetime range for timestamp
1 parent 3018cca commit ef53c5d

5 files changed

Lines changed: 206 additions & 48 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ __pycache__/
44

55
dist/
66
build/
7-
*.egg-info/
7+
*.egg-info/
8+
9+
.vscode/

randomtimestamp/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Python module to generate random time stamps.
2+
Python module to generate random timestamps.
33
"""
44

55
__title__ = 'randomtimestamp'
@@ -8,8 +8,6 @@
88
__license__ = 'GPL v3.0'
99

1010

11-
from .core import randomtimestamp
11+
from .functions import randomtimestamp
1212

13-
__all__ = [
14-
'randomtimestamp'
15-
]
13+
__all__ = ['randomtimestamp']

randomtimestamp/__main__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
from .core import randomtimestamp
1+
from .functions import randomtimestamp
22

33

44
def main():
5-
print(randomtimestamp(1950,True))
5+
print(randomtimestamp(1950, True))
66

77

88
if __name__ == "__main__":
9-
main()
9+
main()

randomtimestamp/core.py

Lines changed: 143 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,144 @@
1+
from datetime import datetime, timedelta
12
from 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

randomtimestamp/functions.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from datetime import datetime
2+
from typing import Union
3+
4+
from .core import DEFAULT_FORMAT, gettime, validate
5+
6+
7+
# Main function that is invoked by the user
8+
def randomtimestamp(
9+
start_year: int = 1950,
10+
text: bool = True,
11+
end_year: int = None,
12+
start: datetime = None,
13+
end: datetime = None,
14+
pattern: str = DEFAULT_FORMAT
15+
) -> Union[datetime, str]:
16+
"""
17+
Function generates random timestamps between two dates/years.
18+
19+
With no input, the resulting timestamp lies between
20+
(January 1, 1950, 00:00:00) and (December 31, current_year, 23:59:59)
21+
22+
Arguments:
23+
- start_year (int) [default=1950]
24+
Generate timestamp after (start_year, 1, 1, 0, 0, 0)
25+
Has no effect if 'start' or 'end' are given
26+
27+
- end_year (int) [default=None]
28+
Generate timestamp before (end_year, 12, 31, 23, 59, 59)
29+
Has no effect if 'start' or 'end' are given
30+
31+
- text (bool) [default=True]
32+
If True, return timestamp string, else return datetime object
33+
34+
- start (datetime) [default=None]
35+
Generate timestamp after 'start' (datetime)
36+
Overrides 'start_year' and 'end_year'
37+
38+
- end (datetime) [default=None]
39+
Generate timestamp before 'end' (datetime)
40+
Overrides 'start_year' and 'end_year'
41+
42+
- pattern (str) [default='%d-%m-%Y %H:%M:%S']
43+
Use custom output format for timestamp string
44+
Has no effect if 'text' == False
45+
"""
46+
start_dtime, end_dtime = validate(start_year, end_year, text, start, end)
47+
stamp = gettime(start_dtime, end_dtime)
48+
if text:
49+
return stamp.strftime(pattern)
50+
else:
51+
return stamp
52+
53+
54+
__all__ = ['randomtimestamp']

0 commit comments

Comments
 (0)