1# -*- coding: utf-8 -*-
2
3# Copyright (c) 2025, Brandon Nielsen
4# All rights reserved.
5#
6# This software may be modified and distributed under the terms
7# of the BSD license. See the LICENSE file for details.
8
9import datetime
10
11
12class UTCOffset(datetime.tzinfo):
13 def __init__(self, name=None, minutes=None):
14 # We build an offset in this manner since the
15 # tzinfo class must have an init
16 # "method that can be called with no arguments"
17 self._name = name
18
19 if minutes is not None:
20 self._utcdelta = datetime.timedelta(minutes=minutes)
21 else:
22 self._utcdelta = None
23
24 def __repr__(self):
25 if self._utcdelta >= datetime.timedelta(hours=0):
26 return "+{0} UTC".format(self._utcdelta)
27
28 # From the docs:
29 # String representations of timedelta objects are normalized
30 # similarly to their internal representation. This leads to
31 # somewhat unusual results for negative timedeltas.
32
33 # Clean this up for printing purposes
34 # Negative deltas start at -1 day
35 correcteddays = abs(self._utcdelta.days + 1)
36
37 # Negative deltas have a positive seconds
38 deltaseconds = (24 * 60 * 60) - self._utcdelta.seconds
39
40 # (24 hours / day) * (60 minutes / hour) * (60 seconds / hour)
41 days, remainder = divmod(deltaseconds, 24 * 60 * 60)
42
43 # (1 hour) * (60 minutes / hour) * (60 seconds / hour)
44 hours, remainder = divmod(remainder, 1 * 60 * 60)
45
46 # (1 minute) * (60 seconds / minute)
47 minutes, seconds = divmod(remainder, 1 * 60)
48
49 # Add any remaining days to the correcteddays count
50 correcteddays += days
51
52 if correcteddays == 0:
53 return "-{0}:{1:02}:{2:02} UTC".format(hours, minutes, seconds)
54 if correcteddays == 1:
55 return "-1 day, {0}:{1:02}:{2:02} UTC".format(hours, minutes, seconds)
56
57 return "-{0} days, {1}:{2:02}:{3:02} UTC".format(
58 correcteddays, hours, minutes, seconds
59 )
60
61 def utcoffset(self, dt):
62 return self._utcdelta
63
64 def tzname(self, dt):
65 return self._name
66
67 def dst(self, dt):
68 # ISO 8601 specifies offsets should be different if DST is required,
69 # instead of allowing for a DST to be specified
70 # https://docs.python.org/2/library/datetime.html#datetime.tzinfo.dst
71 return datetime.timedelta(0)