We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Serialization -> de-serialisation fails for small timedelta (< 100 microseconds)
### Checks

* [x] I added a descriptive title to this issue
* [x] I have searched (google, github) for similar issues and couldn't find anything
* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->

# Bug

The serialization -> de-serialization of a model with small `timedelta` raises a `ValidationError`. The de-serialization fails only when the `timedelta` is below 100 microseconds, see the following example:

```py
from datetime import timedelta
from pydantic import BaseModel

class Model(BaseModel):
    duration: timedelta


# This works
model = Model(duration=timedelta(microseconds=100))
Model.parse_raw(model.json())
# This Fails
model = Model(duration=timedelta(microseconds=99))
Model.parse_raw(model.json())
```

Last line throws the following error:
```py
pydantic.error_wrappers.ValidationError: 1 validation error for Model
duration
  invalid duration format (type=value_error.duration)
```

I believe the error comes from the `parse_duration` function, and in particular the line where the input value is converted to `str`.
https://github.com/samuelcolvin/pydantic/blob/c256dccbb383a7fd462f62fcb5d55558eb3cb108/pydantic/datetime_parse.py#L226-L231
Indeed `str(0.0001)` gives `"0.0001"` but `str(0.000099)` gives `"9.9e-5"`, thus the `re.match` fails.

Changing `value = str(value)` to `value = "f{value:.6f}"` should fix this. I would be happy to create a PR to solve the issue.

# System information

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.2
            pydantic compiled: True
                 install path: <my-home>/.pyenv/versions/3.7.11/envs/pydantic/lib/python3.7/site-packages/pydantic
               python version: 3.7.11 (default, Aug 31 2021, 20:43:02)  [Clang 10.0.1 (clang-1001.0.46.4)]
                     platform: Darwin-19.6.0-x86_64-i386-64bit
     optional deps. installed: ['typing-extensions']
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pydantic/datetime_parse.py`
Content:
```
1 """
2 Functions to parse datetime objects.
3 
4 We're using regular expressions rather than time.strptime because:
5 - They provide both validation and parsing.
6 - They're more flexible for datetimes.
7 - The date/datetime/time constructors produce friendlier error messages.
8 
9 Stolen from https://raw.githubusercontent.com/django/django/master/django/utils/dateparse.py at
10 9718fa2e8abe430c3526a9278dd976443d4ae3c6
11 
12 Changed to:
13 * use standard python datetime types not django.utils.timezone
14 * raise ValueError when regex doesn't match rather than returning None
15 * support parsing unix timestamps for dates and datetimes
16 """
17 import re
18 from datetime import date, datetime, time, timedelta, timezone
19 from typing import Dict, Optional, Type, Union
20 
21 from . import errors
22 
23 date_expr = r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})'
24 time_expr = (
25     r'(?P<hour>\d{1,2}):(?P<minute>\d{1,2})'
26     r'(?::(?P<second>\d{1,2})(?:\.(?P<microsecond>\d{1,6})\d{0,6})?)?'
27     r'(?P<tzinfo>Z|[+-]\d{2}(?::?\d{2})?)?$'
28 )
29 
30 date_re = re.compile(f'{date_expr}$')
31 time_re = re.compile(time_expr)
32 datetime_re = re.compile(f'{date_expr}[T ]{time_expr}')
33 
34 standard_duration_re = re.compile(
35     r'^'
36     r'(?:(?P<days>-?\d+) (days?, )?)?'
37     r'((?:(?P<hours>-?\d+):)(?=\d+:\d+))?'
38     r'(?:(?P<minutes>-?\d+):)?'
39     r'(?P<seconds>-?\d+)'
40     r'(?:\.(?P<microseconds>\d{1,6})\d{0,6})?'
41     r'$'
42 )
43 
44 # Support the sections of ISO 8601 date representation that are accepted by timedelta
45 iso8601_duration_re = re.compile(
46     r'^(?P<sign>[-+]?)'
47     r'P'
48     r'(?:(?P<days>\d+(.\d+)?)D)?'
49     r'(?:T'
50     r'(?:(?P<hours>\d+(.\d+)?)H)?'
51     r'(?:(?P<minutes>\d+(.\d+)?)M)?'
52     r'(?:(?P<seconds>\d+(.\d+)?)S)?'
53     r')?'
54     r'$'
55 )
56 
57 EPOCH = datetime(1970, 1, 1)
58 # if greater than this, the number is in ms, if less than or equal it's in seconds
59 # (in seconds this is 11th October 2603, in ms it's 20th August 1970)
60 MS_WATERSHED = int(2e10)
61 # slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9
62 MAX_NUMBER = int(3e20)
63 StrBytesIntFloat = Union[str, bytes, int, float]
64 
65 
66 def get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]:
67     if isinstance(value, (int, float)):
68         return value
69     try:
70         return float(value)
71     except ValueError:
72         return None
73     except TypeError:
74         raise TypeError(f'invalid type; expected {native_expected_type}, string, bytes, int or float')
75 
76 
77 def from_unix_seconds(seconds: Union[int, float]) -> datetime:
78     if seconds > MAX_NUMBER:
79         return datetime.max
80     elif seconds < -MAX_NUMBER:
81         return datetime.min
82 
83     while abs(seconds) > MS_WATERSHED:
84         seconds /= 1000
85     dt = EPOCH + timedelta(seconds=seconds)
86     return dt.replace(tzinfo=timezone.utc)
87 
88 
89 def _parse_timezone(value: Optional[str], error: Type[Exception]) -> Union[None, int, timezone]:
90     if value == 'Z':
91         return timezone.utc
92     elif value is not None:
93         offset_mins = int(value[-2:]) if len(value) > 3 else 0
94         offset = 60 * int(value[1:3]) + offset_mins
95         if value[0] == '-':
96             offset = -offset
97         try:
98             return timezone(timedelta(minutes=offset))
99         except ValueError:
100             raise error()
101     else:
102         return None
103 
104 
105 def parse_date(value: Union[date, StrBytesIntFloat]) -> date:
106     """
107     Parse a date/int/float/string and return a datetime.date.
108 
109     Raise ValueError if the input is well formatted but not a valid date.
110     Raise ValueError if the input isn't well formatted.
111     """
112     if isinstance(value, date):
113         if isinstance(value, datetime):
114             return value.date()
115         else:
116             return value
117 
118     number = get_numeric(value, 'date')
119     if number is not None:
120         return from_unix_seconds(number).date()
121 
122     if isinstance(value, bytes):
123         value = value.decode()
124 
125     match = date_re.match(value)  # type: ignore
126     if match is None:
127         raise errors.DateError()
128 
129     kw = {k: int(v) for k, v in match.groupdict().items()}
130 
131     try:
132         return date(**kw)
133     except ValueError:
134         raise errors.DateError()
135 
136 
137 def parse_time(value: Union[time, StrBytesIntFloat]) -> time:
138     """
139     Parse a time/string and return a datetime.time.
140 
141     Raise ValueError if the input is well formatted but not a valid time.
142     Raise ValueError if the input isn't well formatted, in particular if it contains an offset.
143     """
144     if isinstance(value, time):
145         return value
146 
147     number = get_numeric(value, 'time')
148     if number is not None:
149         if number >= 86400:
150             # doesn't make sense since the time time loop back around to 0
151             raise errors.TimeError()
152         return (datetime.min + timedelta(seconds=number)).time()
153 
154     if isinstance(value, bytes):
155         value = value.decode()
156 
157     match = time_re.match(value)  # type: ignore
158     if match is None:
159         raise errors.TimeError()
160 
161     kw = match.groupdict()
162     if kw['microsecond']:
163         kw['microsecond'] = kw['microsecond'].ljust(6, '0')
164 
165     tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.TimeError)
166     kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}
167     kw_['tzinfo'] = tzinfo
168 
169     try:
170         return time(**kw_)  # type: ignore
171     except ValueError:
172         raise errors.TimeError()
173 
174 
175 def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime:
176     """
177     Parse a datetime/int/float/string and return a datetime.datetime.
178 
179     This function supports time zone offsets. When the input contains one,
180     the output uses a timezone with a fixed offset from UTC.
181 
182     Raise ValueError if the input is well formatted but not a valid datetime.
183     Raise ValueError if the input isn't well formatted.
184     """
185     if isinstance(value, datetime):
186         return value
187 
188     number = get_numeric(value, 'datetime')
189     if number is not None:
190         return from_unix_seconds(number)
191 
192     if isinstance(value, bytes):
193         value = value.decode()
194 
195     match = datetime_re.match(value)  # type: ignore
196     if match is None:
197         raise errors.DateTimeError()
198 
199     kw = match.groupdict()
200     if kw['microsecond']:
201         kw['microsecond'] = kw['microsecond'].ljust(6, '0')
202 
203     tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.DateTimeError)
204     kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}
205     kw_['tzinfo'] = tzinfo
206 
207     try:
208         return datetime(**kw_)  # type: ignore
209     except ValueError:
210         raise errors.DateTimeError()
211 
212 
213 def parse_duration(value: StrBytesIntFloat) -> timedelta:
214     """
215     Parse a duration int/float/string and return a datetime.timedelta.
216 
217     The preferred format for durations in Django is '%d %H:%M:%S.%f'.
218 
219     Also supports ISO 8601 representation.
220     """
221     if isinstance(value, timedelta):
222         return value
223 
224     if isinstance(value, (int, float)):
225         # below code requires a string
226         value = str(value)
227     elif isinstance(value, bytes):
228         value = value.decode()
229 
230     try:
231         match = standard_duration_re.match(value) or iso8601_duration_re.match(value)
232     except TypeError:
233         raise TypeError('invalid type; expected timedelta, string, bytes, int or float')
234 
235     if not match:
236         raise errors.DurationError()
237 
238     kw = match.groupdict()
239     sign = -1 if kw.pop('sign', '+') == '-' else 1
240     if kw.get('microseconds'):
241         kw['microseconds'] = kw['microseconds'].ljust(6, '0')
242 
243     if kw.get('seconds') and kw.get('microseconds') and kw['seconds'].startswith('-'):
244         kw['microseconds'] = '-' + kw['microseconds']
245 
246     kw_ = {k: float(v) for k, v in kw.items() if v is not None}
247 
248     return sign * timedelta(**kw_)
249
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pydantic/datetime_parse.py b/pydantic/datetime_parse.py
--- a/pydantic/datetime_parse.py
+++ b/pydantic/datetime_parse.py
@@ -223,7 +223,7 @@
 
     if isinstance(value, (int, float)):
         # below code requires a string
-        value = str(value)
+        value = f'{value:f}'
     elif isinstance(value, bytes):
         value = value.decode()

{"golden_diff": "diff --git a/pydantic/datetime_parse.py b/pydantic/datetime_parse.py\n--- a/pydantic/datetime_parse.py\n+++ b/pydantic/datetime_parse.py\n@@ -223,7 +223,7 @@\n \n     if isinstance(value, (int, float)):\n         # below code requires a string\n-        value = str(value)\n+        value = f'{value:f}'\n     elif isinstance(value, bytes):\n         value = value.decode()\n", "issue": "Serialization -> de-serialisation fails for small timedelta (< 100 microseconds)\n### Checks\r\n\r\n* [x] I added a descriptive title to this issue\r\n* [x] I have searched (google, github) for similar issues and couldn't find anything\r\n* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug\r\n\r\n<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->\r\n\r\n# Bug\r\n\r\nThe serialization -> de-serialization of a model with small `timedelta` raises a `ValidationError`. The de-serialization fails only when the `timedelta` is below 100 microseconds, see the following example:\r\n\r\n```py\r\nfrom datetime import timedelta\r\nfrom pydantic import BaseModel\r\n\r\nclass Model(BaseModel):\r\n    duration: timedelta\r\n\r\n\r\n# This works\r\nmodel = Model(duration=timedelta(microseconds=100))\r\nModel.parse_raw(model.json())\r\n# This Fails\r\nmodel = Model(duration=timedelta(microseconds=99))\r\nModel.parse_raw(model.json())\r\n```\r\n\r\nLast line throws the following error:\r\n```py\r\npydantic.error_wrappers.ValidationError: 1 validation error for Model\r\nduration\r\n  invalid duration format (type=value_error.duration)\r\n```\r\n\r\nI believe the error comes from the `parse_duration` function, and in particular the line where the input value is converted to `str`.\r\nhttps://github.com/samuelcolvin/pydantic/blob/c256dccbb383a7fd462f62fcb5d55558eb3cb108/pydantic/datetime_parse.py#L226-L231\r\nIndeed `str(0.0001)` gives `\"0.0001\"` but `str(0.000099)` gives `\"9.9e-5\"`, thus the `re.match` fails.\r\n\r\nChanging `value = str(value)` to `value = \"f{value:.6f}\"` should fix this. I would be happy to create a PR to solve the issue.\r\n\r\n# System information\r\n\r\nOutput of `python -c \"import pydantic.utils; print(pydantic.utils.version_info())\"`:\r\n```\r\n             pydantic version: 1.8.2\r\n            pydantic compiled: True\r\n                 install path: <my-home>/.pyenv/versions/3.7.11/envs/pydantic/lib/python3.7/site-packages/pydantic\r\n               python version: 3.7.11 (default, Aug 31 2021, 20:43:02)  [Clang 10.0.1 (clang-1001.0.46.4)]\r\n                     platform: Darwin-19.6.0-x86_64-i386-64bit\r\n     optional deps. installed: ['typing-extensions']\r\n```\n", "before_files": [{"content": "\"\"\"\nFunctions to parse datetime objects.\n\nWe're using regular expressions rather than time.strptime because:\n- They provide both validation and parsing.\n- They're more flexible for datetimes.\n- The date/datetime/time constructors produce friendlier error messages.\n\nStolen from https://raw.githubusercontent.com/django/django/master/django/utils/dateparse.py at\n9718fa2e8abe430c3526a9278dd976443d4ae3c6\n\nChanged to:\n* use standard python datetime types not django.utils.timezone\n* raise ValueError when regex doesn't match rather than returning None\n* support parsing unix timestamps for dates and datetimes\n\"\"\"\nimport re\nfrom datetime import date, datetime, time, timedelta, timezone\nfrom typing import Dict, Optional, Type, Union\n\nfrom . import errors\n\ndate_expr = r'(?P<year>\\d{4})-(?P<month>\\d{1,2})-(?P<day>\\d{1,2})'\ntime_expr = (\n    r'(?P<hour>\\d{1,2}):(?P<minute>\\d{1,2})'\n    r'(?::(?P<second>\\d{1,2})(?:\\.(?P<microsecond>\\d{1,6})\\d{0,6})?)?'\n    r'(?P<tzinfo>Z|[+-]\\d{2}(?::?\\d{2})?)?$'\n)\n\ndate_re = re.compile(f'{date_expr}$')\ntime_re = re.compile(time_expr)\ndatetime_re = re.compile(f'{date_expr}[T ]{time_expr}')\n\nstandard_duration_re = re.compile(\n    r'^'\n    r'(?:(?P<days>-?\\d+) (days?, )?)?'\n    r'((?:(?P<hours>-?\\d+):)(?=\\d+:\\d+))?'\n    r'(?:(?P<minutes>-?\\d+):)?'\n    r'(?P<seconds>-?\\d+)'\n    r'(?:\\.(?P<microseconds>\\d{1,6})\\d{0,6})?'\n    r'$'\n)\n\n# Support the sections of ISO 8601 date representation that are accepted by timedelta\niso8601_duration_re = re.compile(\n    r'^(?P<sign>[-+]?)'\n    r'P'\n    r'(?:(?P<days>\\d+(.\\d+)?)D)?'\n    r'(?:T'\n    r'(?:(?P<hours>\\d+(.\\d+)?)H)?'\n    r'(?:(?P<minutes>\\d+(.\\d+)?)M)?'\n    r'(?:(?P<seconds>\\d+(.\\d+)?)S)?'\n    r')?'\n    r'$'\n)\n\nEPOCH = datetime(1970, 1, 1)\n# if greater than this, the number is in ms, if less than or equal it's in seconds\n# (in seconds this is 11th October 2603, in ms it's 20th August 1970)\nMS_WATERSHED = int(2e10)\n# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9\nMAX_NUMBER = int(3e20)\nStrBytesIntFloat = Union[str, bytes, int, float]\n\n\ndef get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]:\n    if isinstance(value, (int, float)):\n        return value\n    try:\n        return float(value)\n    except ValueError:\n        return None\n    except TypeError:\n        raise TypeError(f'invalid type; expected {native_expected_type}, string, bytes, int or float')\n\n\ndef from_unix_seconds(seconds: Union[int, float]) -> datetime:\n    if seconds > MAX_NUMBER:\n        return datetime.max\n    elif seconds < -MAX_NUMBER:\n        return datetime.min\n\n    while abs(seconds) > MS_WATERSHED:\n        seconds /= 1000\n    dt = EPOCH + timedelta(seconds=seconds)\n    return dt.replace(tzinfo=timezone.utc)\n\n\ndef _parse_timezone(value: Optional[str], error: Type[Exception]) -> Union[None, int, timezone]:\n    if value == 'Z':\n        return timezone.utc\n    elif value is not None:\n        offset_mins = int(value[-2:]) if len(value) > 3 else 0\n        offset = 60 * int(value[1:3]) + offset_mins\n        if value[0] == '-':\n            offset = -offset\n        try:\n            return timezone(timedelta(minutes=offset))\n        except ValueError:\n            raise error()\n    else:\n        return None\n\n\ndef parse_date(value: Union[date, StrBytesIntFloat]) -> date:\n    \"\"\"\n    Parse a date/int/float/string and return a datetime.date.\n\n    Raise ValueError if the input is well formatted but not a valid date.\n    Raise ValueError if the input isn't well formatted.\n    \"\"\"\n    if isinstance(value, date):\n        if isinstance(value, datetime):\n            return value.date()\n        else:\n            return value\n\n    number = get_numeric(value, 'date')\n    if number is not None:\n        return from_unix_seconds(number).date()\n\n    if isinstance(value, bytes):\n        value = value.decode()\n\n    match = date_re.match(value)  # type: ignore\n    if match is None:\n        raise errors.DateError()\n\n    kw = {k: int(v) for k, v in match.groupdict().items()}\n\n    try:\n        return date(**kw)\n    except ValueError:\n        raise errors.DateError()\n\n\ndef parse_time(value: Union[time, StrBytesIntFloat]) -> time:\n    \"\"\"\n    Parse a time/string and return a datetime.time.\n\n    Raise ValueError if the input is well formatted but not a valid time.\n    Raise ValueError if the input isn't well formatted, in particular if it contains an offset.\n    \"\"\"\n    if isinstance(value, time):\n        return value\n\n    number = get_numeric(value, 'time')\n    if number is not None:\n        if number >= 86400:\n            # doesn't make sense since the time time loop back around to 0\n            raise errors.TimeError()\n        return (datetime.min + timedelta(seconds=number)).time()\n\n    if isinstance(value, bytes):\n        value = value.decode()\n\n    match = time_re.match(value)  # type: ignore\n    if match is None:\n        raise errors.TimeError()\n\n    kw = match.groupdict()\n    if kw['microsecond']:\n        kw['microsecond'] = kw['microsecond'].ljust(6, '0')\n\n    tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.TimeError)\n    kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}\n    kw_['tzinfo'] = tzinfo\n\n    try:\n        return time(**kw_)  # type: ignore\n    except ValueError:\n        raise errors.TimeError()\n\n\ndef parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime:\n    \"\"\"\n    Parse a datetime/int/float/string and return a datetime.datetime.\n\n    This function supports time zone offsets. When the input contains one,\n    the output uses a timezone with a fixed offset from UTC.\n\n    Raise ValueError if the input is well formatted but not a valid datetime.\n    Raise ValueError if the input isn't well formatted.\n    \"\"\"\n    if isinstance(value, datetime):\n        return value\n\n    number = get_numeric(value, 'datetime')\n    if number is not None:\n        return from_unix_seconds(number)\n\n    if isinstance(value, bytes):\n        value = value.decode()\n\n    match = datetime_re.match(value)  # type: ignore\n    if match is None:\n        raise errors.DateTimeError()\n\n    kw = match.groupdict()\n    if kw['microsecond']:\n        kw['microsecond'] = kw['microsecond'].ljust(6, '0')\n\n    tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.DateTimeError)\n    kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}\n    kw_['tzinfo'] = tzinfo\n\n    try:\n        return datetime(**kw_)  # type: ignore\n    except ValueError:\n        raise errors.DateTimeError()\n\n\ndef parse_duration(value: StrBytesIntFloat) -> timedelta:\n    \"\"\"\n    Parse a duration int/float/string and return a datetime.timedelta.\n\n    The preferred format for durations in Django is '%d %H:%M:%S.%f'.\n\n    Also supports ISO 8601 representation.\n    \"\"\"\n    if isinstance(value, timedelta):\n        return value\n\n    if isinstance(value, (int, float)):\n        # below code requires a string\n        value = str(value)\n    elif isinstance(value, bytes):\n        value = value.decode()\n\n    try:\n        match = standard_duration_re.match(value) or iso8601_duration_re.match(value)\n    except TypeError:\n        raise TypeError('invalid type; expected timedelta, string, bytes, int or float')\n\n    if not match:\n        raise errors.DurationError()\n\n    kw = match.groupdict()\n    sign = -1 if kw.pop('sign', '+') == '-' else 1\n    if kw.get('microseconds'):\n        kw['microseconds'] = kw['microseconds'].ljust(6, '0')\n\n    if kw.get('seconds') and kw.get('microseconds') and kw['seconds'].startswith('-'):\n        kw['microseconds'] = '-' + kw['microseconds']\n\n    kw_ = {k: float(v) for k, v in kw.items() if v is not None}\n\n    return sign * timedelta(**kw_)\n", "path": "pydantic/datetime_parse.py"}], "after_files": [{"content": "\"\"\"\nFunctions to parse datetime objects.\n\nWe're using regular expressions rather than time.strptime because:\n- They provide both validation and parsing.\n- They're more flexible for datetimes.\n- The date/datetime/time constructors produce friendlier error messages.\n\nStolen from https://raw.githubusercontent.com/django/django/master/django/utils/dateparse.py at\n9718fa2e8abe430c3526a9278dd976443d4ae3c6\n\nChanged to:\n* use standard python datetime types not django.utils.timezone\n* raise ValueError when regex doesn't match rather than returning None\n* support parsing unix timestamps for dates and datetimes\n\"\"\"\nimport re\nfrom datetime import date, datetime, time, timedelta, timezone\nfrom typing import Dict, Optional, Type, Union\n\nfrom . import errors\n\ndate_expr = r'(?P<year>\\d{4})-(?P<month>\\d{1,2})-(?P<day>\\d{1,2})'\ntime_expr = (\n    r'(?P<hour>\\d{1,2}):(?P<minute>\\d{1,2})'\n    r'(?::(?P<second>\\d{1,2})(?:\\.(?P<microsecond>\\d{1,6})\\d{0,6})?)?'\n    r'(?P<tzinfo>Z|[+-]\\d{2}(?::?\\d{2})?)?$'\n)\n\ndate_re = re.compile(f'{date_expr}$')\ntime_re = re.compile(time_expr)\ndatetime_re = re.compile(f'{date_expr}[T ]{time_expr}')\n\nstandard_duration_re = re.compile(\n    r'^'\n    r'(?:(?P<days>-?\\d+) (days?, )?)?'\n    r'((?:(?P<hours>-?\\d+):)(?=\\d+:\\d+))?'\n    r'(?:(?P<minutes>-?\\d+):)?'\n    r'(?P<seconds>-?\\d+)'\n    r'(?:\\.(?P<microseconds>\\d{1,6})\\d{0,6})?'\n    r'$'\n)\n\n# Support the sections of ISO 8601 date representation that are accepted by timedelta\niso8601_duration_re = re.compile(\n    r'^(?P<sign>[-+]?)'\n    r'P'\n    r'(?:(?P<days>\\d+(.\\d+)?)D)?'\n    r'(?:T'\n    r'(?:(?P<hours>\\d+(.\\d+)?)H)?'\n    r'(?:(?P<minutes>\\d+(.\\d+)?)M)?'\n    r'(?:(?P<seconds>\\d+(.\\d+)?)S)?'\n    r')?'\n    r'$'\n)\n\nEPOCH = datetime(1970, 1, 1)\n# if greater than this, the number is in ms, if less than or equal it's in seconds\n# (in seconds this is 11th October 2603, in ms it's 20th August 1970)\nMS_WATERSHED = int(2e10)\n# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9\nMAX_NUMBER = int(3e20)\nStrBytesIntFloat = Union[str, bytes, int, float]\n\n\ndef get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]:\n    if isinstance(value, (int, float)):\n        return value\n    try:\n        return float(value)\n    except ValueError:\n        return None\n    except TypeError:\n        raise TypeError(f'invalid type; expected {native_expected_type}, string, bytes, int or float')\n\n\ndef from_unix_seconds(seconds: Union[int, float]) -> datetime:\n    if seconds > MAX_NUMBER:\n        return datetime.max\n    elif seconds < -MAX_NUMBER:\n        return datetime.min\n\n    while abs(seconds) > MS_WATERSHED:\n        seconds /= 1000\n    dt = EPOCH + timedelta(seconds=seconds)\n    return dt.replace(tzinfo=timezone.utc)\n\n\ndef _parse_timezone(value: Optional[str], error: Type[Exception]) -> Union[None, int, timezone]:\n    if value == 'Z':\n        return timezone.utc\n    elif value is not None:\n        offset_mins = int(value[-2:]) if len(value) > 3 else 0\n        offset = 60 * int(value[1:3]) + offset_mins\n        if value[0] == '-':\n            offset = -offset\n        try:\n            return timezone(timedelta(minutes=offset))\n        except ValueError:\n            raise error()\n    else:\n        return None\n\n\ndef parse_date(value: Union[date, StrBytesIntFloat]) -> date:\n    \"\"\"\n    Parse a date/int/float/string and return a datetime.date.\n\n    Raise ValueError if the input is well formatted but not a valid date.\n    Raise ValueError if the input isn't well formatted.\n    \"\"\"\n    if isinstance(value, date):\n        if isinstance(value, datetime):\n            return value.date()\n        else:\n            return value\n\n    number = get_numeric(value, 'date')\n    if number is not None:\n        return from_unix_seconds(number).date()\n\n    if isinstance(value, bytes):\n        value = value.decode()\n\n    match = date_re.match(value)  # type: ignore\n    if match is None:\n        raise errors.DateError()\n\n    kw = {k: int(v) for k, v in match.groupdict().items()}\n\n    try:\n        return date(**kw)\n    except ValueError:\n        raise errors.DateError()\n\n\ndef parse_time(value: Union[time, StrBytesIntFloat]) -> time:\n    \"\"\"\n    Parse a time/string and return a datetime.time.\n\n    Raise ValueError if the input is well formatted but not a valid time.\n    Raise ValueError if the input isn't well formatted, in particular if it contains an offset.\n    \"\"\"\n    if isinstance(value, time):\n        return value\n\n    number = get_numeric(value, 'time')\n    if number is not None:\n        if number >= 86400:\n            # doesn't make sense since the time time loop back around to 0\n            raise errors.TimeError()\n        return (datetime.min + timedelta(seconds=number)).time()\n\n    if isinstance(value, bytes):\n        value = value.decode()\n\n    match = time_re.match(value)  # type: ignore\n    if match is None:\n        raise errors.TimeError()\n\n    kw = match.groupdict()\n    if kw['microsecond']:\n        kw['microsecond'] = kw['microsecond'].ljust(6, '0')\n\n    tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.TimeError)\n    kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}\n    kw_['tzinfo'] = tzinfo\n\n    try:\n        return time(**kw_)  # type: ignore\n    except ValueError:\n        raise errors.TimeError()\n\n\ndef parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime:\n    \"\"\"\n    Parse a datetime/int/float/string and return a datetime.datetime.\n\n    This function supports time zone offsets. When the input contains one,\n    the output uses a timezone with a fixed offset from UTC.\n\n    Raise ValueError if the input is well formatted but not a valid datetime.\n    Raise ValueError if the input isn't well formatted.\n    \"\"\"\n    if isinstance(value, datetime):\n        return value\n\n    number = get_numeric(value, 'datetime')\n    if number is not None:\n        return from_unix_seconds(number)\n\n    if isinstance(value, bytes):\n        value = value.decode()\n\n    match = datetime_re.match(value)  # type: ignore\n    if match is None:\n        raise errors.DateTimeError()\n\n    kw = match.groupdict()\n    if kw['microsecond']:\n        kw['microsecond'] = kw['microsecond'].ljust(6, '0')\n\n    tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.DateTimeError)\n    kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None}\n    kw_['tzinfo'] = tzinfo\n\n    try:\n        return datetime(**kw_)  # type: ignore\n    except ValueError:\n        raise errors.DateTimeError()\n\n\ndef parse_duration(value: StrBytesIntFloat) -> timedelta:\n    \"\"\"\n    Parse a duration int/float/string and return a datetime.timedelta.\n\n    The preferred format for durations in Django is '%d %H:%M:%S.%f'.\n\n    Also supports ISO 8601 representation.\n    \"\"\"\n    if isinstance(value, timedelta):\n        return value\n\n    if isinstance(value, (int, float)):\n        # below code requires a string\n        value = f'{value:f}'\n    elif isinstance(value, bytes):\n        value = value.decode()\n\n    try:\n        match = standard_duration_re.match(value) or iso8601_duration_re.match(value)\n    except TypeError:\n        raise TypeError('invalid type; expected timedelta, string, bytes, int or float')\n\n    if not match:\n        raise errors.DurationError()\n\n    kw = match.groupdict()\n    sign = -1 if kw.pop('sign', '+') == '-' else 1\n    if kw.get('microseconds'):\n        kw['microseconds'] = kw['microseconds'].ljust(6, '0')\n\n    if kw.get('seconds') and kw.get('microseconds') and kw['seconds'].startswith('-'):\n        kw['microseconds'] = '-' + kw['microseconds']\n\n    kw_ = {k: float(v) for k, v in kw.items() if v is not None}\n\n    return sign * timedelta(**kw_)\n", "path": "pydantic/datetime_parse.py"}]}