Skip to content

Commit 48ee7d5

Browse files
committed
Follow all .strftime("%Y%m%d")s with .zfill(8)
1 parent 3d6bb0b commit 48ee7d5

5 files changed

Lines changed: 31 additions & 9 deletions

File tree

.github/workflows/run_checks_build_and_test.yml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,20 @@ jobs:
5858
matrix:
5959
python-version: [
6060
"3.14",
61+
"3.13",
62+
"3.12",
63+
"3.15-dev",
64+
"3.11",
65+
"3.10",
66+
"3.9",
6167
]
6268
os: [
6369
"ubuntu-24.04",
6470
]
71+
include:
72+
- python-version: "3.14"
73+
- os: "ubuntu-latest"
74+
6575
runs-on: ${{ matrix.os }}
6676
steps:
6777
- uses: actions/setup-python@v6
@@ -73,7 +83,6 @@ jobs:
7383
path: ./Pyshp
7484

7585
- name: "Hypothesis tests"
76-
if:
7786
uses: ./Pyshp/.github/actions/test
7887
with:
7988
extra_args: '-m hypothesis'

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ The Python Shapefile Library (PyShp) reads and writes ESRI Shapefiles in pure Py
88

99
- **Author**: [Joel Lawhead](https://github.com/GeospatialPython)
1010
- **Maintainers**: [James Parrott](https://github.com/JamesParrott) & [Karim Bahgat](https://github.com/karimbahgat)
11-
- **Version**: 3.1.4
12-
- **Date**: 29th June 2026
11+
- **Version**: 3.1.5
12+
- **Date**: 22nd July 2026
1313
- **License**: [MIT](https://github.com/GeospatialPython/pyshp/blob/master/LICENSE.TXT)
1414

1515
## Contents
@@ -93,6 +93,10 @@ part of your geospatial project.
9393

9494
# Version Changes
9595

96+
## 3.1.5
97+
### Bug fix
98+
- Fixed another bug causing dates before the year 1000 to be encoded as less than 8 chars under "%Y%m%d (found by [Thomas Beierlein](https://github.com/GeospatialPython/pyshp/issues/435))
99+
96100
## 3.1.4
97101
### Bug fix
98102
- Fix bug causing dates supplied as length 8 strings of digits to be encoded by the custom encoding, not ascii.

changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
VERSION 3.1.5
2+
2026-07-22
3+
* Fixed another bug causing dates before the year 1000 to be encoded as less than 8 chars under "%Y%m%d (found by [Thomas Beierlein](https://github.com/GeospatialPython/pyshp/issues/435))
4+
15

26
VERSION 3.1.4
37
2026-06-29

src/shapefile.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from __future__ import annotations
1010

11-
__version__ = "3.1.4"
11+
__version__ = "3.1.5"
1212

1313
import abc
1414
import array
@@ -4430,8 +4430,10 @@ def _record(self, record: list[RecordValue]) -> None:
44304430
# date: 8 bytes - date stored as a string in the format YYYYMMDD.
44314431
if isinstance(value, list) and len(value) == 3:
44324432
value = date(*value)
4433-
if isinstance(value, date):
4434-
str_val = value.strftime("%Y%m%d")
4433+
if isinstance(value, date):
4434+
# In Pythons using certain glibc versions.
4435+
# date.strftime does not preppend zeros.
4436+
str_val = value.strftime("%Y%m%d").zfill(8)
44354437
# b"".join(ord(c).to_bytes() for c in s)
44364438
elif value in MISSING:
44374439
str_val = "0" * 8 # QGIS NULL for date type

tests/hypothesis_tests.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ def test_dbf_Field_roundtrips(encoding_and_dbf_field: dict) -> None:
688688

689689
ascii_printable = string.ascii_letters + string.digits + string.punctuation + " "
690690

691+
def date_to_str(d: datetime.date) -> str:
692+
return d.strftime("%Y%m%d").zfill(8)
693+
691694
def record_value_for_field(name: str, field_type: str, size: int, decimal: int, encoding: str):
692695

693696
if field_type == "C":
@@ -715,7 +718,7 @@ def record_value_for_field(name: str, field_type: str, size: int, decimal: int,
715718
if field_type == "L":
716719
return sampled_from([True, False, None])
717720
if field_type == "D":
718-
return one_of(dates(), dates().map(lambda d: d.strftime("%Y%m%d")))
721+
return one_of(dates(), dates().map(date_to_str))
719722

720723
raise ValueError(f"Unsupported: {field_type=}")
721724

@@ -771,9 +774,9 @@ def _assert_reader_matches_expected_records(r, fields, written_records):
771774
decimal = field["decimal"]
772775
if field_type == "D":
773776
if isinstance(expected, datetime.date):
774-
expected = expected.strftime("%Y%m%d")
777+
expected = date_to_str(expected)
775778
if isinstance(actual, datetime.date):
776-
actual = actual.strftime("%Y%m%d")
779+
actual = date_to_str(actual)
777780
elif field_type in ("N", "F") and decimal >= 1:
778781
expected = float(format(expected, f".{decimal}f"))
779782
assert actual == expected, f"{actual=}, {expected=}, {field_type=}, {type(actual)=}, {type(expected)=}"

0 commit comments

Comments
 (0)