Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/isodate/isodates.py @ 5:9b1c78e6ba9c draft default tip
"planemo upload commit 6c0a8142489327ece472c84e558c47da711a9142"
author | shellac |
---|---|
date | Mon, 01 Jun 2020 08:59:25 -0400 |
parents | 79f47841a781 |
children |
comparison
equal
deleted
inserted
replaced
4:79f47841a781 | 5:9b1c78e6ba9c |
---|---|
1 ############################################################################## | |
2 # Copyright 2009, Gerhard Weis | |
3 # All rights reserved. | |
4 # | |
5 # Redistribution and use in source and binary forms, with or without | |
6 # modification, are permitted provided that the following conditions are met: | |
7 # | |
8 # * Redistributions of source code must retain the above copyright notice, | |
9 # this list of conditions and the following disclaimer. | |
10 # * Redistributions in binary form must reproduce the above copyright notice, | |
11 # this list of conditions and the following disclaimer in the documentation | |
12 # and/or other materials provided with the distribution. | |
13 # * Neither the name of the authors nor the names of its contributors | |
14 # may be used to endorse or promote products derived from this software | |
15 # without specific prior written permission. | |
16 # | |
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
18 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
21 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
22 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
23 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
24 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
25 # CONTRACT, STRICT LIABILITY, OR TORT | |
26 ############################################################################## | |
27 ''' | |
28 This modules provides a method to parse an ISO 8601:2004 date string to a | |
29 python datetime.date instance. | |
30 | |
31 It supports all basic, extended and expanded formats as described in the ISO | |
32 standard. The only limitations it has, are given by the Python datetime.date | |
33 implementation, which does not support dates before 0001-01-01. | |
34 ''' | |
35 import re | |
36 from datetime import date, timedelta | |
37 | |
38 from isodate.isostrf import strftime, DATE_EXT_COMPLETE | |
39 from isodate.isoerror import ISO8601Error | |
40 | |
41 DATE_REGEX_CACHE = {} | |
42 # A dictionary to cache pre-compiled regular expressions. | |
43 # A set of regular expressions is identified, by number of year digits allowed | |
44 # and whether a plus/minus sign is required or not. (This option is changeable | |
45 # only for 4 digit years). | |
46 | |
47 | |
48 def build_date_regexps(yeardigits=4, expanded=False): | |
49 ''' | |
50 Compile set of regular expressions to parse ISO dates. The expressions will | |
51 be created only if they are not already in REGEX_CACHE. | |
52 | |
53 It is necessary to fix the number of year digits, else it is not possible | |
54 to automatically distinguish between various ISO date formats. | |
55 | |
56 ISO 8601 allows more than 4 digit years, on prior agreement, but then a +/- | |
57 sign is required (expanded format). To support +/- sign for 4 digit years, | |
58 the expanded parameter needs to be set to True. | |
59 ''' | |
60 if yeardigits != 4: | |
61 expanded = True | |
62 if (yeardigits, expanded) not in DATE_REGEX_CACHE: | |
63 cache_entry = [] | |
64 # ISO 8601 expanded DATE formats allow an arbitrary number of year | |
65 # digits with a leading +/- sign. | |
66 if expanded: | |
67 sign = 1 | |
68 else: | |
69 sign = 0 | |
70 # 1. complete dates: | |
71 # YYYY-MM-DD or +- YYYYYY-MM-DD... extended date format | |
72 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
73 r"-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})" | |
74 % (sign, yeardigits))) | |
75 # YYYYMMDD or +- YYYYYYMMDD... basic date format | |
76 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
77 r"(?P<month>[0-9]{2})(?P<day>[0-9]{2})" | |
78 % (sign, yeardigits))) | |
79 # 2. complete week dates: | |
80 # YYYY-Www-D or +-YYYYYY-Www-D ... extended week date | |
81 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
82 r"-W(?P<week>[0-9]{2})-(?P<day>[0-9]{1})" | |
83 % (sign, yeardigits))) | |
84 # YYYYWwwD or +-YYYYYYWwwD ... basic week date | |
85 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})W" | |
86 r"(?P<week>[0-9]{2})(?P<day>[0-9]{1})" | |
87 % (sign, yeardigits))) | |
88 # 3. ordinal dates: | |
89 # YYYY-DDD or +-YYYYYY-DDD ... extended format | |
90 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
91 r"-(?P<day>[0-9]{3})" | |
92 % (sign, yeardigits))) | |
93 # YYYYDDD or +-YYYYYYDDD ... basic format | |
94 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
95 r"(?P<day>[0-9]{3})" | |
96 % (sign, yeardigits))) | |
97 # 4. week dates: | |
98 # YYYY-Www or +-YYYYYY-Www ... extended reduced accuracy week date | |
99 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
100 r"-W(?P<week>[0-9]{2})" | |
101 % (sign, yeardigits))) | |
102 # YYYYWww or +-YYYYYYWww ... basic reduced accuracy week date | |
103 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})W" | |
104 r"(?P<week>[0-9]{2})" | |
105 % (sign, yeardigits))) | |
106 # 5. month dates: | |
107 # YYY-MM or +-YYYYYY-MM ... reduced accuracy specific month | |
108 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
109 r"-(?P<month>[0-9]{2})" | |
110 % (sign, yeardigits))) | |
111 # YYYMM or +-YYYYYYMM ... basic incomplete month date format | |
112 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
113 r"(?P<month>[0-9]{2})" | |
114 % (sign, yeardigits))) | |
115 # 6. year dates: | |
116 # YYYY or +-YYYYYY ... reduced accuracy specific year | |
117 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}(?P<year>[0-9]{%d})" | |
118 % (sign, yeardigits))) | |
119 # 7. century dates: | |
120 # YY or +-YYYY ... reduced accuracy specific century | |
121 cache_entry.append(re.compile(r"(?P<sign>[+-]){%d}" | |
122 r"(?P<century>[0-9]{%d})" | |
123 % (sign, yeardigits - 2))) | |
124 | |
125 DATE_REGEX_CACHE[(yeardigits, expanded)] = cache_entry | |
126 return DATE_REGEX_CACHE[(yeardigits, expanded)] | |
127 | |
128 | |
129 def parse_date( | |
130 datestring, | |
131 yeardigits=4, expanded=False, defaultmonth=1, defaultday=1): | |
132 ''' | |
133 Parse an ISO 8601 date string into a datetime.date object. | |
134 | |
135 As the datetime.date implementation is limited to dates starting from | |
136 0001-01-01, negative dates (BC) and year 0 can not be parsed by this | |
137 method. | |
138 | |
139 For incomplete dates, this method chooses the first day for it. For | |
140 instance if only a century is given, this method returns the 1st of | |
141 January in year 1 of this century. | |
142 | |
143 supported formats: (expanded formats are shown with 6 digits for year) | |
144 YYYYMMDD +-YYYYYYMMDD basic complete date | |
145 YYYY-MM-DD +-YYYYYY-MM-DD extended complete date | |
146 YYYYWwwD +-YYYYYYWwwD basic complete week date | |
147 YYYY-Www-D +-YYYYYY-Www-D extended complete week date | |
148 YYYYDDD +-YYYYYYDDD basic ordinal date | |
149 YYYY-DDD +-YYYYYY-DDD extended ordinal date | |
150 YYYYWww +-YYYYYYWww basic incomplete week date | |
151 YYYY-Www +-YYYYYY-Www extended incomplete week date | |
152 YYYMM +-YYYYYYMM basic incomplete month date | |
153 YYY-MM +-YYYYYY-MM incomplete month date | |
154 YYYY +-YYYYYY incomplete year date | |
155 YY +-YYYY incomplete century date | |
156 | |
157 @param datestring: the ISO date string to parse | |
158 @param yeardigits: how many digits are used to represent a year | |
159 @param expanded: if True then +/- signs are allowed. This parameter | |
160 is forced to True, if yeardigits != 4 | |
161 | |
162 @return: a datetime.date instance represented by datestring | |
163 @raise ISO8601Error: if this function can not parse the datestring | |
164 @raise ValueError: if datestring can not be represented by datetime.date | |
165 ''' | |
166 if yeardigits != 4: | |
167 expanded = True | |
168 isodates = build_date_regexps(yeardigits, expanded) | |
169 for pattern in isodates: | |
170 match = pattern.match(datestring) | |
171 if match: | |
172 groups = match.groupdict() | |
173 # sign, century, year, month, week, day, | |
174 # FIXME: negative dates not possible with python standard types | |
175 sign = (groups['sign'] == '-' and -1) or 1 | |
176 if 'century' in groups: | |
177 return date( | |
178 sign * (int(groups['century']) * 100 + 1), | |
179 defaultmonth, defaultday) | |
180 if 'month' not in groups: # weekdate or ordinal date | |
181 ret = date(sign * int(groups['year']), 1, 1) | |
182 if 'week' in groups: | |
183 isotuple = ret.isocalendar() | |
184 if 'day' in groups: | |
185 days = int(groups['day'] or 1) | |
186 else: | |
187 days = 1 | |
188 # if first week in year, do weeks-1 | |
189 return ret + timedelta(weeks=int(groups['week']) - | |
190 (((isotuple[1] == 1) and 1) or 0), | |
191 days=-isotuple[2] + days) | |
192 elif 'day' in groups: # ordinal date | |
193 return ret + timedelta(days=int(groups['day']) - 1) | |
194 else: # year date | |
195 return ret.replace(month=defaultmonth, day=defaultday) | |
196 # year-, month-, or complete date | |
197 if 'day' not in groups or groups['day'] is None: | |
198 day = defaultday | |
199 else: | |
200 day = int(groups['day']) | |
201 return date(sign * int(groups['year']), | |
202 int(groups['month']) or defaultmonth, day) | |
203 raise ISO8601Error('Unrecognised ISO 8601 date format: %r' % datestring) | |
204 | |
205 | |
206 def date_isoformat(tdate, format=DATE_EXT_COMPLETE, yeardigits=4): | |
207 ''' | |
208 Format date strings. | |
209 | |
210 This method is just a wrapper around isodate.isostrf.strftime and uses | |
211 Date-Extended-Complete as default format. | |
212 ''' | |
213 return strftime(tdate, format, yeardigits) |