Skip to content

Commit 8a212c7

Browse files
binggao1230arthurdejong
authored andcommitted
Support GS1-128 date AIs with a four-digit year
AI 7250 (DOB, N8 YYYYMMDD) and 7251 (DOB TIME, N12 YYYYMMDDhhmm) use a four-digit year, but _encode_date() and _decode_date() only handled two-digit-year formats. Encoding raised "unsupported format: N8" and decoding raised a bare ValueError: N8 was parsed with '%y%m%d%H' and N12 was mistaken for two YYMMDD dates. Handle N8 and N12 explicitly in both directions and stop treating N12 as a pair of dates (only N6[+N6] / N6..12 encode two dates). Closes #498
1 parent 7662137 commit 8a212c7

2 files changed

Lines changed: 24 additions & 2 deletions

File tree

stdnum/gs1_128.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,15 @@ def _encode_date(fmt: str, value: object) -> str:
122122
# Format date in different formats
123123
if fmt in ('N6', 'N6..12', 'N6[+N6]'):
124124
return value.strftime('%y%m%d')
125+
elif fmt == 'N8':
126+
# Date with a four-digit year (YYYYMMDD), e.g. AI 7250 (DOB).
127+
return value.strftime('%Y%m%d')
125128
elif fmt == 'N10':
126129
return value.strftime('%y%m%d%H%M')
130+
elif fmt == 'N12':
131+
# Date and time with a four-digit year (YYYYMMDDhhmm), e.g. AI 7251
132+
# (DOB TIME).
133+
return value.strftime('%Y%m%d%H%M')
127134
elif fmt in ('N6+N..4', 'N6[+N..4]', 'N6[+N4]'):
128135
value = value.strftime('%y%m%d%H%M')
129136
if value.endswith('00'):
@@ -185,7 +192,14 @@ def _decode_decimal(ai: str, fmt: str, value: str) -> decimal.Decimal | tuple[st
185192

186193
def _decode_date(fmt: str, value: str) -> datetime.date | datetime.datetime | tuple[datetime.date, datetime.date]:
187194
"""Decode the specified date value given the fmt."""
188-
if len(value) == 6:
195+
if fmt == 'N8':
196+
# Date with a four-digit year (YYYYMMDD), e.g. AI 7250 (DOB).
197+
return datetime.datetime.strptime(value, '%Y%m%d').date()
198+
elif fmt == 'N12':
199+
# Date and time with a four-digit year (YYYYMMDDhhmm), e.g. AI 7251
200+
# (DOB TIME). This is a single datetime, not two YYMMDD dates.
201+
return datetime.datetime.strptime(value, '%Y%m%d%H%M')
202+
elif len(value) == 6:
189203
if value[4:] == '00':
190204
# When day == '00', it must be interpreted as last day of month
191205
date = datetime.datetime.strptime(value[:4], '%y%m')
@@ -196,7 +210,7 @@ def _decode_date(fmt: str, value: str) -> datetime.date | datetime.datetime | tu
196210
return date.date()
197211
else:
198212
return datetime.datetime.strptime(value, '%y%m%d').date()
199-
elif len(value) == 12 and fmt in ('N12', 'N6..12', 'N6[+N6]'):
213+
elif len(value) == 12 and fmt in ('N6..12', 'N6[+N6]'):
200214
return (_decode_date('N6', value[:6]), _decode_date('N6', value[6:])) # type: ignore[return-value]
201215
else:
202216
# Other lengths are interpreted as variable-length datetime values

tests/test_gs1_128.doctest

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ We generate dates in various formats, depending on the AI.
9494
'(7011)181119'
9595
>>> gs1_128.encode({'7011': datetime.datetime(2018, 11, 19, 12, 45)}, parentheses=True)
9696
'(7011)1811191245'
97+
>>> gs1_128.encode({'7250': datetime.date(1980, 7, 15)}, parentheses=True) # four-digit year
98+
'(7250)19800715'
99+
>>> gs1_128.encode({'7251': datetime.datetime(1980, 7, 15, 14, 30)}, parentheses=True)
100+
'(7251)198007151430'
97101

98102
If we try to encode an invalid EAN we will get an error.
99103

@@ -154,6 +158,10 @@ We an decode date files from various formats.
154158
{'7011': datetime.date(2018, 11, 19)}
155159
>>> pprint.pprint(gs1_128.info('(7011)1811191245'))
156160
{'7011': datetime.datetime(2018, 11, 19, 12, 45)}
161+
>>> pprint.pprint(gs1_128.info('(7250)19800715'))
162+
{'7250': datetime.date(1980, 7, 15)}
163+
>>> pprint.pprint(gs1_128.info('(7251)198007151430'))
164+
{'7251': datetime.datetime(1980, 7, 15, 14, 30)}
157165

158166

159167
While the compact() function can clean up the number somewhat the validate()

0 commit comments

Comments
 (0)