Patch contains tree patches which was merge to poco at once
and fix "time" issues

1 - fix(Foundation): Timezone: invalidate utcOffset cache when /etc/localtime 
changes

Poco commit 1850dc16aabf5980a490bb1b66086d6695abb823 introduced a
TZInfo cache for the UTC offset to avoid repeated tzset() syscalls.
The cache is invalidated only when the TZ environment variable changes.
However, the TZ variable is process-local: if a different process (e.g.
a timezone configuration daemon or an init script) changes the system
timezone by updating /etc/localtime, the running process is not notified
and its TZ environment variable remains unchanged.

On systems that switch timezone by updating /etc/localtime (a symlink)
without touching the TZ env var, the cache is therefore never invalidated
and Timezone::utcOffset() returns the stale value computed at startup.

Fix by extending cacheTZ()/tzChanged() to also track the inode and
mtime of /etc/localtime via stat(2).  When either changes the cache is
considered stale and reloaded, preserving the performance benefit for
the common case where neither TZ nor /etc/localtime changes between
calls.

2 - fix(Foundation): DateTimeParser: %S consume optional fractional seconds

Parsing ISO 8601 date strings that contain both fractional seconds and a
timezone offset (e.g. "2013-10-07T08:23:19.120-04:00") with the format
"%Y-%m-%dT%H:%M:%S%z" raises a SyntaxException:

  - %S consumes the integer seconds but stops at '.', leaving
    ".120-04:00" unconsumed.
  - %z (parseTZD) is called next but sees '.' and returns without
    consuming anything.
  - The trailing-garbage check then raises SyntaxException.

Extend the %S case to consume and discard an optional fractional-second
suffix ('.' or ',' followed by one or more digits) immediately after
parsing the integer seconds.  This mirrors the existing %s behaviour and
allows %z to see the timezone designator directly, keeping the
trailing-garbage check fully effective for truly invalid input.

3 - test(DateTimeParserTest): add ISO8601 fractional seconds parser test

Add testISO8601FracSeconds to verify that DateTimeParser correctly
handles fractional-second suffixes (dot and comma separated) in
ISO8601_FORMAT strings, and rejects malformed input such as a
bare decimal point with no digits.

Signed-off-by: Andrej Kozemcak <[email protected]>
---
 ...er-trailing-timezone-designators-Tim.patch | 240 ++++++++++++++++++
 meta-oe/recipes-support/poco/poco_1.15.2.bb   |   1 +
 2 files changed, 241 insertions(+)
 create mode 100644 
meta-oe/recipes-support/poco/poco/0004-Fix-DateTimeParser-trailing-timezone-designators-Tim.patch

diff --git 
a/meta-oe/recipes-support/poco/poco/0004-Fix-DateTimeParser-trailing-timezone-designators-Tim.patch
 
b/meta-oe/recipes-support/poco/poco/0004-Fix-DateTimeParser-trailing-timezone-designators-Tim.patch
new file mode 100644
index 0000000000..d2a8666b23
--- /dev/null
+++ 
b/meta-oe/recipes-support/poco/poco/0004-Fix-DateTimeParser-trailing-timezone-designators-Tim.patch
@@ -0,0 +1,240 @@
+From a767d36fed678e874536e33731be6dbcc5fdc5d0 Mon Sep 17 00:00:00 2001
+From: kozemcak <[email protected]>
+Date: Tue, 12 May 2026 16:13:12 +0200
+Subject: [PATCH] Fix: DateTimeParser trailing timezone designators & Timezone
+ UTC offset cache invalidation (#5318)
+
+* fix(Foundation): Timezone: invalidate utcOffset cache when /etc/localtime 
changes
+
+Poco commit 1850dc16aabf5980a490bb1b66086d6695abb823 introduced a
+TZInfo cache for the UTC offset to avoid repeated tzset() syscalls.
+The cache is invalidated only when the TZ environment variable changes.
+However, the TZ variable is process-local: if a different process (e.g.
+a timezone configuration daemon or an init script) changes the system
+timezone by updating /etc/localtime, the running process is not notified
+and its TZ environment variable remains unchanged.
+
+On systems that switch timezone by updating /etc/localtime (a symlink)
+without touching the TZ env var, the cache is therefore never invalidated
+and Timezone::utcOffset() returns the stale value computed at startup.
+
+Fix by extending cacheTZ()/tzChanged() to also track the inode and
+mtime of /etc/localtime via stat(2).  When either changes the cache is
+considered stale and reloaded, preserving the performance benefit for
+the common case where neither TZ nor /etc/localtime changes between
+calls.
+
+Signed-off-by: Andrej Kozemcak <[email protected]>
+
+* fix(Foundation): DateTimeParser: %S consume optional fractional seconds
+
+Parsing ISO 8601 date strings that contain both fractional seconds and a
+timezone offset (e.g. "2013-10-07T08:23:19.120-04:00") with the format
+"%Y-%m-%dT%H:%M:%S%z" raises a SyntaxException:
+
+  - %S consumes the integer seconds but stops at '.', leaving
+    ".120-04:00" unconsumed.
+  - %z (parseTZD) is called next but sees '.' and returns without
+    consuming anything.
+  - The trailing-garbage check then raises SyntaxException.
+
+Extend the %S case to consume and discard an optional fractional-second
+suffix ('.' or ',' followed by one or more digits) immediately after
+parsing the integer seconds.  This mirrors the existing %s behaviour and
+allows %z to see the timezone designator directly, keeping the
+trailing-garbage check fully effective for truly invalid input.
+
+Fix suggested by matejk.
+
+Signed-off-by: Andrej Kozemcak <[email protected]>
+
+* test(DateTimeParserTest): add ISO8601 fractional seconds parser test
+
+Add testISO8601FracSeconds to verify that DateTimeParser correctly
+handles fractional-second suffixes (dot and comma separated) in
+ISO8601_FORMAT strings, and rejects malformed input such as a
+bare decimal point with no digits.
+
+---------
+
+Upstream-Status: Backport [1.15.3, 
https://github.com/pocoproject/poco/commit/b8d2b50774b25a470c5a30fc91bae7cd47c251fa]
+
+Signed-off-by: Andrej Kozemcak <[email protected]>
+Co-authored-by: Andrej Kozemcak <[email protected]>
+---
+ Foundation/include/Poco/DateTimeParser.h      |  6 ++++
+ Foundation/src/DateTimeParser.cpp             | 12 +++++++
+ Foundation/src/Timezone_UNIX.cpp              | 36 ++++++++++++++++++-
+ .../testsuite/src/DateTimeParserTest.cpp      | 32 +++++++++++++++++
+ Foundation/testsuite/src/DateTimeParserTest.h |  1 +
+ 5 files changed, 86 insertions(+), 1 deletion(-)
+
+diff --git a/Foundation/include/Poco/DateTimeParser.h 
b/Foundation/include/Poco/DateTimeParser.h
+index 2d1882d83..e82a934c9 100644
+--- a/Foundation/include/Poco/DateTimeParser.h
++++ b/Foundation/include/Poco/DateTimeParser.h
+@@ -63,6 +63,12 @@ public:
+               /// Throws a SyntaxException if the string cannot be 
successfully parsed.
+               /// Please see DateTimeFormatter::format() for a description of 
the format string.
+               /// Class DateTimeFormat defines format strings for various 
standard date/time formats.
++              ///
++              /// Note: The %S specifier parses whole seconds and then 
silently discards any
++              /// fractional-second suffix of the form '.DDD' or ',DDD' 
(including a bare decimal
++              /// point that is immediately followed by a non-digit is 
treated as a parse error).
++              /// Callers that need the fractional digits captured must use 
%s (millis+micros),
++              /// %i (milliseconds only), %c (centiseconds), or %F (six-digit 
fractional seconds).
+ 
+       static DateTime parse(const std::string& fmt, const std::string& str, 
int& timeZoneDifferential);
+               /// Parses a date and time in the given format from the given 
string.
+diff --git a/Foundation/src/DateTimeParser.cpp 
b/Foundation/src/DateTimeParser.cpp
+index 08b3494ac..c2fe3dfaa 100644
+--- a/Foundation/src/DateTimeParser.cpp
++++ b/Foundation/src/DateTimeParser.cpp
+@@ -243,6 +243,18 @@ void DateTimeParser::parse(const std::string& fmt, const 
std::string& dtStr, Dat
+                               case 'S':
+                                       it = skipNonDigits(it, end);
+                                       second = parseNumberN(dtStr, it, end, 
2);
++                                      // Consume optional fractional seconds 
('.NNN' or ',NNN') so that a
++                                      // subsequent %z specifier can reach 
the timezone designator.
++                                      // A decimal point/comma not followed 
by a digit is an error.
++                                      if (it != end && (*it == '.' || *it == 
','))
++                                      {
++                                              ++it;
++                                              if (it == end || 
!Ascii::isDigit(*it))
++                                              {
++                                                      throw 
SyntaxException("Invalid DateTimeString: " + dtStr + ", missing fractional 
digits");
++                                              }
++                                              it = skipDigits(it, end);
++                                      }
+                                       break;
+                               case 's':
+                                       it = skipNonDigits(it, end);
+diff --git a/Foundation/src/Timezone_UNIX.cpp 
b/Foundation/src/Timezone_UNIX.cpp
+index d1489e72f..3e0d29838 100644
+--- a/Foundation/src/Timezone_UNIX.cpp
++++ b/Foundation/src/Timezone_UNIX.cpp
+@@ -18,6 +18,7 @@
+ #include <ctime>
+ #include <cstdlib>
+ #include <string>
++#include <sys/stat.h>
+ 
+ 
+ namespace Poco {
+@@ -66,13 +67,44 @@ private:
+       {
+               const char* tz = std::getenv("TZ");
+               _cachedTZ = tz ? tz : "";
++              // /etc/localtime is the system-wide zone source (updated by 
timedatectl etc.).
++              // Stat'ing it lets us detect zone changes that don't touch the 
TZ env var; we
++              // don't read its contents — tzset()/libc still resolves the 
actual zone data.
++              cacheLocaltimeStat();
+       }
+ 
+       bool tzChanged() const
+       {
+               const char* tz = std::getenv("TZ");
+               std::string currentTZ = tz ? tz : "";
+-              return currentTZ != _cachedTZ;
++              if (currentTZ != _cachedTZ) return true;
++              return localtimeStatChanged();
++      }
++
++      void cacheLocaltimeStat()
++      {
++              struct stat st{};
++              if (::stat("/etc/localtime", &st) == 0)
++              {
++                      _localtimeIno = st.st_ino;
++                      _localtimeMtime = st.st_mtime;
++              }
++              else
++              {
++                      _localtimeIno = 0;
++                      _localtimeMtime = 0;
++              }
++      }
++
++      bool localtimeStatChanged() const
++      {
++              struct stat st{};
++              if (::stat("/etc/localtime", &st) == 0)
++              {
++                      return st.st_ino != _localtimeIno || st.st_mtime != 
_localtimeMtime;
++              }
++              // /etc/localtime not accessible: treat as changed only if we 
had it before
++              return _localtimeIno != 0;
+       }
+ 
+       static int computeTimeZone()
+@@ -112,6 +144,8 @@ private:
+       std::mutex _mutex;
+       int _tzOffset;
+       std::string _cachedTZ;
++      ino_t _localtimeIno = 0;
++      time_t _localtimeMtime = 0;
+ };
+ 
+ 
+diff --git a/Foundation/testsuite/src/DateTimeParserTest.cpp 
b/Foundation/testsuite/src/DateTimeParserTest.cpp
+index 246a0d531..0742e1e02 100644
+--- a/Foundation/testsuite/src/DateTimeParserTest.cpp
++++ b/Foundation/testsuite/src/DateTimeParserTest.cpp
+@@ -638,6 +638,37 @@ void DateTimeParserTest::testCustom()
+ }
+ 
+ 
++void DateTimeParserTest::testISO8601FracSeconds()
++{
++      // ISO8601_FORMAT uses %S which silently discards a well-formed 
fractional-second
++      // suffix so that the trailing %z can still reach the timezone 
designator.
++      int tzd;
++
++      // Dot-separated fractional seconds with negative timezone offset
++      DateTime dt = DateTimeParser::parse(DateTimeFormat::ISO8601_FORMAT, 
"2013-10-07T08:23:19.120-04:00", tzd);
++      assertTrue (dt.year()   == 2013);
++      assertTrue (dt.month()  == 10);
++      assertTrue (dt.day()    == 7);
++      assertTrue (dt.hour()   == 8);
++      assertTrue (dt.minute() == 23);
++      assertTrue (dt.second() == 19);
++      assertTrue (tzd == -4*3600);
++
++      // Comma-separated fractional seconds (ISO 8601 allows ',' as the 
decimal sign)
++      dt = DateTimeParser::parse(DateTimeFormat::ISO8601_FORMAT, 
"2013-10-07T08:23:19,120-04:00", tzd);
++      assertTrue (dt.year()   == 2013);
++      assertTrue (dt.month()  == 10);
++      assertTrue (dt.day()    == 7);
++      assertTrue (dt.hour()   == 8);
++      assertTrue (dt.minute() == 23);
++      assertTrue (dt.second() == 19);
++      assertTrue (tzd == -4*3600);
++
++      // A bare decimal point not followed by any digit must be rejected
++      testBad(DateTimeFormat::ISO8601_FORMAT, "2013-10-07T08:23:19.-04:00", 
tzd);
++}
++
++
+ void DateTimeParserTest::testGuess()
+ {
+       int tzd;
+@@ -917,6 +948,7 @@ CppUnit::Test* DateTimeParserTest::suite()
+       CppUnit_addTest(pSuite, DateTimeParserTest, testASCTIME);
+       CppUnit_addTest(pSuite, DateTimeParserTest, testSORTABLE);
+       CppUnit_addTest(pSuite, DateTimeParserTest, testCustom);
++      CppUnit_addTest(pSuite, DateTimeParserTest, testISO8601FracSeconds);
+       CppUnit_addTest(pSuite, DateTimeParserTest, testGuess);
+       CppUnit_addTest(pSuite, DateTimeParserTest, testCleanup);
+       CppUnit_addTest(pSuite, DateTimeParserTest, testParseMonth);
+diff --git a/Foundation/testsuite/src/DateTimeParserTest.h 
b/Foundation/testsuite/src/DateTimeParserTest.h
+index f25416971..07f0b6924 100644
+--- a/Foundation/testsuite/src/DateTimeParserTest.h
++++ b/Foundation/testsuite/src/DateTimeParserTest.h
+@@ -34,6 +34,7 @@ public:
+       void testASCTIME();
+       void testSORTABLE();
+       void testCustom();
++      void testISO8601FracSeconds();
+       void testGuess();
+       void testCleanup();
+       void testParseMonth();
diff --git a/meta-oe/recipes-support/poco/poco_1.15.2.bb 
b/meta-oe/recipes-support/poco/poco_1.15.2.bb
index 5a873a1d85..bc3d3f9180 100644
--- a/meta-oe/recipes-support/poco/poco_1.15.2.bb
+++ b/meta-oe/recipes-support/poco/poco_1.15.2.bb
@@ -12,6 +12,7 @@ SRC_URI = 
"git://github.com/pocoproject/poco.git;branch=poco-${PV};protocol=http
            file://0001-cppignore.lnx-Ignore-PKCS12-and-testLaunch-test.patch \
            file://0002-DataTest-disable-testSQLChannel-test.patch \
            file://0003-quill-rdtsc-fallback-for-32-bit-powerpc.patch \
+           
file://0004-Fix-DateTimeParser-trailing-timezone-designators-Tim.patch \
            file://run-ptest \
            "
 SRCREV = "afbb1ab68f29eec7079e2fdfa04b3efdbec6529d"
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#127314): 
https://lists.openembedded.org/g/openembedded-devel/message/127314
Mute This Topic: https://lists.openembedded.org/mt/119589240/21656
Group Owner: [email protected]
Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to