lurch: The tests pass, so LGTM.

@willmcgugan Slightly off-topic question, but is there a good reason for the inconsistency of having the RE_LINUX using numbered capture-groups but the RE_WINDOWSNT using named capture-groups?
willmcgugan: @lurch It's been so long, I'd be guessing. But I reckon I copied those regexes from somewhere.
xoriath: So, anything else needed? I don't seem to have merge rights :) 
willmcgugan: Sorry. There is a back log. Plan to clear it soon.

On Mon, 18 May 2020 at 17:18, Morten Engelhardt Olsen <
notifications@github.com> wrote:

> So, anything else needed? I don't seem to have merge rights :)
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <https://github.com/PyFilesystem/pyfilesystem2/pull/396#issuecomment-630290453>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAEHLAM3ZRU4EHB3YBWOJR3RSFNWRANCNFSM4NCXBWJA>
> .
>
-- 
Will McGugan
https://www.willmcgugan.com <http://www.willmcgugan.com>

xoriath: Hihihi, no problem!
richardcooper: I tripped over this bug recently. I'm applying this patch locally and can confirm that it fixes the problem.
althonos: @xoriath sorry to bother after such a long time, could you please update the `CHANGELOG.md` and `CONTRIBUTORS.md` files so that I can merge this ? Thanks!
xoriath: No problem, @althonos , updated the files and rebased to upstream master
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0449d14..7cec240 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
   ensuring `conftest.py` is present, fixes [#364](https://github.com/PyFilesystem/pyfilesystem2/issues/364).
 - Stop patching copy with Python 3.8+ because it already uses sendfile.
 - Fixed crash when CPython's -OO flag is used
+- Fixed error when parsing timestamps from a FTP directory served from a WindowsNT FTP Server, fixes [#395](https://github.com/PyFilesystem/pyfilesystem2/issues/395).
 
 ## [2.4.11] - 2019-09-07
 
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index de54b66..3b3e8c2 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -11,3 +11,4 @@ Many thanks to the following developers for contributing to this project:
 - [Martin Larralde](https://github.com/althonos)
 - [Will McGugan](https://github.com/willmcgugan)
 - [Zmej Serow](https://github.com/zmej-serow)
+- [Morten Engelhardt Olsen](https://github.com/xoriath)
diff --git a/fs/_ftp_parse.py b/fs/_ftp_parse.py
index b50f75e..b503d73 100644
--- a/fs/_ftp_parse.py
+++ b/fs/_ftp_parse.py
@@ -41,7 +41,7 @@ RE_LINUX = re.compile(
 RE_WINDOWSNT = re.compile(
     r"""
     ^
-    (?P<modified>.*(AM|PM))
+    (?P<modified>.*?(AM|PM))
     \s*
     (?P<size>(<DIR>|\d*))
     \s*

fs/_ftp_parse.py fails when parsing directory listing on NT format if folder or filename contains AM or PM
The regex pattern used to parse the directory listing for NT servers uses a greedy (default) pattern when parsing the modified date column. This causes the `(<modified>)` capture group to capture until the last AM or PM, which could be in the file name.

Example file listing that fails:
```
01-29-20  04:11AM       <DIR>          Clock at AM or PM
```
This fails with the following trace
```
  File ".venv\lib\site-packages\fs\ftpfs.py", line 746, in scandir
    if not self.supports_mlst and not self.getinfo(path).is_dir:
  File ".venv\lib\site-packages\fs\ftpfs.py", line 614, in getinfo
    directory = self._read_dir(dir_name)
  File ".venv\lib\site-packages\fs\ftpfs.py", line 495, in _read_dir
    _list = [Info(raw_info) for raw_info in ftp_parse.parse(lines)]
  File ".venv\lib\site-packages\fs\_ftp_parse.py", line 70, in parse
    raw_info = parse_line(line)
  File ".venv\lib\site-packages\fs\_ftp_parse.py", line 81, in parse_line
    return decode_callable(line, match)
  File ".venv\lib\site-packages\fs\_ftp_parse.py", line 163, in decode_windowsnt
    raw_info["details"]["size"] = int(match.group("size"))
ValueError: invalid literal for int() with base 10: ''
```


diff --git a/tests/test_ftp_parse.py b/tests/test_ftp_parse.py
index c649a1f..d0abc05 100644
--- a/tests/test_ftp_parse.py
+++ b/tests/test_ftp_parse.py
@@ -166,6 +166,7 @@ drwxr-xr-x   2 foo-user foo-group         0 Jan  5 11:59 240485
         directory = """\
 11-02-17  02:00AM       <DIR>          docs
 11-02-17  02:12PM       <DIR>          images
+11-02-17  02:12PM       <DIR>          AM to PM
 11-02-17  03:33PM                 9276 logo.gif
 """
         expected = [
@@ -183,6 +184,13 @@ drwxr-xr-x   2 foo-user foo-group         0 Jan  5 11:59 240485
                     "ls": "11-02-17  02:12PM       <DIR>          images"
                 },
             },
+            {
+                "basic": {"is_dir": True, "name": "AM to PM"},
+                "details": {"modified": 1486822320.0, "type": 1},
+                "ftp": {
+                    "ls": "11-02-17  02:12PM       <DIR>          AM to PM"
+                },
+            },
             {
                 "basic": {"is_dir": False, "name": "logo.gif"},
                 "details": {"modified": 1486827180.0, "size": 9276, "type": 2},

pip install -e .
parse_log_pytest
requirements.txt
tox tox-travis pytest pytest-cov pytest-randomly mock pyftpdlib psutil pysendfile
apt-get update apt-get install -y gcc
3.7
requirements-readthedocs.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
certifi @ file:///croot/certifi_1671487769961/work/certifi
coverage==7.2.7
distlib==0.3.9
exceptiongroup==1.2.2
filelock==3.12.2
-e git+https://github.com/PyFilesystem/pyfilesystem2.git@34084cf5d1027d413fff265c93af5b8dc0685ea7#egg=fs
importlib-metadata==6.7.0
iniconfig==2.0.0
mock==5.2.0
packaging==24.0
platformdirs==4.0.0
pluggy==1.2.0
psutil==7.0.0
py==1.11.0
pyftpdlib==2.0.1
pysendfile==2.0.1
pytest==7.4.4
pytest-cov==4.1.0
pytest-randomly==3.12.0
pytz==2025.2
six==1.17.0
tomli==2.0.1
tox==3.28.0
tox-travis==0.13
typing_extensions==4.7.1
virtualenv==20.26.6
zipp==3.15.0

name: pyfilesystem2
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - appdirs==1.4.4
      - coverage==7.2.7
      - distlib==0.3.9
      - exceptiongroup==1.2.2
      - filelock==3.12.2
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - mock==5.2.0
      - packaging==24.0
      - platformdirs==4.0.0
      - pluggy==1.2.0
      - psutil==7.0.0
      - py==1.11.0
      - pyftpdlib==2.0.1
      - pysendfile==2.0.1
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytest-randomly==3.12.0
      - pytz==2025.2
      - six==1.17.0
      - tomli==2.0.1
      - tox==3.28.0
      - tox-travis==0.13
      - typing-extensions==4.7.1
      - virtualenv==20.26.6
      - zipp==3.15.0
prefix: /opt/conda/envs/pyfilesystem2

tests/test_ftp_parse.py::TestFTPParse::test_decode_windowsnt
tests/test_ftp_parse.py::TestFTPParse::test_parse_line tests/test_ftp_parse.py::TestFTPParse::test_parse_time tests/test_ftp_parse.py::TestFTPParse::test_parse tests/test_ftp_parse.py::TestFTPParse::test_decode_linux
CONTRIBUTORS.md fs/_ftp_parse.py CHANGELOG.md
CONTRIBUTORS.md fs/_ftp_parse.py CHANGELOG.md