Skip to content

Commit 191a83a

Browse files
committed
[ptime] fix non-english month abbrev handling
1 parent 12c206d commit 191a83a

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

src/ptimec.hh

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
dst[off_inout] = ch; \
6666
off_inout += 1;
6767

68-
#define ABR_TO_INT(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8))
68+
#define ABR_TO_INT(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8))
6969
#define ABR_TO_INT4(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d)))
7070

7171
inline bool
@@ -153,7 +153,9 @@ ptime_b_int(struct exttm* dst, const char* str, off_t off)
153153
}
154154

155155
#define PTIME_CHECK_b(dst, str, off) \
156-
if (!ptime_b_int(dst, str, off)) { \
156+
if (str[off + 3] == '.' || isalpha(str[off + 3]) \
157+
|| !ptime_b_int(dst, str, off)) \
158+
{ \
157159
off_t tmp_off = off; \
158160
if (!ptime_b_slow(dst, str, tmp_off, len)) { \
159161
off_inout = off; \
@@ -166,7 +168,17 @@ ptime_b_int(struct exttm* dst, const char* str, off_t off)
166168
inline bool
167169
ptime_b(exttm* dst, const char* str, off_t& off_inout, ssize_t len)
168170
{
169-
if (off_inout + 3 < len) {
171+
// fast path to detect english abbreviated months
172+
//
173+
// only detect english abbreviated months if they end at a word
174+
// boundary. if the abbreviated month in the current locale is longer
175+
// than 3 letters, and starts with the same letters as an english locale
176+
// month abbreviation, then the computation of off_inout is incorrect.
177+
//
178+
// Ex: in fr_FR november is `nov.`. Parsing `nov. 29` as `%b %d` fails
179+
// if this fast path is taken as later we will attempt to parse `. 29`
180+
// as ` %d`.
181+
if (off_inout + 3 < len && isspace(str[off_inout + 3])) {
170182
if (ptime_b_int(dst, str, off_inout)) {
171183
off_inout += 3;
172184
return true;

src/ptimec_rt.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ ptime_b_slow(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
4848
zone[zone_len] = '\0';
4949
if ((end_of_date = strptime(zone, "%b", &dst->et_tm)) != NULL) {
5050
off_inout += end_of_date - zone;
51+
// Some formats append a dot, maybe to align a 3 letter abbrev with the
52+
// four letter ones?
53+
if (off_inout + 1 < len && zone[off_inout] == '.') {
54+
off_inout += 1;
55+
}
56+
dst->et_flags |= ETF_MONTH_SET;
5157
return true;
5258
}
5359

test/test_date_time_scanner.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ TEST_CASE("date_time_scanner")
231231
{
232232
const char* en_date = "Jan 1 12:00:00";
233233
const char* fr_date = "août 19 11:08:37";
234+
const char* fr_date2 = "nov. 29 20:23:37";
234235
timeval en_tv, fr_tv;
235236
exttm en_tm, fr_tm;
236237
date_time_scanner dts;
@@ -241,6 +242,9 @@ TEST_CASE("date_time_scanner")
241242
dts.clear();
242243
CHECK(dts.scan(fr_date, strlen(fr_date), nullptr, &fr_tm, fr_tv)
243244
!= nullptr);
245+
dts.clear();
246+
assert(dts.scan(fr_date2, strlen(fr_date), nullptr, &fr_tm, fr_tv)
247+
!= nullptr);
244248
}
245249
}
246250

0 commit comments

Comments
 (0)