lists.arthurdejong.org
RSS feed

python-stdnum branch master updated. 2.2-6-g8a212c7

[Date Prev][Date Next] [Thread Prev][Thread Next]

python-stdnum branch master updated. 2.2-6-g8a212c7



This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-stdnum".

The branch, master has been updated
       via  8a212c7cd1324f326ed30f61b7b2ac43cdf69572 (commit)
      from  7662137d48daddf3e6f0e79a69d24197c9761d1c (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://arthurdejong.org/git/python-stdnum/commit/?id=8a212c7cd1324f326ed30f61b7b2ac43cdf69572

commit 8a212c7cd1324f326ed30f61b7b2ac43cdf69572
Author: Vincent Gao <gaobing1230@gmail.com>
Date:   Tue Jun 16 12:47:18 2026 +0200

    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 https://github.com/arthurdejong/python-stdnum/pull/498

diff --git a/stdnum/gs1_128.py b/stdnum/gs1_128.py
index 001dd58..03cff8a 100644
--- a/stdnum/gs1_128.py
+++ b/stdnum/gs1_128.py
@@ -122,8 +122,15 @@ def _encode_date(fmt: str, value: object) -> str:
         # Format date in different formats
         if fmt in ('N6', 'N6..12', 'N6[+N6]'):
             return value.strftime('%y%m%d')
+        elif fmt == 'N8':
+            # Date with a four-digit year (YYYYMMDD), e.g. AI 7250 (DOB).
+            return value.strftime('%Y%m%d')
         elif fmt == 'N10':
             return value.strftime('%y%m%d%H%M')
+        elif fmt == 'N12':
+            # Date and time with a four-digit year (YYYYMMDDhhmm), e.g. AI 7251
+            # (DOB TIME).
+            return value.strftime('%Y%m%d%H%M')
         elif fmt in ('N6+N..4', 'N6[+N..4]', 'N6[+N4]'):
             value = value.strftime('%y%m%d%H%M')
             if value.endswith('00'):
@@ -185,7 +192,14 @@ def _decode_decimal(ai: str, fmt: str, value: str) -> 
decimal.Decimal | tuple[st
 
 def _decode_date(fmt: str, value: str) -> datetime.date | datetime.datetime | 
tuple[datetime.date, datetime.date]:
     """Decode the specified date value given the fmt."""
-    if len(value) == 6:
+    if fmt == 'N8':
+        # Date with a four-digit year (YYYYMMDD), e.g. AI 7250 (DOB).
+        return datetime.datetime.strptime(value, '%Y%m%d').date()
+    elif fmt == 'N12':
+        # Date and time with a four-digit year (YYYYMMDDhhmm), e.g. AI 7251
+        # (DOB TIME). This is a single datetime, not two YYMMDD dates.
+        return datetime.datetime.strptime(value, '%Y%m%d%H%M')
+    elif len(value) == 6:
         if value[4:] == '00':
             # When day == '00', it must be interpreted as last day of month
             date = datetime.datetime.strptime(value[:4], '%y%m')
@@ -196,7 +210,7 @@ def _decode_date(fmt: str, value: str) -> datetime.date | 
datetime.datetime | tu
             return date.date()
         else:
             return datetime.datetime.strptime(value, '%y%m%d').date()
-    elif len(value) == 12 and fmt in ('N12', 'N6..12', 'N6[+N6]'):
+    elif len(value) == 12 and fmt in ('N6..12', 'N6[+N6]'):
         return (_decode_date('N6', value[:6]), _decode_date('N6', value[6:]))  
# type: ignore[return-value]
     else:
         # Other lengths are interpreted as variable-length datetime values
diff --git a/tests/test_gs1_128.doctest b/tests/test_gs1_128.doctest
index 7036d27..98172f4 100644
--- a/tests/test_gs1_128.doctest
+++ b/tests/test_gs1_128.doctest
@@ -94,6 +94,10 @@ We generate dates in various formats, depending on the AI.
 '(7011)181119'
 >>> gs1_128.encode({'7011': datetime.datetime(2018, 11, 19, 12, 45)}, 
 >>> parentheses=True)
 '(7011)1811191245'
+>>> gs1_128.encode({'7250': datetime.date(1980, 7, 15)}, parentheses=True)  # 
four-digit year
+'(7250)19800715'
+>>> gs1_128.encode({'7251': datetime.datetime(1980, 7, 15, 14, 30)}, 
parentheses=True)
+'(7251)198007151430'
 
 If we try to encode an invalid EAN we will get an error.
 
@@ -154,6 +158,10 @@ We an decode date files from various formats.
 {'7011': datetime.date(2018, 11, 19)}
 >>> pprint.pprint(gs1_128.info('(7011)1811191245'))
 {'7011': datetime.datetime(2018, 11, 19, 12, 45)}
+>>> pprint.pprint(gs1_128.info('(7250)19800715'))
+{'7250': datetime.date(1980, 7, 15)}
+>>> pprint.pprint(gs1_128.info('(7251)198007151430'))
+{'7251': datetime.datetime(1980, 7, 15, 14, 30)}
 
 
 While the compact() function can clean up the number somewhat the validate()

-----------------------------------------------------------------------

Summary of changes:
 stdnum/gs1_128.py          | 18 ++++++++++++++++--
 tests/test_gs1_128.doctest |  8 ++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)


hooks/post-receive
-- 
python-stdnum