Skip to content

Commit bdac0af

Browse files
committed
Added funtion to convert 24h to 12h time
1 parent 839decd commit bdac0af

File tree

2 files changed

+144
-5
lines changed

2 files changed

+144
-5
lines changed

appointment/tests/utils/test_date_time.py

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
from django.test import TestCase
88

99
from appointment.settings import APP_TIME_ZONE
10-
from appointment.utils.date_time import convert_12_hour_time_to_24_hour_time, convert_minutes_in_human_readable_format, \
11-
convert_str_to_date, convert_str_to_time, get_ar_end_time, get_current_year, get_timestamp, get_timezone, \
12-
get_weekday_num, time_difference
10+
from appointment.utils.date_time import (
11+
combine_date_and_time, convert_12_hour_time_to_24_hour_time, convert_24_hour_time_to_12_hour_time,
12+
convert_minutes_in_human_readable_format, convert_str_to_date,
13+
convert_str_to_time, get_ar_end_time, get_current_year, get_timestamp, get_timezone, get_weekday_num,
14+
time_difference
15+
)
1316

1417

1518
class Convert12HourTo24HourTimeTests(TestCase):
@@ -66,6 +69,50 @@ def test_invalid_inputs(self):
6669
convert_12_hour_time_to_24_hour_time("01:60 AM")
6770

6871

72+
class Convert24HourTimeTo12HourTimeTests(TestCase):
73+
74+
def test_valid_24_hour_time_strings(self):
75+
self.assertEqual(convert_24_hour_time_to_12_hour_time("13:00"), "01:00 PM")
76+
self.assertEqual(convert_24_hour_time_to_12_hour_time("00:00"), "12:00 AM")
77+
self.assertEqual(convert_24_hour_time_to_12_hour_time("23:59"), "11:59 PM")
78+
self.assertEqual(convert_24_hour_time_to_12_hour_time("12:00"), "12:00 PM")
79+
self.assertEqual(convert_24_hour_time_to_12_hour_time("01:00"), "01:00 AM")
80+
81+
def test_valid_24_hour_time_with_seconds(self):
82+
self.assertEqual(convert_24_hour_time_to_12_hour_time("13:00:01"), "01:00:01 PM")
83+
self.assertEqual(convert_24_hour_time_to_12_hour_time("00:00:59"), "12:00:59 AM")
84+
85+
def test_datetime_time_object_input(self):
86+
time_input = datetime.time(13, 15)
87+
self.assertEqual(convert_24_hour_time_to_12_hour_time(time_input), "01:15 PM")
88+
time_input = datetime.time(0, 0)
89+
self.assertEqual(convert_24_hour_time_to_12_hour_time(time_input), "12:00 AM")
90+
91+
def test_invalid_time_strings(self):
92+
with self.assertRaises(ValueError):
93+
convert_24_hour_time_to_12_hour_time("25:00")
94+
with self.assertRaises(ValueError):
95+
convert_24_hour_time_to_12_hour_time("-01:00")
96+
with self.assertRaises(ValueError):
97+
convert_24_hour_time_to_12_hour_time("13:60")
98+
with self.assertRaises(ValueError):
99+
convert_24_hour_time_to_12_hour_time("invalid")
100+
101+
def test_incorrect_format(self):
102+
with self.assertRaises(ValueError):
103+
convert_24_hour_time_to_12_hour_time("1 PM")
104+
with self.assertRaises(ValueError):
105+
convert_24_hour_time_to_12_hour_time("13 PM")
106+
with self.assertRaises(ValueError):
107+
convert_24_hour_time_to_12_hour_time("24:00")
108+
109+
def test_edge_cases(self):
110+
self.assertEqual(convert_24_hour_time_to_12_hour_time("12:00"), "12:00 PM")
111+
self.assertEqual(convert_24_hour_time_to_12_hour_time("00:00"), "12:00 AM")
112+
self.assertEqual(convert_24_hour_time_to_12_hour_time("11:59"), "11:59 AM")
113+
self.assertEqual(convert_24_hour_time_to_12_hour_time("23:59"), "11:59 PM")
114+
115+
69116
class ConvertMinutesInHumanReadableFormatTests(TestCase):
70117
def test_valid_basic_conversions(self):
71118
"""Test basic conversions"""
@@ -218,6 +265,15 @@ def test_end_time_past_midnight(self):
218265
# hence "23:30:00" + 60 minutes = "00:30:00".
219266
self.assertEqual(get_ar_end_time("23:30:00", 60), datetime.time(0, 30))
220267

268+
def test_invalid_start_time_type(self):
269+
"""Test that an invalid start_time type raises a TypeError."""
270+
with self.assertRaises(TypeError):
271+
get_ar_end_time([], 60) # Passing a list instead of a datetime.time object or string
272+
with self.assertRaises(TypeError):
273+
get_ar_end_time(12345, 30) # Passing an integer
274+
with self.assertRaises(TypeError):
275+
get_ar_end_time(None, 30) # Passing None
276+
221277

222278
class TimeDifferenceTests(TestCase):
223279

@@ -249,6 +305,66 @@ def test_negative_difference_with_datetime_objects(self):
249305
with self.assertRaises(ValueError):
250306
time_difference(datetime2, datetime1)
251307

308+
def test_mismatched_input_types(self):
309+
"""Test that providing one 'datetime.time' and one datetime.datetime raises a ValueError."""
310+
time_obj = datetime.time(10, 0)
311+
datetime_obj = datetime.datetime(2023, 1, 1, 11, 0)
312+
313+
with self.assertRaises(ValueError) as context:
314+
time_difference(time_obj, datetime_obj)
315+
316+
self.assertEqual(str(context.exception),
317+
"Both inputs should be of the same type, either datetime.time or datetime.datetime")
318+
319+
# Test the reverse case as well for completeness
320+
with self.assertRaises(ValueError) as context:
321+
time_difference(datetime_obj, time_obj)
322+
323+
self.assertEqual(str(context.exception),
324+
"Both inputs should be of the same type, either datetime.time or datetime.datetime")
325+
326+
327+
class CombineDateAndTimeTests(TestCase):
328+
def test_combine_valid_date_and_time(self):
329+
"""Test combining a valid date and time."""
330+
date = datetime.date(2023, 1, 1)
331+
time = datetime.time(12, 30)
332+
expected_datetime = datetime.datetime(2023, 1, 1, 12, 30)
333+
result = combine_date_and_time(date, time)
334+
self.assertEqual(result, expected_datetime)
335+
336+
def test_combine_with_midnight(self):
337+
"""Test combining a date with a midnight time."""
338+
date = datetime.date(2023, 1, 1)
339+
time = datetime.time(0, 0)
340+
expected_datetime = datetime.datetime(2023, 1, 1, 0, 0)
341+
result = combine_date_and_time(date, time)
342+
self.assertEqual(result, expected_datetime)
343+
344+
def test_combine_with_leap_year_date(self):
345+
"""Test combining a leap year date and time."""
346+
date = datetime.date(2024, 2, 29)
347+
time = datetime.time(23, 59)
348+
expected_datetime = datetime.datetime(2024, 2, 29, 23, 59)
349+
result = combine_date_and_time(date, time)
350+
self.assertEqual(result, expected_datetime)
351+
352+
def test_combine_with_end_of_day(self):
353+
"""Test combining a date with 'end of day time'."""
354+
date = datetime.date(2023, 1, 1)
355+
time = datetime.time(23, 59, 59)
356+
expected_datetime = datetime.datetime(2023, 1, 1, 23, 59, 59)
357+
result = combine_date_and_time(date, time)
358+
self.assertEqual(result, expected_datetime)
359+
360+
def test_combine_with_microseconds(self):
361+
"""Test combining a date and time with microseconds."""
362+
date = datetime.date(2023, 1, 1)
363+
time = datetime.time(12, 30, 15, 123456)
364+
expected_datetime = datetime.datetime(2023, 1, 1, 12, 30, 15, 123456)
365+
result = combine_date_and_time(date, time)
366+
self.assertEqual(result, expected_datetime)
367+
252368

253369
class TimestampTests(TestCase):
254370
@patch('appointment.utils.date_time.timezone.now')

appointment/utils/date_time.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,31 @@ def convert_12_hour_time_to_24_hour_time(time_to_convert) -> str:
4343
raise ValueError(f"Unsupported data type for time conversion: {type(time_to_convert)}")
4444

4545

46+
def convert_24_hour_time_to_12_hour_time(time_to_convert) -> str:
47+
"""Convert a 24-hour time to a 12-hour time.
48+
49+
:param time_to_convert: The time to convert in 'HH:MM' or 'HH:MM:SS' format, or a datetime.time object.
50+
:return: The converted time in 'HH:MM AM/PM' or 'HH:MM:SS AM/PM' format.
51+
:raises ValueError: If the input time is not in the correct format or is invalid.
52+
"""
53+
# Handle datetime.time object directly
54+
if isinstance(time_to_convert, datetime.time):
55+
return time_to_convert.strftime('%I:%M %p')
56+
57+
# Handle string input
58+
for source_fmt, dest_fmt in zip(['%H:%M:%S', '%H:%M'], ['%I:%M:%S %p', '%I:%M %p']):
59+
try:
60+
# Parse the input string according to the 24-hour format
61+
parsed_time = datetime.datetime.strptime(time_to_convert, source_fmt)
62+
# Convert and return the time in 12-hour format
63+
return parsed_time.strftime(dest_fmt)
64+
except ValueError:
65+
continue # Try the next format if there was a parsing error
66+
67+
# If input was not datetime.time and did not match string formats, raise an error
68+
raise ValueError(f"Invalid 24-hour time format: {time_to_convert}")
69+
70+
4671
def convert_minutes_in_human_readable_format(minutes: float) -> str:
4772
"""Convert a number of minutes in a human-readable format.
4873
@@ -75,8 +100,6 @@ def convert_minutes_in_human_readable_format(minutes: float) -> str:
75100
return _("{first_part} and {second_part}").format(first_part=parts[0], second_part=parts[1])
76101
elif len(parts) == 3:
77102
return _("{days}, {hours} and {minutes}").format(days=parts[0], hours=parts[1], minutes=parts[2])
78-
else:
79-
return ""
80103

81104

82105
def convert_str_to_date(date_str: str) -> datetime.date:

0 commit comments

Comments
 (0)