Repository: pydicom/pydicom

Issue:
Remove dateutil dependencie
It seems that `dateutil` is used for `tzoffset` class which is available in python standard library since python 2.6 with `datetime.timedelta`

```
pydicom/valuerep.py:    from dateutil.tz import tzoffset
pydicom/valuerep.py:                    tzinfo = tzoffset(tz_match, offset)
tests/test_filewriter.py:    from dateutil.tz import tzoffset
tests/test_filewriter.py:        tzinfo = tzoffset('-0600', -21600)
tests/test_filewriter.py:                                      tzoffset('-0600', -21600)))
tests/test_valuerep.py:    from dateutil.tz import tzoffset
tests/test_valuerep.py:                                     tzoffset(None, -10 * 3600))
```

we should probably rework the code to remove this unecessary dependency

Discussion:
pep8speaks: Hello @glemaitre! Thanks for submitting the PR.

 - In the file [`pydicom/tests/test_filewriter.py`](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py), following are the PEP8 issues :

> [Line 81:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L81): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (83 > 79 characters)
> [Line 100:47](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L100): [E225](https://duckduckgo.com/?q=pep8%20E225) missing whitespace around operator
> [Line 206:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L206): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (119 > 79 characters)
> [Line 207:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L207): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (101 > 79 characters)
> [Line 208:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L208): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (126 > 79 characters)
> [Line 209:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L209): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (119 > 79 characters)
> [Line 210:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L210): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (101 > 79 characters)
> [Line 295:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L295): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (82 > 79 characters)
> [Line 296:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L296): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (84 > 79 characters)
> [Line 339:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L339): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (82 > 79 characters)
> [Line 340:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L340): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (84 > 79 characters)
> [Line 501:53](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L501): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 508:53](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L508): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 515:53](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L515): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 526:59](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L526): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 551:39](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L551): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 552:58](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L552): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 555:59](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L555): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 581:39](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L581): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 601:42](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L601): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 602:58](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L602): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 605:59](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L605): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 619:42](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L619): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 630:59](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L630): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 631:37](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L631): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 632:58](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L632): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 639:59](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L639): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 641:58](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L641): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 687:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L687): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (84 > 79 characters)
> [Line 692:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L692): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (89 > 79 characters)
> [Line 693:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L693): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (81 > 79 characters)
> [Line 719:53](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L719): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 737:53](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L737): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 792:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L792): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (90 > 79 characters)
> [Line 798:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L798): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (82 > 79 characters)
> [Line 824:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L824): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (80 > 79 characters)
> [Line 846:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L846): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 848:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L848): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 872:37](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L872): [E701](https://duckduckgo.com/?q=pep8%20E701) multiple statements on one line (colon)
> [Line 873:37](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L873): [E701](https://duckduckgo.com/?q=pep8%20E701) multiple statements on one line (colon)
> [Line 886:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L886): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (80 > 79 characters)
> [Line 900:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L900): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 908:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L908): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (94 > 79 characters)
> [Line 911:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L911): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 914:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L914): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 916:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L916): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 927:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L927): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 934:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L934): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (85 > 79 characters)
> [Line 944:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L944): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 998:50](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L998): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1068:47](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1068): [E225](https://duckduckgo.com/?q=pep8%20E225) missing whitespace around operator
> [Line 1085:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1085): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (80 > 79 characters)
> [Line 1105:37](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1105): [E701](https://duckduckgo.com/?q=pep8%20E701) multiple statements on one line (colon)
> [Line 1106:37](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1106): [E701](https://duckduckgo.com/?q=pep8%20E701) multiple statements on one line (colon)
> [Line 1128:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1128): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1144:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1144): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1162:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1162): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1177:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1177): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1205:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1205): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (95 > 79 characters)
> [Line 1207:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1207): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1227:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1227): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (95 > 79 characters)
> [Line 1229:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1229): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1248:9](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1248): [E265](https://duckduckgo.com/?q=pep8%20E265) block comment should start with '# '
> [Line 1248:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1248): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (96 > 79 characters)
> [Line 1250:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1250): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1274:9](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1274): [E265](https://duckduckgo.com/?q=pep8%20E265) block comment should start with '# '
> [Line 1274:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1274): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (96 > 79 characters)
> [Line 1276:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1276): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1299:9](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1299): [E265](https://duckduckgo.com/?q=pep8%20E265) block comment should start with '# '
> [Line 1299:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1299): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (96 > 79 characters)
> [Line 1301:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1301): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1325:9](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1325): [E265](https://duckduckgo.com/?q=pep8%20E265) block comment should start with '# '
> [Line 1325:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1325): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (96 > 79 characters)
> [Line 1327:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1327): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1348:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1348): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (95 > 79 characters)
> [Line 1350:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1350): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1370:9](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1370): [E265](https://duckduckgo.com/?q=pep8%20E265) block comment should start with '# '
> [Line 1370:80](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1370): [E501](https://duckduckgo.com/?q=pep8%20E501) line too long (96 > 79 characters)
> [Line 1372:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1372): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1382:25](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1382): [E127](https://duckduckgo.com/?q=pep8%20E127) continuation line over-indented for visual indent
> [Line 1405:41](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1405): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment
> [Line 1502:49](https://github.com/pydicom/pydicom/blob/e5a8452788c2fa61320cc456fb0c625f6ecc0b1c/pydicom/tests/test_filewriter.py#L1502): [E261](https://duckduckgo.com/?q=pep8%20E261) at least two spaces before inline comment






glemaitre: Not as pretty that I wanted since `timezone` was not ported to python 2.7.
I still think that we should avoid a dependency thought.
glemaitre: @darcymason I am not sure if we should go with our own backport as currently implemented or use `python-future` as a dependency which will be cleaner and make the code transparent between python 2/3 for standard library. I think I am more for the second solution.
massich: -1 checking travis, python 2.7 does not pass. Change title to WIP
darcymason: So does this not create a dependency on `future`?  Can the required module just be incorporated into pydicom?
darcymason: My original thought when you said about eliminating the `python-dateutil` dependency was making it an optional dependency, like numpy and others.  Is that a reasonable possibility? 

Date-times are one of these things I rarely use (or in the past if  I needed to work with dates,  I converted to a date/time class from the string in my code outside pydicom), but I do get the impression it is quite important to many people.
vsoch: why can't we just use datetime? Is it missing additional functionality? 
darcymason: > why can't we just use datetime? Is it missing additional functionality?

There was an old discussion around these changes, one comment about datetime is [here](https://groups.google.com/d/msg/pydicom/4IMwZiFgCkk/oypLAsSI5KAJ).  I'm no expert in this, just passing along what was said.

vsoch: hmm. My naive instinct is that, while it would be nice to always be able to parse / convert datetime for the user, why not just leave as a string and allow them to manage? With pydicom doing the conversion there is chance of getting it wrong, for example going from import to save might not be consistent. I guess it comes down to being a question of how much post processing pydicom should do for the data beyond providing a means to read and work with it.  It looks like the extra needed functionality is for the timezone offset.
glemaitre: > My original thought when you said about eliminating the python-dateutil dependency was making it an optional dependency, like numpy and others. Is that a reasonable possibility?

My original solution (backporting timezone in util.fixes) seems to work and remove dependencies. The only thing which I didn't like is that timezone representation will be printed as `fixes.timezone` in python 2 and `datetime.timezone` in python 3 but both are subclassed from `datetime.tzinfo` (present in py2 and py3) which make thing work.

> Date-times are one of these things I rarely use (or in the past if I needed to work with dates, I converted to a date/time class from the string in my code outside pydicom), but I do get the impression it is quite important to many people.

Does they need the objects DT or a convert function would be more than enough. Regarding the pattern of the object, it moreless as only a `__init__` which means that it could be replace by a function making the conversion to/from DICOM DT.
glemaitre: @pydicom/pydicom-core I think this is ok for a revision
glemaitre: Ups I forgot the tests
massich: @glemaitre are `fromutc` and `tzname` used anywhere? these are the tests you are talking about? or you just add these functions for completeness?
glemaitre: This is for completeness. This is a port of the python code itself.
massich: ok. LGTM once there's no conflicts.
glemaitre:                                                                                       Yep this is still WIP. I would think that copyright could have his copyright file in the root
glemaitre:                                                                                       Oh I think I missed what you meant. With the authors field, this is not to replace the copyright but rather to have rough idea of who is knowing about the file. In some sort this is rough git blame.
mrbean-bremen: I'm fine with that, just noticed that other recently touched files are updated with a standard copyright notice (like [dataset.py](https://github.com/pydicom/pydicom/blob/master/pydicom/dataset.py)) .
glemaitre: I see. I think that we should avoid this line on the top of the file but rather inside.
glemaitre: Ok appveyor is lagging but if you have any review, I think it should be fine
@massich @mrbean-bremen 
mrbean-bremen: What about a note where the timezone code is from (see my previous comment)? Or did you write it from scratch?
glemaitre: > see my previous comment

I extended the note to be more precise.

> Or did you write it from scratch

adapted only.
massich: I think that what @mrbean-bremen is referring to is to the conversation we had regarding adding the authorship and license of the files. The issue came across in PR by @vsoch. (I didn't find it, maybe @vsoch can point where it was and bring some light to the discussion). Maybe we should update the [CONTRIBUTING.md](https://github.com/pydicom/pydicom/blob/master/CONTRIBUTING.md) with the instructions regarding the headers. I agree with @glemaitre that having *author* (or in other words: *who to blame or ping*)  directly in the file header sometimes helps. I don't have any strong opinion regarding those issues but whatever is policie should be stated more clear in the `CONTRIBUTING.md`.
mrbean-bremen: > The issue came across in PR by @vsoch. 

There is link to the PR in the related issue #447.
glemaitre: waiting for the released note to be merged
glemaitre: Back to be mergeable @pydicom/pydicom-core 

Patch:
diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh
index cd59b797d..0034e0156 100755
--- a/build_tools/travis/install.sh
+++ b/build_tools/travis/install.sh
@@ -38,7 +38,7 @@ if [[ "$DISTRIB" == "conda" ]]; then
     # provided versions
     conda create -n testenv --yes python=$PYTHON_VERSION pip
     source activate testenv
-    conda install --yes nose pytest pytest-cov python-dateutil
+    conda install --yes nose pytest pytest-cov
     if [[ "$NUMPY" == "true" ]]; then
         conda install --yes numpy
     fi
@@ -65,7 +65,7 @@ elif [[ "$DISTRIB" == "ubuntu" ]]; then
     # Create a new virtualenv using system site packages for python, numpy
     virtualenv --system-site-packages testvenv
     source testvenv/bin/activate
-    pip install nose nose-timer pytest pytest-cov codecov python-dateutil
+    pip install nose nose-timer pytest pytest-cov codecov
 
 elif [[ "$DISTRIB" == "pypy" ]]; then
     # This is to see if we are supporting pypy. With pypy3, numpypy is not
@@ -97,7 +97,7 @@ elif [[ "$DISTRIB" == "pypy" ]]; then
     elif [[ "$NUMPY" == "true" ]]; then
         python -m pip install cython numpy
     fi
-    python -m pip install nose nose-timer pytest pytest-cov codecov python-dateutil
+    python -m pip install nose nose-timer pytest pytest-cov codecov
 fi
 
 python --version
diff --git a/doc/release-notes.rst b/doc/release-notes.rst
index 117fd5122..0267393d3 100644
--- a/doc/release-notes.rst
+++ b/doc/release-notes.rst
@@ -7,6 +7,9 @@ Release history
 Version 1.0.0 (under development)
 =================================
 
+Highlights
+----------
+
 This is a major release, with major changes, including backwards-incompatible
 changes.
 
@@ -27,8 +30,19 @@ Enhancements
 Documentation
 .............
 
-* Documentation refactorization with examples. :issue:`472` by :user:`Guillaume
-  Lemaitre <glemaitre>`.
+* Documentation refactorization with examples. :issue:`472`.
+
+Maintenance
+...........
+
+* Remove :class:`pydicom.filereader.DicomIter` since it is
+  unused. :issue:`493`.
+
+Maintenance
+...........
+
+* Remove ``python-dateutil`` dependency by backporting ``datetime.timezone``
+  from Python 3.6 to Python 2.7. :issue:`435`.
 
 Other changes
 .............
diff --git a/pydicom/filereader.py b/pydicom/filereader.py
index 692cc43d9..427791b16 100644
--- a/pydicom/filereader.py
+++ b/pydicom/filereader.py
@@ -65,95 +65,6 @@ except ImportError:
 sys_is_little_endian = (byteorder == 'little')
 
 
-class DicomIter(object):
-    """Iterator over DICOM data elements
-       created from a file-like object
-    """
-
-    def __init__(self, fp, stop_when=None, force=False):
-        """Read the preamble and meta info and prepare
-           iterator for remainder of file.
-
-        Parameters
-        ----------
-        fp : an open DicomFileLike object, at start of file
-        force : boolean
-            Force reading of data. See ``read_file`` for
-             more parameter info.
-
-        Adds flags to fp: Big/Little-endian & Implicit/Explicit VR
-        """
-        self.fp = fp
-        self.stop_when = stop_when
-        self.preamble = preamble = read_preamble(fp, force)
-        self.has_header = has_header = (preamble is not None)
-        self.file_meta_info = Dataset()
-
-        if has_header:
-            self.file_meta_info = file_meta_info = _read_file_meta_info(fp)
-            transfer_syntax = file_meta_info.TransferSyntaxUID
-
-            if transfer_syntax == pydicom.uid.ExplicitVRLittleEndian:
-                self._is_implicit_VR = False
-                self._is_little_endian = True
-
-            elif transfer_syntax == pydicom.uid.ImplicitVRLittleEndian:
-                self._is_implicit_VR = True
-                self._is_little_endian = True
-
-            elif transfer_syntax == pydicom.uid.ExplicitVRBigEndian:
-                self._is_implicit_VR = False
-                self._is_little_endian = False
-
-            elif transfer_syntax == pydicom.uid.DeflatedExplicitVRLittleEndian:
-                # See PS3.6-2008 A.5 (p 71) -- when written, the entire dataset
-                # following the file metadata was prepared the normal way,
-                # then "deflate" compression applied.
-                # All that is needed here is to decompress and then
-                # use as normal in a file-like object
-                zipped = fp.read()
-
-                # -MAX_WBITS part is from comp.lang.python answer:
-                # groups.google.com/group/comp.lang.python/msg/e95b3b38a71e6799
-                unzipped = zlib.decompress(zipped, -zlib.MAX_WBITS)
-
-                # a file-like object
-                fp = BytesIO(unzipped)
-
-                # point to new object
-                self.fp = fp
-                self._is_implicit_VR = False
-                self._is_little_endian = True
-
-            else:
-                # Any other syntax should be Explicit VR Little Endian,
-                # e.g. all Encapsulated (JPEG etc) are ExplVR-LE
-                # by Standard PS 3.5-2008 A.4 (p63)
-                self._is_implicit_VR = False
-                self._is_little_endian = True
-
-        else:  # no header -- make assumptions
-            fp.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian
-            self._is_little_endian = True
-            self._is_implicit_VR = True
-
-        impl_expl = ("Explicit", "Implicit")[self._is_implicit_VR]
-        big_little = ("Big", "Little")[self._is_little_endian]
-        logger.debug("Using {0:s} VR, {1:s} Endian transfer syntax".format(
-                     impl_expl, big_little))
-
-    def __iter__(self):
-        tags = sorted(self.file_meta_info.keys())
-        for tag in tags:
-            yield self.file_meta_info[tag]
-
-        for data_element in data_element_generator(self.fp,
-                                                   self._is_implicit_VR,
-                                                   self._is_little_endian,
-                                                   stop_when=self.stop_when):
-            yield data_element
-
-
 def data_element_generator(fp,
                            is_implicit_VR,
                            is_little_endian,
diff --git a/pydicom/util/fixes.py b/pydicom/util/fixes.py
new file mode 100644
index 000000000..6d2eed258
--- /dev/null
+++ b/pydicom/util/fixes.py
@@ -0,0 +1,137 @@
+"""Compatibility fixes for older version of python."""
+
+# Authors : Guillaume Lemaitre <g.lemaitre58@mgail.com>
+# Copyright 2008-2017 pydicom authors. See LICENSE file for details.
+
+import sys
+
+from datetime import datetime, tzinfo, timedelta
+
+if sys.version_info[0] < 3:
+    class timezone(tzinfo):
+        """Backport of datetime.timezone.
+
+        Notes
+        -----
+        Backport of datetime.timezone for Python 2.7, from Python 3.6
+        documentation (https://tinyurl.com/z4cegu9), copyright Python Software
+        Foundation (https://docs.python.org/3/license.html)
+
+        """
+        __slots__ = '_offset', '_name'
+
+        # Sentinel value to disallow None
+        _Omitted = object()
+
+        def __new__(cls, offset, name=_Omitted):
+            if not isinstance(offset, timedelta):
+                raise TypeError("offset must be a timedelta")
+            if name is cls._Omitted:
+                if not offset:
+                    return cls.utc
+                name = None
+            elif not isinstance(name, str):
+                raise TypeError("name must be a string")
+            if not cls._minoffset <= offset <= cls._maxoffset:
+                raise ValueError("offset must be a timedelta "
+                                 "strictly between -timedelta(hours=24) and "
+                                 "timedelta(hours=24).")
+            if (offset.microseconds != 0 or offset.seconds % 60 != 0):
+                raise ValueError("offset must be a timedelta "
+                                 "representing a whole number of minutes")
+            return cls._create(offset, name)
+
+        @classmethod
+        def _create(cls, offset, name=None):
+            self = tzinfo.__new__(cls)
+            self._offset = offset
+            self._name = name
+            return self
+
+        def __getinitargs__(self):
+            """pickle support"""
+            if self._name is None:
+                return (self._offset,)
+            return (self._offset, self._name)
+
+        def __eq__(self, other):
+            if type(other) != timezone:
+                return False
+            return self._offset == other._offset
+
+        def __lt__(self, other):
+            raise TypeError("'<' not supported between instances of"
+                            " 'datetime.timezone' and 'datetime.timezone'")
+
+        def __hash__(self):
+            return hash(self._offset)
+
+        def __repr__(self):
+            if self is self.utc:
+                return '%s.%s.utc' % (self.__class__.__module__,
+                                      self.__class__.__name__)
+            if self._name is None:
+                return "%s.%s(%r)" % (self.__class__.__module__,
+                                      self.__class__.__name__,
+                                      self._offset)
+            return "%s.%s(%r, %r)" % (self.__class__.__module__,
+                                      self.__class__.__name__,
+                                      self._offset, self._name)
+
+        def __str__(self):
+            return self.tzname(None)
+
+        def utcoffset(self, dt):
+            if isinstance(dt, datetime) or dt is None:
+                return self._offset
+            raise TypeError("utcoffset() argument must be a datetime instance"
+                            " or None")
+
+        def tzname(self, dt):
+            if isinstance(dt, datetime) or dt is None:
+                if self._name is None:
+                    return self._name_from_offset(self._offset)
+                return self._name
+            raise TypeError("tzname() argument must be a datetime instance"
+                            " or None")
+
+        def dst(self, dt):
+            if isinstance(dt, datetime) or dt is None:
+                return None
+            raise TypeError("dst() argument must be a datetime instance"
+                            " or None")
+
+        def fromutc(self, dt):
+            if isinstance(dt, datetime):
+                if dt.tzinfo is not self:
+                    raise ValueError("fromutc: dt.tzinfo "
+                                     "is not self")
+                return dt + self._offset
+            raise TypeError("fromutc() argument must be a datetime instance"
+                            " or None")
+
+        _maxoffset = timedelta(hours=23, minutes=59)
+        _minoffset = -_maxoffset
+
+        @staticmethod
+        def _name_from_offset(delta):
+            if not delta:
+                return 'UTC'
+            if delta < timedelta(0):
+                sign = '-'
+                delta = -delta
+            else:
+                sign = '+'
+            hours, rest = divmod(delta.total_seconds(), 3600)
+            hours = int(hours)
+            minutes = rest // timedelta(minutes=1).total_seconds()
+            minutes = int(minutes)
+            return 'UTC{}{:02d}:{:02d}'.format(sign, hours, minutes)
+
+    timezone.utc = timezone._create(timedelta(0))
+    timezone.min = timezone._create(timezone._minoffset)
+    timezone.max = timezone._create(timezone._maxoffset)
+    _EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
+
+else:
+    from datetime import timezone
diff --git a/pydicom/valuerep.py b/pydicom/valuerep.py
index f217e3eee..3f07ef740 100644
--- a/pydicom/valuerep.py
+++ b/pydicom/valuerep.py
@@ -8,18 +8,13 @@ from copy import deepcopy
 from decimal import Decimal
 import re
 
+from datetime import (date, datetime, time, timedelta)
+
 # don't import datetime_conversion directly
 from pydicom import config
 from pydicom import compat
 from pydicom.multival import MultiValue
-
-from datetime import (date, datetime, time)
-
-have_dateutil = True
-try:
-    from dateutil.tz import tzoffset
-except ImportError:
-    have_dateutil = False
+from pydicom.util.fixes import timezone
 
 # can't import from charset or get circular import
 default_encoding = "iso8859"
@@ -140,6 +135,10 @@ class DT(datetime):
     def __reduce_ex__(self, protocol):
         return super(DT, self).__reduce__() + (self.__getstate__(), )
 
+    @staticmethod
+    def _utc_offset(offset, name):
+        return timezone(timedelta(seconds=offset), name)
+
     def __new__(cls, val):
         """Create an instance of DT object.
 
@@ -187,14 +186,7 @@ class DT(datetime):
                     offset = (offset1 + offset2) * 60
                     if tz_match[0] == '-':
                         offset = -offset
-                    if not have_dateutil:
-                        msg = "The python-dateutil package is required"
-                        msg += "to convert dates/times to datetime objects. "
-                        msg += "\nPlease install python-dateutil or set "
-                        msg += "pydicom.config.datetime_conversion = False"
-
-                        raise ImportError(msg)
-                    tzinfo = tzoffset(tz_match, offset)
+                    tzinfo = cls._utc_offset(offset, tz_match)
                 else:
                     tzinfo = None
                 val = super(DT,


Test patch:
diff --git a/pydicom/tests/test_filewriter.py b/pydicom/tests/test_filewriter.py
index 4d7814ed0..f7f149dd6 100644
--- a/pydicom/tests/test_filewriter.py
+++ b/pydicom/tests/test_filewriter.py
@@ -2,10 +2,11 @@
 """unittest cases for pydicom.filewriter module"""
 
 from copy import deepcopy
-from datetime import date, datetime, time
+from datetime import date, datetime, time, timedelta
 from io import BytesIO
 import os
 import os.path
+
 from struct import unpack
 from tempfile import TemporaryFile
 
@@ -25,14 +26,9 @@ from pydicom.sequence import Sequence
 from pydicom.uid import (ImplicitVRLittleEndian, ExplicitVRBigEndian,
                          PYDICOM_IMPLEMENTATION_UID)
 from pydicom.util.hexutil import hex2bytes, bytes2hex
+from pydicom.util.fixes import timezone
 from pydicom.valuerep import DA, DT, TM
 import unittest
-
-have_dateutil = True
-try:
-    from dateutil.tz import tzoffset
-except ImportError:
-    have_dateutil = False
 try:
     unittest.TestCase.assertSequenceEqual
 except AttributeError:
@@ -83,7 +79,6 @@ class WriteFileTests(unittest.TestCase):
 
     def compare(self, in_filename, decode=False):
         """Read Dataset from in_filename, write to file, compare"""
-
         with open(in_filename, 'rb') as f:
             bytes_in = BytesIO(f.read())
             bytes_in.seek(0)
@@ -96,7 +91,7 @@ class WriteFileTests(unittest.TestCase):
         bytes_out.seek(0)
         same, pos = bytes_identical(bytes_in.getvalue(), bytes_out.getvalue())
         self.assertTrue(same, "Read bytes is not identical to written bytes - "
-                              "first difference at 0x%x" % pos)
+                        "first difference at 0x%x" % pos)
 
     def compare_bytes(self, bytes_in, bytes_out):
         """Compare two bytestreams for equality"""
@@ -185,10 +180,9 @@ class WriteFileTests(unittest.TestCase):
         self.assertRaises(ValueError, ds.save_as, self.file_out)
 
 
-@unittest.skipIf(not have_dateutil,
-                 "Need python-dateutil installed for these tests")
 class ScratchWriteDateTimeTests(WriteFileTests):
     """Write and reread simple or multi-value DA/DT/TM data elements"""
+
     def setUp(self):
         config.datetime_conversion = True
         self.file_out = TemporaryFile('w+b')
@@ -200,10 +194,10 @@ class ScratchWriteDateTimeTests(WriteFileTests):
         """Write DA/DT/TM data elements.........."""
         multi_DA_expected = (date(1961, 8, 4), date(1963, 11, 22))
         DA_expected = date(1961, 8, 4)
-        tzinfo = tzoffset('-0600', -21600)
-        multi_DT_expected = (datetime(1961, 8, 4),
-                             datetime(1963, 11, 22, 12, 30, 0, 0,
-                                      tzoffset('-0600', -21600)))
+        tzinfo = timezone(timedelta(seconds=-21600), '-0600')
+        multi_DT_expected = (datetime(1961, 8, 4), datetime(
+            1963, 11, 22, 12, 30, 0, 0,
+            timezone(timedelta(seconds=-21600), '-0600')))
         multi_TM_expected = (time(1, 23, 45), time(11, 11, 11))
         TM_expected = time(11, 11, 11, 1)
         ds = read_file(datetime_name)
@@ -217,7 +211,6 @@ class ScratchWriteDateTimeTests(WriteFileTests):
         self.file_out.seek(0)
         # Now read it back in and check the values are as expected
         ds = read_file(self.file_out)
-
         self.assertSequenceEqual(multi_DA_expected, ds.CalibrationDate)
         self.assertEqual(DA_expected, ds.DateOfLastCalibration)
         self.assertSequenceEqual(multi_DT_expected, ds.ReferencedDateTime)
@@ -227,6 +220,7 @@ class ScratchWriteDateTimeTests(WriteFileTests):
 
 class WriteDataElementTests(unittest.TestCase):
     """Attempt to write data elements has the expected behaviour"""
+
     def setUp(self):
         # Create a dummy (in memory) file to write to
         self.f1 = DicomBytesIO()
@@ -368,12 +362,10 @@ class WriteDataElementTests(unittest.TestCase):
         # VR (OD): \x4f\x44
         # Reserved: \x00\x00
         # Length (16): \x10\x00\x00\x00
-
         #             | Tag          | VR    |
         ref_bytes = b'\x70\x00\x0d\x15\x4f\x44' \
                     b'\x00\x00\x10\x00\x00\x00' + bytestring
         #             |Rsrvd |   Length      |    Value ->
-
         self.assertEqual(encoded_elem, ref_bytes)
 
         # Empty data
@@ -416,12 +408,10 @@ class WriteDataElementTests(unittest.TestCase):
         # VR (OL): \x4f\x4c
         # Reserved: \x00\x00
         # Length (12): 0c 00 00 00
-
         #             | Tag          | VR    |
         ref_bytes = b'\x66\x00\x29\x01\x4f\x4c' \
                     b'\x00\x00\x0c\x00\x00\x00' + bytestring
         #             |Rsrvd |   Length      |    Value ->
-
         self.assertEqual(encoded_elem, ref_bytes)
 
         # Empty data
@@ -577,6 +567,7 @@ class WriteDataElementTests(unittest.TestCase):
 
 class TestCorrectAmbiguousVR(unittest.TestCase):
     """Test correct_ambiguous_vr."""
+
     def test_pixel_representation_vm_one(self):
         """Test correcting VM 1 elements which require PixelRepresentation."""
         ref_ds = Dataset()
@@ -783,6 +774,7 @@ class TestCorrectAmbiguousVR(unittest.TestCase):
 
 class WriteAmbiguousVRTests(unittest.TestCase):
     """Attempt to write data elements with ambiguous VR."""
+
     def setUp(self):
         # Create a dummy (in memory) file to write to
         self.fp = DicomBytesIO()
@@ -838,6 +830,7 @@ class WriteAmbiguousVRTests(unittest.TestCase):
 
 class ScratchWriteTests(unittest.TestCase):
     """Simple dataset from scratch, written in all endian/VR combinations"""
+
     def setUp(self):
         # Create simple dataset for all tests
         ds = Dataset()
@@ -857,7 +850,7 @@ class ScratchWriteTests(unittest.TestCase):
         sub_ds.ContourSequence = Sequence((subitem1, subitem2))
 
         # Now the top-level sequence
-        ds.ROIContourSequence = Sequence((sub_ds,))  # Comma to make one-tuple
+        ds.ROIContourSequence = Sequence((sub_ds, ))  # Comma to make one-tuple
 
         # Store so each test can use it
         self.ds = ds
@@ -876,7 +869,6 @@ class ScratchWriteTests(unittest.TestCase):
         # print "std    :", bytes2hex(std)
         # print "written:", bytes2hex(bytes_written)
         same, pos = bytes_identical(std, bytes_written)
-
         self.assertTrue(same,
                         "Writing from scratch unexpected result "
                         "- 1st diff at 0x%x" % pos)
@@ -968,7 +960,6 @@ class TestWriteToStandard(object):
             pass
         for elem in ref_ds.iterall():
             pass
-
         for ref_elem, test_elem in zip(ref_ds.file_meta, ds.file_meta):
             assert ref_elem == test_elem
 
@@ -1000,7 +991,6 @@ class TestWriteToStandard(object):
         del ds.file_meta.TransferSyntaxUID
         ds.is_implicit_VR = False
         ds.is_little_endian = True
-
         with pytest.raises(ValueError):
             ds.save_as(DicomBytesIO(), write_like_original=False)
         assert 'TransferSyntaxUID' not in ds.file_meta
@@ -1011,7 +1001,6 @@ class TestWriteToStandard(object):
         ds = read_file(rtplan_name)
         ds.is_implicit_VR = True
         ds.is_little_endian = False
-
         with pytest.raises(NotImplementedError):
             ds.save_as(DicomBytesIO(), write_like_original=False)
 
@@ -1274,6 +1263,7 @@ class TestWriteFileMetaInfoToStandard(object):
 
 class TestWriteNonStandard(unittest.TestCase):
     """Unit tests for writing datasets not to the DICOM standard."""
+
     def setUp(self):
         """Create an empty file-like for use in testing."""
         self.fp = DicomBytesIO()
@@ -1610,6 +1600,7 @@ class TestWriteNonStandard(unittest.TestCase):
 
 class TestWriteFileMetaInfoNonStandard(unittest.TestCase):
     """Unit tests for writing File Meta Info not to the DICOM standard."""
+
     def setUp(self):
         """Create an empty file-like for use in testing."""
         self.fp = DicomBytesIO()
@@ -1635,8 +1626,12 @@ class TestWriteFileMetaInfoNonStandard(unittest.TestCase):
         meta.MediaStorageSOPInstanceUID = '1.2'
         meta.TransferSyntaxUID = '1.3'
         meta.ImplementationClassUID = '1.4'
-        self.assertRaises(ValueError, write_file_meta_info, self.fp, meta,
-                          enforce_standard=False)
+        self.assertRaises(
+            ValueError,
+            write_file_meta_info,
+            self.fp,
+            meta,
+            enforce_standard=False)
 
     def test_missing_elements(self):
         """Test that missing required elements doesn't raise ValueError."""
diff --git a/pydicom/tests/test_fixes.py b/pydicom/tests/test_fixes.py
new file mode 100644
index 000000000..124461c15
--- /dev/null
+++ b/pydicom/tests/test_fixes.py
@@ -0,0 +1,242 @@
+"""Test fixes modules"""
+
+# Authors : Guillaume Lemaitre <g.lemaitre58@mgail.com>
+# License : MIT
+
+import unittest
+import copy
+import pickle
+
+import datetime as datetime_module
+from datetime import datetime
+from datetime import timedelta
+from datetime import tzinfo
+
+import pydicom as pydicom_module
+from pydicom.util.fixes import timezone
+
+pickle_choices = [(pickle, pickle, proto)
+                  for proto in range(pickle.HIGHEST_PROTOCOL + 1)]
+
+ZERO = timedelta(0)
+HOUR = timedelta(hours=1)
+# In the US, DST starts at 2am (standard time) on the first Sunday in April.
+DSTSTART = datetime(1, 4, 1, 2)
+# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct,
+# which is the first Sunday on or after Oct 25.  Because we view 1:MM as
+# being standard time on that day, there is no spelling in local time of
+# the last hour of DST (that's 1:MM DST, but 1:MM is taken as standard time).
+DSTEND = datetime(1, 10, 25, 1)
+
+
+def first_sunday_on_or_after(dt):
+    days_to_go = 6 - dt.weekday()
+    if days_to_go:
+        dt += timedelta(days_to_go)
+    return dt
+
+
+class USTimeZone(tzinfo):
+
+    def __init__(self, hours, reprname, stdname, dstname):
+        self.stdoffset = timedelta(hours=hours)
+        self.reprname = reprname
+        self.stdname = stdname
+        self.dstname = dstname
+
+    def __repr__(self):
+        return self.reprname
+
+    def tzname(self, dt):
+        if self.dst(dt):
+            return self.dstname
+        else:
+            return self.stdname
+
+    def utcoffset(self, dt):
+        return self.stdoffset + self.dst(dt)
+
+    def dst(self, dt):
+        if dt is None or dt.tzinfo is None:
+            # An exception instead may be sensible here, in one or more of
+            # the cases.
+            return ZERO
+        assert dt.tzinfo is self
+
+        # Find first Sunday in April.
+        start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year))
+        assert start.weekday() == 6 and start.month == 4 and start.day <= 7
+
+        # Find last Sunday in October.
+        end = first_sunday_on_or_after(DSTEND.replace(year=dt.year))
+        assert end.weekday() == 6 and end.month == 10 and end.day >= 25
+
+        # Can't compare naive to aware objects, so strip the timezone from
+        # dt first.
+        if start <= dt.replace(tzinfo=None) < end:
+            return HOUR
+        else:
+            return ZERO
+
+
+Eastern = USTimeZone(-5, "Eastern",  "EST", "EDT")
+
+
+class TestTimeZone(unittest.TestCase):
+    """Backport of datetime.timezone tests.
+
+    Notes
+    -----
+    Backport of datetime.timezone for Python 2.7, from Python 3.6
+    documentation (https://tinyurl.com/z4cegu9), copyright Python Software
+    Foundation (https://docs.python.org/3/license.html)
+
+    """
+
+    def setUp(self):
+        self.ACDT = timezone(timedelta(hours=9.5), 'ACDT')
+        self.EST = timezone(-timedelta(hours=5), 'EST')
+        self.DT = datetime(2010, 1, 1)
+
+    def test_str(self):
+        for tz in [self.ACDT, self.EST, timezone.utc,
+                   timezone.min, timezone.max]:
+            self.assertEqual(str(tz), tz.tzname(None))
+
+    def test_repr(self):
+        datetime = datetime_module
+        pydicom = pydicom_module
+        for tz in [self.ACDT, self.EST, timezone.utc,
+                   timezone.min, timezone.max]:
+            # test round-trip
+            tzrep = repr(tz)
+            self.assertEqual(tz, eval(tzrep))
+
+    def test_class_members(self):
+        limit = timedelta(hours=23, minutes=59)
+        self.assertEqual(timezone.utc.utcoffset(None), ZERO)
+        self.assertEqual(timezone.min.utcoffset(None), -limit)
+        self.assertEqual(timezone.max.utcoffset(None), limit)
+
+    def test_constructor(self):
+        self.assertIs(timezone.utc, timezone(timedelta(0)))
+        self.assertIsNot(timezone.utc, timezone(timedelta(0), 'UTC'))
+        self.assertEqual(timezone.utc, timezone(timedelta(0), 'UTC'))
+        # invalid offsets
+        for invalid in [timedelta(microseconds=1), timedelta(1, 1),
+                        timedelta(seconds=1), timedelta(1), -timedelta(1)]:
+            self.assertRaises(ValueError, timezone, invalid)
+            self.assertRaises(ValueError, timezone, -invalid)
+
+        with self.assertRaises(TypeError):
+            timezone(None)
+        with self.assertRaises(TypeError):
+            timezone(42)
+        with self.assertRaises(TypeError):
+            timezone(ZERO, None)
+        with self.assertRaises(TypeError):
+            timezone(ZERO, 42)
+        with self.assertRaises(TypeError):
+            timezone(ZERO, 'ABC', 'extra')
+
+    def test_inheritance(self):
+        self.assertIsInstance(timezone.utc, tzinfo)
+        self.assertIsInstance(self.EST, tzinfo)
+
+    def test_utcoffset(self):
+        dummy = self.DT
+        for h in [0, 1.5, 12]:
+            offset = h * HOUR.total_seconds()
+            offset = timedelta(seconds=offset)
+            self.assertEqual(offset, timezone(offset).utcoffset(dummy))
+            self.assertEqual(-offset, timezone(-offset).utcoffset(dummy))
+
+        with self.assertRaises(TypeError):
+            self.EST.utcoffset('')
+        with self.assertRaises(TypeError):
+            self.EST.utcoffset(5)
+
+    def test_dst(self):
+        self.assertIsNone(timezone.utc.dst(self.DT))
+
+        with self.assertRaises(TypeError):
+            self.EST.dst('')
+        with self.assertRaises(TypeError):
+            self.EST.dst(5)
+
+    def test_tzname(self):
+        self.assertTrue('UTC' in timezone.utc.tzname(None))
+        self.assertTrue('UTC' in timezone(ZERO).tzname(None))
+        self.assertEqual('UTC-05:00', timezone(timedelta(
+            hours=-5)).tzname(None))
+        self.assertEqual('UTC+09:30', timezone(timedelta(
+            hours=9.5)).tzname(None))
+        self.assertEqual('UTC-00:01',
+                         timezone(timedelta(minutes=-1)).tzname(None))
+        self.assertEqual('XYZ', timezone(-5 * HOUR, 'XYZ').tzname(None))
+
+        with self.assertRaises(TypeError):
+            self.EST.tzname('')
+        with self.assertRaises(TypeError):
+            self.EST.tzname(5)
+
+    def test_fromutc(self):
+        with self.assertRaises(ValueError):
+            timezone.utc.fromutc(self.DT)
+        with self.assertRaises(TypeError):
+            timezone.utc.fromutc('not datetime')
+        for tz in [self.EST, self.ACDT, Eastern]:
+            utctime = self.DT.replace(tzinfo=tz)
+            local = tz.fromutc(utctime)
+            self.assertEqual(local - utctime, tz.utcoffset(local))
+            self.assertEqual(local,
+                             self.DT.replace(tzinfo=timezone.utc))
+
+    def test_comparison(self):
+        self.assertNotEqual(timezone(ZERO), timezone(HOUR))
+        self.assertEqual(timezone(HOUR), timezone(HOUR))
+        self.assertEqual(timezone(-5 * HOUR), timezone(-5 * HOUR, 'EST'))
+        with self.assertRaises(TypeError):
+            timezone(ZERO) < timezone(ZERO)
+        self.assertIn(timezone(ZERO), {timezone(ZERO)})
+        self.assertTrue(timezone(ZERO) is not None)
+        self.assertFalse(timezone(ZERO) is None)
+        self.assertNotEqual(timezone(ZERO), 'random')
+
+    def test_aware_datetime(self):
+        # test that timezone instances can be used by datetime
+        t = datetime(1, 1, 1)
+        for tz in [timezone.min, timezone.max, timezone.utc]:
+            print(tz.tzname(t))
+            self.assertEqual(tz.tzname(t),
+                             t.replace(tzinfo=tz).tzname())
+            self.assertEqual(tz.utcoffset(t),
+                             t.replace(tzinfo=tz).utcoffset())
+            self.assertEqual(tz.dst(t),
+                             t.replace(tzinfo=tz).dst())
+
+    def test_pickle(self):
+        for tz in self.ACDT, self.EST, timezone.min, timezone.max:
+            for pickler, unpickler, proto in pickle_choices:
+                tz_copy = unpickler.loads(pickler.dumps(tz, proto))
+                self.assertEqual(tz_copy, tz)
+        tz = timezone.utc
+        for pickler, unpickler, proto in pickle_choices:
+            tz_copy = unpickler.loads(pickler.dumps(tz, proto))
+            self.assertIs(tz_copy, tz)
+
+    def test_copy(self):
+        for tz in self.ACDT, self.EST, timezone.min, timezone.max:
+            tz_copy = copy.copy(tz)
+            self.assertEqual(tz_copy, tz)
+        tz = timezone.utc
+        tz_copy = copy.copy(tz)
+        self.assertIs(tz_copy, tz)
+
+    def test_deepcopy(self):
+        for tz in self.ACDT, self.EST, timezone.min, timezone.max:
+            tz_copy = copy.deepcopy(tz)
+            self.assertEqual(tz_copy, tz)
+        tz = timezone.utc
+        tz_copy = copy.deepcopy(tz)
+        self.assertIs(tz_copy, tz)
diff --git a/pydicom/tests/test_valuerep.py b/pydicom/tests/test_valuerep.py
index 78407b6d7..cd4e0a7fb 100644
--- a/pydicom/tests/test_valuerep.py
+++ b/pydicom/tests/test_valuerep.py
@@ -20,15 +20,10 @@ import platform
 from pydicom.compat import in_py2
 from pydicom import config
 from pydicom import valuerep
+from pydicom.util.fixes import timezone
 from pydicom.data import get_testdata_files
 import unittest
 
-have_dateutil = True
-try:
-    from dateutil.tz import tzoffset
-except ImportError:
-    have_dateutil = False
-
 try:
     unittest.skipIf
 except AttributeError:
@@ -316,8 +311,6 @@ class PersonNametests(unittest.TestCase):
         self.assertFalse(pn != "John^Doe", msg)
 
 
-@unittest.skipIf(not have_dateutil,
-                 "Need python-dateutil installed for these tests")
 class DateTimeTests(unittest.TestCase):
     """Unit tests for DA, DT, TM conversion to datetime objects"""
 
@@ -377,7 +370,7 @@ class DateTimeTests(unittest.TestCase):
         dicom_datetime = "196108041924-1000"
         dt = valuerep.DT(dicom_datetime)
         datetime_datetime = datetime(1961, 8, 4, 19, 24, 0, 0,
-                                     tzoffset(None, -10 * 3600))
+                                     timezone(timedelta(seconds=-10 * 3600)))
         self.assertEqual(dt, datetime_datetime,
                          ("DT {0} not equal to datetime {1}"
                           .format(dicom_datetime,