Passed
Push — 2.x ( 14eff7...cd037c )
by Jordi
05:19
created

senaite.core.api.dtime   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 48
eloc 122
dl 0
loc 238
rs 8.5599
c 0
b 0
f 0

15 Functions

Rating   Name   Duplication   Size   Complexity  
A to_zone() 0 19 5
A from_timestamp() 0 7 1
A is_dt() 0 7 1
A to_iso_format() 0 11 4
A to_timestamp() 0 15 4
A to_dt() 0 17 5
A is_d() 0 7 1
A is_timezone_naive() 0 16 5
A is_DT() 0 7 1
B get_os_timezone() 0 24 6
A is_valid_timezone() 0 11 2
A is_date() 0 16 5
A is_timezone_aware() 0 7 1
B to_DT() 0 20 6
A is_str() 0 7 1

How to fix   Complexity   

Complexity

Complex classes like senaite.core.api.dtime often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
3
import os
4
import time
5
from datetime import date
6
from datetime import datetime
7
8
import six
9
10
import pytz
11
from bika.lims import logger
12
from bika.lims.api import APIError
13
from DateTime import DateTime
14
from DateTime.DateTime import DateError
15
from DateTime.DateTime import SyntaxError
16
from DateTime.DateTime import TimeError
17
18
19
def is_str(obj):
20
    """Check if the given object is a string
21
22
    :param obj: arbitrary object
23
    :returns: True when the object is a string
24
    """
25
    return isinstance(obj, six.string_types)
26
27
28
def is_d(dt):
29
    """Check if the date is a Python `date` object
30
31
    :param dt: date to check
32
    :returns: True when the date is a Python `date`
33
    """
34
    return type(dt) is date
35
36
37
def is_dt(dt):
38
    """Check if the date is a Python `datetime` object
39
40
    :param dt: date to check
41
    :returns: True when the date is a Python `datetime`
42
    """
43
    return type(dt) is datetime
44
45
46
def is_DT(dt):
47
    """Check if the date is a Zope `DateTime` object
48
49
    :param dt: object to check
50
    :returns: True when the object is a Zope `DateTime`
51
    """
52
    return type(dt) is DateTime
53
54
55
def is_date(dt):
56
    """Check if the date is a datetime or DateTime object
57
58
    :param dt: date to check
59
    :returns: True when the object is either a datetime or DateTime
60
    """
61
    if is_str(dt):
62
        DT = to_DT(dt)
63
        return is_date(DT)
64
    if is_d(dt):
65
        return True
66
    if is_dt(dt):
67
        return True
68
    if is_DT(dt):
69
        return True
70
    return False
71
72
73
def is_timezone_naive(dt):
74
    """Check if the date is timezone naive
75
76
    :param dt: date to check
77
    :returns: True when the date has no timezone
78
    """
79
    if is_d(dt):
80
        return True
81
    elif is_DT(dt):
82
        return dt.timezoneNaive()
83
    elif is_dt(dt):
84
        return dt.tzinfo is None
85
    elif is_str(dt):
86
        DT = to_DT(dt)
87
        return is_timezone_naive(DT)
88
    raise APIError("Expected a date type, got '%r'" % type(dt))
89
90
91
def is_timezone_aware(dt):
92
    """Check if the date is timezone aware
93
94
    :param dt: date to check
95
    :returns: True when the date has a timezone
96
    """
97
    return not is_timezone_naive(dt)
98
99
100
def to_DT(dt):
101
    """Convert to DateTime
102
103
    :param dt: DateTime/datetime/date
104
    :returns: DateTime object
105
    """
106
    if is_DT(dt):
107
        return dt
108
    elif is_str(dt):
109
        try:
110
            return DateTime(dt)
111
        except (DateError, TimeError, SyntaxError, IndexError):
112
            return None
113
    elif is_dt(dt):
114
        return DateTime(dt.isoformat())
115
    elif is_d(dt):
116
        dt = datetime(dt.year, dt.month, dt.day)
117
        return DateTime(dt.isoformat())
118
    else:
119
        return None
120
121
122
def to_dt(dt):
123
    """Convert to datetime
124
125
    :param dt: DateTime/datetime/date
126
    :returns: datetime object
127
    """
128
    if is_DT(dt):
129
        return dt.asdatetime()
130
    elif is_str(dt):
131
        DT = to_DT(dt)
132
        return to_dt(DT)
133
    elif is_dt(dt):
134
        return dt
135
    elif is_d(dt):
136
        return datetime(dt.year, dt.month, dt.day)
137
    else:
138
        return None
139
140
141
def is_valid_timezone(timezone):
142
    """Checks if the timezone is a valid pytz/Olson name
143
144
    :param timezone: pytz/Olson timezone name
145
    :returns: True when the timezone is a valid zone
146
    """
147
    try:
148
        pytz.timezone(timezone)
149
        return True
150
    except pytz.UnknownTimeZoneError:
151
        return False
152
153
154
def get_os_timezone():
155
    """Return the default timezone of the system
156
157
    :returns: OS timezone or UTC
158
    """
159
    fallback = "UTC"
160
    timezone = None
161
    if "TZ" in os.environ.keys():
162
        # Timezone from OS env var
163
        timezone = os.environ["TZ"]
164
    if not timezone:
165
        # Timezone from python time
166
        zones = time.tzname
167
        if zones and len(zones) > 0:
168
            timezone = zones[0]
169
        else:
170
            # Default fallback = UTC
171
            logger.warn(
172
                "Operating system\'s timezone cannot be found. "
173
                "Falling back to UTC.")
174
            timezone = fallback
175
    if not is_valid_timezone(timezone):
176
        return fallback
177
    return timezone
178
179
180
def to_zone(dt, timezone):
181
    """Convert date to timezone
182
183
    Adds the timezone for timezone naive datetimes
184
185
    :param dt: date object
186
    :param timezone: timezone
187
    :returns: date converted to timezone
188
    """
189
    if is_dt(dt) or is_d(dt):
190
        dt = to_dt(dt)
191
        zone = pytz.timezone(timezone)
192
        if is_timezone_aware(dt):
193
            return dt.astimezone(zone)
194
        return zone.localize(dt)
195
    elif is_DT(dt):
196
        # NOTE: This shifts the time according to the TZ offset
197
        return dt.toZone(timezone)
198
    raise TypeError("Expected a date, got '%r'" % type(dt))
199
200
201
def to_timestamp(dt):
202
    """Generate a Portable Operating System Interface (POSIX) timestamp
203
204
    :param dt: date object
205
    :returns: timestamp in seconds
206
    """
207
    timestamp = 0
208
    if is_DT(dt):
209
        timestamp = dt.timeTime()
210
    elif is_dt(dt):
211
        timestamp = time.mktime(dt.timetuple())
212
    elif is_str(dt):
213
        DT = to_DT(dt)
214
        return to_timestamp(DT)
215
    return timestamp
216
217
218
def from_timestamp(timestamp):
219
    """Generate a datetime object from a POSIX timestamp
220
221
    :param timestamp: POSIX timestamp
222
    :returns: datetime object
223
    """
224
    return datetime.utcfromtimestamp(timestamp)
225
226
227
def to_iso_format(dt):
228
    """Convert to ISO format
229
    """
230
    if is_dt(dt):
231
        return dt.isoformat()
232
    elif is_DT(dt):
233
        return dt.ISO()
234
    elif is_str(dt):
235
        DT = to_DT(dt)
236
        return to_iso_format(DT)
237
    return None
238