Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/isodate/isodates.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 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) |
