Skip to content

Commit 0c3943e

Browse files
Support RabbitMQ log format (dd-mon-yyyy::hh:mm:ss)
Adapt araddon#122 by https://github.com/bizy01 to add support for RMQ log format. Refactor to avoid redundant code. Add format validations. As a side note, will also support the format dd-mm-yyyy:hh:mm:ss.
1 parent 249dd73 commit 0c3943e

File tree

2 files changed

+71
-31
lines changed

2 files changed

+71
-31
lines changed

parseany.go

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -598,44 +598,76 @@ iterRunes:
598598
// 13-Feb-03 ambiguous
599599
// 28-Feb-03 ambiguous
600600
// 29-Jun-2016 dd-month(alpha)-yyyy
601+
// 8-Mar-2018::
601602
// dateDigitDashDigitDash:
602603
// 29-06-2026
604+
// 08-03-18:: ambiguous (dd-mm-yy or yy-mm-dd)
603605
switch r {
604-
case ' ':
605-
// we need to find if this was 4 digits, aka year
606-
// or 2 digits which makes it ambiguous year/day
607-
length := i - (p.moi + p.molen + 1)
608-
if length == 4 {
609-
p.yearlen = 4
610-
p.set(p.yeari, "2006")
611-
// We now also know that part1 was the day
612-
p.dayi = 0
613-
p.daylen = p.part1Len
614-
if !p.setDay() {
615-
return p, unknownErr(datestr)
606+
case ' ', ':':
607+
doubleColonTimeConnector := false
608+
if r == ':' {
609+
p.link++
610+
if p.link == 2 {
611+
if i+1 < len(p.datestr) {
612+
// only legitimate content to follow "::" is the start of the time
613+
nextChar, _ := utf8.DecodeRuneInString(p.datestr[i+1:])
614+
if unicode.IsDigit(nextChar) {
615+
doubleColonTimeConnector = true
616+
}
617+
}
618+
if !doubleColonTimeConnector {
619+
return p, unknownErr(datestr)
620+
}
616621
}
617-
} else if length == 2 {
618-
// We have no idea if this is
619-
// yy-mon-dd OR dd-mon-yy
620-
// (or for dateDigitDashDigitDash, yy-mm-dd OR dd-mm-yy)
621-
//
622-
// We are going to ASSUME (bad, bad) that it is dd-mon-yy (dd-mm-yy),
623-
// which is a horrible assumption, but seems to be the convention for
624-
// dates that are formatted in this way.
625-
p.ambiguousMD = true
626-
p.yearlen = 2
627-
p.set(p.yeari, "06")
628-
// We now also know that part1 was the day
629-
p.dayi = 0
630-
p.daylen = p.part1Len
631-
if !p.setDay() {
622+
} else if p.link > 0 {
623+
return p, unknownErr(datestr)
624+
}
625+
if r == ' ' || doubleColonTimeConnector {
626+
// we need to find if this was 4 digits, aka year
627+
// or 2 digits which makes it ambiguous year/day
628+
var sepLen int
629+
if doubleColonTimeConnector {
630+
sepLen = 2
631+
} else {
632+
sepLen = 1
633+
}
634+
length := i - (p.moi + p.molen + sepLen)
635+
if length == 4 {
636+
p.yearlen = 4
637+
p.set(p.yeari, "2006")
638+
// We now also know that part1 was the day
639+
p.dayi = 0
640+
p.daylen = p.part1Len
641+
if !p.setDay() {
642+
return p, unknownErr(datestr)
643+
}
644+
} else if length == 2 {
645+
// We have no idea if this is
646+
// yy-mon-dd OR dd-mon-yy
647+
// (or for dateDigitDashDigitDash, yy-mm-dd OR dd-mm-yy)
648+
//
649+
// We are going to ASSUME (bad, bad) that it is dd-mon-yy (dd-mm-yy),
650+
// which is a horrible assumption, but seems to be the convention for
651+
// dates that are formatted in this way.
652+
p.ambiguousMD = true
653+
p.yearlen = 2
654+
p.set(p.yeari, "06")
655+
// We now also know that part1 was the day
656+
p.dayi = 0
657+
p.daylen = p.part1Len
658+
if !p.setDay() {
659+
return p, unknownErr(datestr)
660+
}
661+
} else {
632662
return p, unknownErr(datestr)
633663
}
634-
} else {
664+
p.stateTime = timeStart
665+
break iterRunes
666+
}
667+
default:
668+
if !unicode.IsDigit(r) && !unicode.IsLetter(r) && p.link > 0 {
635669
return p, unknownErr(datestr)
636670
}
637-
p.stateTime = timeStart
638-
break iterRunes
639671
}
640672

641673
case dateDigitYearSlash:
@@ -2397,6 +2429,7 @@ type parser struct {
23972429
fullMonth string
23982430
parsedAMPM bool
23992431
skip int
2432+
link int
24002433
extra int
24012434
part1Len int
24022435
yeari int

parseany_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ var testInputs = []dateTest{
446446
// Git log default date format - https://github.com/araddon/dateparse/pull/92
447447
{in: "Thu Apr 7 15:13:13 2005 -0700", out: "2005-04-07 22:13:13 +0000 UTC"},
448448
{in: "Tue Dec 12 23:07:11 2023 -0700", out: "2023-12-13 06:07:11 +0000 UTC"},
449+
// RabbitMQ log format - https://github.com/araddon/dateparse/pull/122
450+
{in: "8-Mar-2018::14:09:27", out: "2018-03-08 14:09:27 +0000 UTC"},
451+
{in: "08-03-2018::02:09:29 PM", out: "2018-03-08 14:09:29 +0000 UTC"},
449452
// yyyy-mm-dd hh:mm:ss,000
450453
{in: "2014-05-11 08:20:13,787", out: "2014-05-11 08:20:13.787 +0000 UTC"},
451454
// yyyy-mm-dd hh:mm:ss +0000
@@ -827,6 +830,10 @@ var testParseErrors = []dateTest{
827830
{in: "2014-02-13 00:00:00 utc", err: true}, // lowercase timezones are not valid
828831
{in: "2014-02-13t00:00:00.0z", err: true}, // lowercase 't' separator is not supported
829832
{in: "2014-02-13T00:00:00.0z", err: true}, // lowercase 'z' zulu timezone indicator not a valid format
833+
// Invalid variants of RabbitMQ log format
834+
{in: "8-Mar-2018:14:09:27", err: true},
835+
{in: "8-Mar-2018: 14:09:27", err: true},
836+
{in: "8-Mar-2018:::14:09:27", err: true},
830837
}
831838

832839
func TestParseErrors(t *testing.T) {
@@ -1093,5 +1100,5 @@ func TestRetryAmbiguousDateWithSwap(t *testing.T) {
10931100

10941101
// Convenience function for debugging a particular broken test case
10951102
func TestDebug(t *testing.T) {
1096-
MustParse("Tue Dec 12 23:07:11 2023 -0700")
1103+
MustParse("8-Mar-2018::14:09:27")
10971104
}

0 commit comments

Comments
 (0)