Skip to content

Commit 6e5f191

Browse files
authored
Merge pull request #619 from sputn1ck/fix_faulty_timestamps
loopdb: fix timestamp parsing
2 parents 4a476cb + 5cafa34 commit 6e5f191

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

loopdb/postgres.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func NewPostgresStore(cfg *PostgresConfig,
115115
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
116116
defer cancel()
117117

118-
err = baseDB.FixFaultyTimestamps(ctx, parsePostgresTimeStamp)
118+
err = baseDB.FixFaultyTimestamps(ctx)
119119
if err != nil {
120120
log.Errorf("Failed to fix faulty timestamps: %v", err)
121121
return nil, err

loopdb/sql_test.go

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,19 +375,54 @@ func TestIssue615(t *testing.T) {
375375
require.NoError(t, err)
376376
}
377377

378-
parseFunc := parseSqliteTimeStamp
379-
if testDBType == "postgres" {
380-
parseFunc = parsePostgresTimeStamp
381-
}
382-
383378
// Fix the faulty timestamp.
384-
err = sqlDB.FixFaultyTimestamps(ctxb, parseFunc)
379+
err = sqlDB.FixFaultyTimestamps(ctxb)
385380
require.NoError(t, err)
386381

387382
_, err = sqlDB.GetLoopOutSwaps(ctxb)
388383
require.NoError(t, err)
389384
}
390385

386+
func TestTimeConversions(t *testing.T) {
387+
tests := []struct {
388+
timeString string
389+
expectedTime time.Time
390+
}{
391+
{
392+
timeString: "2018-11-01 00:00:00 +0000 UTC",
393+
expectedTime: time.Date(2018, 11, 1, 0, 0, 0, 0, time.UTC),
394+
},
395+
{
396+
timeString: "2018-11-01 00:00:01.10000 +0000 UTC",
397+
expectedTime: time.Date(2018, 11, 1, 0, 0, 1, 0, time.UTC),
398+
},
399+
{
400+
timeString: "2053-12-29T02:40:44.269009408Z",
401+
expectedTime: time.Date(
402+
2053, 12, 29, 2, 40, 44, 0, time.UTC,
403+
),
404+
},
405+
{
406+
timeString: "55563-06-27 02:09:24 +0000 UTC",
407+
expectedTime: time.Date(
408+
55563, 6, 27, 2, 9, 24, 0, time.UTC,
409+
),
410+
},
411+
{
412+
timeString: "2172-03-11 10:01:11.849906176 +0000 UTC",
413+
expectedTime: time.Date(
414+
2172, 3, 11, 10, 1, 11, 0, time.UTC,
415+
),
416+
},
417+
}
418+
419+
for _, test := range tests {
420+
time, err := parseTimeStamp(test.timeString)
421+
require.NoError(t, err)
422+
require.Equal(t, test.expectedTime, time)
423+
}
424+
}
425+
391426
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
392427

393428
func randomString(length int) string {

loopdb/sqlite.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func NewSqliteStore(cfg *SqliteConfig, network *chaincfg.Params) (*SqliteSwapSto
122122
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
123123
defer cancel()
124124

125-
err = baseDB.FixFaultyTimestamps(ctx, parseSqliteTimeStamp)
125+
err = baseDB.FixFaultyTimestamps(ctx)
126126
if err != nil {
127127
log.Errorf("Failed to fix faulty timestamps: %v", err)
128128
return nil, err
@@ -209,8 +209,7 @@ func (db *BaseDB) ExecTx(ctx context.Context, txOptions TxOptions,
209209

210210
// FixFaultyTimestamps fixes faulty timestamps in the database, caused
211211
// by using milliseconds instead of seconds as the publication deadline.
212-
func (b *BaseDB) FixFaultyTimestamps(ctx context.Context,
213-
parseTimeFunc func(string) (time.Time, error)) error {
212+
func (b *BaseDB) FixFaultyTimestamps(ctx context.Context) error {
214213

215214
// Manually fetch all the loop out swaps.
216215
rows, err := b.DB.QueryContext(
@@ -248,7 +247,7 @@ func (b *BaseDB) FixFaultyTimestamps(ctx context.Context,
248247
defer tx.Rollback() //nolint: errcheck
249248

250249
for _, swap := range loopOutSwaps {
251-
faultyTime, err := parseTimeFunc(swap.PublicationDeadline)
250+
faultyTime, err := parseTimeStamp(swap.PublicationDeadline)
252251
if err != nil {
253252
return err
254253
}
@@ -309,14 +308,29 @@ func (r *SqliteTxOptions) ReadOnly() bool {
309308
return r.readOnly
310309
}
311310

311+
// parseTimeStamp tries to parse a timestamp string with both the
312+
// parseSqliteTimeStamp and parsePostgresTimeStamp functions.
313+
// If both fail, it returns an error.
314+
func parseTimeStamp(dateTimeStr string) (time.Time, error) {
315+
t, err := parseSqliteTimeStamp(dateTimeStr)
316+
if err != nil {
317+
t, err = parsePostgresTimeStamp(dateTimeStr)
318+
if err != nil {
319+
return time.Time{}, err
320+
}
321+
}
322+
323+
return t, nil
324+
}
325+
312326
// parseSqliteTimeStamp parses a timestamp string in the format of
313327
// "YYYY-MM-DD HH:MM:SS +0000 UTC" and returns a time.Time value.
314328
// NOTE: we can't use time.Parse() because it doesn't support having years
315329
// with more than 4 digits.
316330
func parseSqliteTimeStamp(dateTimeStr string) (time.Time, error) {
317331
// Split the date and time parts.
318332
parts := strings.Fields(strings.TrimSpace(dateTimeStr))
319-
if len(parts) <= 2 {
333+
if len(parts) < 2 {
320334
return time.Time{}, fmt.Errorf("invalid timestamp format: %v",
321335
dateTimeStr)
322336
}
@@ -385,7 +399,10 @@ func parseTimeParts(datePart, timePart string) (time.Time, error) {
385399
return time.Time{}, err
386400
}
387401

388-
second, err := strconv.Atoi(timeParts[2])
402+
// Parse the seconds and ignore the fractional part.
403+
secondParts := strings.Split(timeParts[2], ".")
404+
405+
second, err := strconv.Atoi(secondParts[0])
389406
if err != nil {
390407
return time.Time{}, err
391408
}

0 commit comments

Comments
 (0)