# Create a Time class.

Time is on my side

## Specification

• Basic attributes: hour, minute, second and day (default is 0), + getters, + setters (using a decorator)

• If you try to initialize an incorrect value of seconds or minutes, i.e. greater than or equal to 60, raise an exception from your own WrongSeconds or WrongMinutes class

Add the following operators:

• +: works as follows - adds hours to hours, minutes to minutes, and so on, e.g. 2 h 30 m 4 s + 6 h 35 m 50 s = 9 h 5 m 54 s (we also return an instance of the Time class), if we exceed 24 h, the day should be 1

• <: Compare first day, hours, then minutes, seconds. Return True / False, e.g. 2 h 40 m 30 s d 0 < 1 h 59 m 30 s d 0 → False, 2 h 40 m 30 s d -1 < 1 h 59 m 30 s d 0 → True

• __str__: Time should be displayed as: "20:05:25, day without any changes" (when day = 1, -1 : next / previous day)

Add the function zone, which for a given instance of the Time class returns the appropriate time in another time zone. The argument of the function is the city for which we find the time: Warsaw, London, New York, Tokyo, Syndey, Moscow, Los Angeles. We assume that the default time is GMT.

• PEP8
• DOC
• tests

And here is the code!

class WrongSeconds(Exception):
def __str__(self):
return "Wrong amount of seconds passed (greater or equal 60)"

class WrongMinutes(Exception):
def __str__(self):
return "Wrong amount of minutes passed (greater or equal 60)"

class Time:
TIME_ZONES = { "Warsaw": 2,
"London": 1,
"Tokio": 9,
"Sydney": 10,
"Moscow": 3,
"Los angeles": -7 }

def __init__(self, d = 0, h = 0, m = 0, s = 0):
self.days = d
self.hours = h
self.minutes = m
self.seconds = s

@property
def days(self):
return self._d

@days.setter
def days(self, val):
self._d = val

@property
def hours(self):
return self._h

@hours.setter
def hours(self, val):
if val < 0:
self.days += val//60
val = 24 - abs(val)%24
elif val >= 24:
self.days += val//24
val %= 24
self._h = val

@property
def minutes(self):
return self._m

@minutes.setter
def minutes(self, val):
if "_m" not in self.__dict__ and  val >= 60:
raise WrongMinutes
if val < 0:
self.hours += val//60
val = 60 - abs(val)%60
elif val >= 60:
self.hours += val//60
val %= 60
self._m = val

@property
def seconds(self):
return self._s

@seconds.setter
def seconds(self, val):
if "_s" not in self.__dict__ and  val >= 60:
raise WrongSeconds
if val < 0:
self.minutes += val//60
val = 60 - abs(val)%60
elif val >= 60:
self.minutes += val//60
val %= 60
self._s = val

def strefa(self, city):
if city.capitalize() not in self.TIME_ZONES: raise ValueError(f"City {city} not in time zone database")

result_time = self.__class__( self.days, self.hours, self.minutes, self.seconds)
result_time.hours += self.TIME_ZONES[city.capitalize()]

return str(result_time)

assert isinstance(other, self.__class__), f"Cannot add {type(other)} to a time object"
result = self.__class__()

result.seconds += self.seconds + other.seconds
result.minutes += self.minutes + other.minutes
result.hours   += self.hours   + other.hours
result.days    += self.days    + other.days

return result

def __lt__(self, other):
assert isinstance(other, self.__class__), f"Cannot compare {type(other)} with a time object"

if self.days < other.days: return True
elif self.hours < other.hours: return True
elif self.minutes < other.minutes: return True
elif self.seconds < other.seconds: return True

return False

def __str__(self):
s = f"{self.hours}:{self.minutes:02}:{self.seconds:02}"

if self.days == 0 :
return s + ", day without any changes"

elif self.days == 1 :
return s + ", the next day"

elif self.days == -1 :
return s + ", previous day"

return s + f", day: {self.days}"

#  --- TEST CASES ---
try:
time = Time(m = 60)
except Exception as e:
print(e.__class__, e, "\n")

time = Time(d = 0, h = 23, m = 59, s = 59)
print(time)

time.seconds += 1
print(time, "\n")

time1 = Time(h = 3, m = 2, s = 1)
time2 = Time(h = 6, m = 5, s = 4)
print(time1 + time2, "\n")

print(time1 < time2 )
print(time2 < time1, "\n")

time_gmt = Time(h = 2, m = 0, s = 0)
print(time_gmt.strefa("London"))
print(time_gmt.strefa("Sydney"))
print(time_gmt.strefa("Los Angeles"))
print("------------------------------------")
print("Comparisons")

t1 = Time(h = 14, m = 4, s = 35)
t2 =  Time(h = 8, m = 50, s = 25)

print(t1 + t2)
print(t1)
print(t2)
print(t1 < t2)



Output:

<class '__main__.WrongMinutes'> Wrong amount of minutes passed (greater or equal 60)

23:59:59, day without any changes
0:00:00, the next day

9:07:05, day without any changes

True
False

3:00:00, day without any changes
12:00:00, day without any changes
19:00:00, previous day
------------------------------------
Comparisons
22:55:00, day without any changes
14:04:35, day without any changes
8:50:25, day without any changes
True


And here is my question, how to get a better solution? Maybe shorter? Maybe get rid of some operations, terms?

• If you can't represent the 61st second of a minute, what's supposed to happen when there's a leap second?? Jun 22 '21 at 16:19
• um raise a wrongseconds/wrongminutes error i guess Jun 22 '21 at 16:21
• That's fine - the code just pretends leap seconds don't exist. I'm poking fun a little, but also pointing out that real date-time code has a lot of awkward real-world stuff to deal with, so better using the libraries than writing your own for actual use. Jun 22 '21 at 16:23
• Well you know, sometimes (because its a task for school) I also don't see any sense in creating such complicated and thus simple things, but yeah, here we are! :D Jun 22 '21 at 16:25
• One comment is, whenever you are implementing either of the comparison operators, you need to make sure you always implement them all. This would be, <, <=, >, >=, == and !=. Otherwise, the whoever used your Time class might run into trouble during comparisons without noticing. Jun 22 '21 at 19:35

One small point:

When we inherit from Exception, we get its (actually, BaseException's) str() implementation, so we don't need to provide __str__() if we initialise the base class args with the required string:

class WrongSeconds(Exception):
def __init__(self):
self.args = [ "Wrong amount of seconds passed (greater or equal 60)" ]


In the addition, we have these new values:

    result.seconds += self.seconds + other.seconds
result.minutes += self.minutes + other.minutes
result.hours   += self.hours   + other.hours
result.days    += self.days    + other.days


I don't see anything that handles overflow of any of these values (e.g. if hours > 24, we need to add a day and subtract 24 of the hours to get the values back into their allowed ranges).