Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/openpyxl/utils/datetime.py : 35%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import division
2# Copyright (c) 2010-2020 openpyxl
4"""Manage Excel date weirdness."""
6# Python stdlib imports
7import datetime
8from datetime import timedelta, tzinfo
9from math import isnan
10import re
12from jdcal import (
13 gcal2jd,
14 jd2gcal,
15 MJD_0
16)
19# constants
20MAC_EPOCH = datetime.date(1904, 1, 1)
21WINDOWS_EPOCH = datetime.date(1899, 12, 30)
22CALENDAR_WINDOWS_1900 = sum(gcal2jd(WINDOWS_EPOCH.year, WINDOWS_EPOCH.month, WINDOWS_EPOCH.day))
23CALENDAR_MAC_1904 = sum(gcal2jd(MAC_EPOCH.year, MAC_EPOCH.month, MAC_EPOCH.day))
24SECS_PER_DAY = 86400
26EPOCH = datetime.datetime.utcfromtimestamp(0)
27ISO_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
28ISO_REGEX = re.compile(r'''
29(?P<date>(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}))?T?
30(?P<time>(?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2})(.(?P<ms>\d{2}))?)?Z?''',
31 re.VERBOSE)
34def to_ISO8601(dt):
35 """Convert from a datetime to a timestamp string."""
36 return datetime.datetime.strftime(dt, ISO_FORMAT)
39def from_ISO8601(formatted_string):
40 """Convert from a timestamp string to a datetime object. According to
41 18.17.4 in the specification the following ISO 8601 formats are
42 supported.
44 Dates B.1.1 and B.2.1
45 Times B.1.2 and B.2.2
46 Datetimes B.1.3 and B.2.3
48 There is no concept of timedeltas
49 """
50 match = ISO_REGEX.match(formatted_string)
51 if not match:
52 raise ValueError("Invalid datetime value {}".format(formatted_string))
54 parts = {k:int(v) for k, v in match.groupdict().items() if v is not None and v.isdigit()}
55 if 'year' not in parts:
56 dt = datetime.time(parts['hour'], parts['minute'], parts['second'])
57 elif 'hour' not in parts:
58 dt = datetime.date(parts['year'], parts['month'], parts['day'])
59 else:
60 dt = datetime.datetime(year=parts['year'], month=parts['month'],
61 day=parts['day'], hour=parts['hour'], minute=parts['minute'],
62 second=parts['second'])
63 if 'ms' in parts:
64 dt += timedelta(microseconds=parts['ms'])
65 return dt
68def to_excel(dt, offset=CALENDAR_WINDOWS_1900):
69 if isinstance(dt, datetime.time):
70 return time_to_days(dt)
71 if isinstance(dt, datetime.timedelta):
72 return timedelta_to_days(dt)
73 if isnan(dt.year): # Pandas supports Not a Date
74 return
75 jul = sum(gcal2jd(dt.year, dt.month, dt.day)) - offset
76 if jul <= 60 and offset == CALENDAR_WINDOWS_1900:
77 jul -= 1
78 if hasattr(dt, 'time'):
79 jul += time_to_days(dt)
80 return jul
83def from_excel(value, offset=CALENDAR_WINDOWS_1900):
84 if value is None:
85 return
86 if 1 < value < 60 and offset == CALENDAR_WINDOWS_1900:
87 value += 1
88 parts = list(jd2gcal(MJD_0, value + offset - MJD_0))
89 _, fraction = divmod(value, 1)
90 jumped = (parts[-1] == 0 and fraction > 0)
91 diff = datetime.timedelta(days=fraction)
93 if 0 < abs(value) < 1:
94 return days_to_time(diff)
95 if not jumped:
96 return datetime.datetime(*parts[:3]) + diff
97 else:
98 return datetime.datetime(*parts[:3] + [0])
101class GMT(tzinfo):
103 def utcoffset(self, dt):
104 return timedelta(0)
106 def dst(self, dt):
107 return timedelta(0)
109 def tzname(self,dt):
110 return "GMT"
112try:
113 from datetime import timezone
114 UTC = timezone(timedelta(0))
115except ImportError:
116 # Python 2
117 UTC = GMT()
120def time_to_days(value):
121 """Convert a time value to fractions of day"""
122 if value.tzinfo is not None:
123 value = value.astimezone(UTC)
124 return (
125 (value.hour * 3600)
126 + (value.minute * 60)
127 + value.second
128 + value.microsecond / 10**6
129 ) / SECS_PER_DAY
132def timedelta_to_days(value):
133 """Convert a timedelta value to fractions of a day"""
134 if not hasattr(value, 'total_seconds'):
135 secs = (value.microseconds +
136 (value.seconds + value.days * SECS_PER_DAY) * 10**6) / 10**6
137 else:
138 secs = value.total_seconds()
139 return secs / SECS_PER_DAY
142def days_to_time(value):
143 mins, seconds = divmod(value.seconds, 60)
144 hours, mins = divmod(mins, 60)
145 return datetime.time(hours, mins, seconds, value.microseconds)