0

I am trying to convert timestamps from the local Chrome sqlite db to local time using Go. I know that these timestamps are meant to be microseconds from 1601/01/01.

Checking the values I'm getting for lastVisitTime in the following program on this Chrome timestamp conversion website, I appear to be retrieving them from the database correctly.

package main

import (
    "database/sql"
    "fmt"
    "time"

    _ "github.com/mattn/go-sqlite3"

    "github.com/local_library/comp"
)

var (
    dbPath           = comp.Expanduser("~/Library/Application Support/Google/Chrome/Default/History")
    chromeEpochStart = time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
)

const (
    driverName = "sqlite3"
    tmpPath    = "/tmp/History"
    query      = `
SELECT
    last_visit_time
FROM 
    urls
ORDER BY
    last_visit_time DESC
LIMIT 5
`
)

func main() {
    // Copy to tmp to unlock
    err := comp.Copy(dbPath, tmpPath)
    comp.MustBeNil(err)

    db, err := sql.Open(driverName, tmpPath)
    comp.MustBeNil(err)
    rows, err := db.Query(query)
    comp.MustBeNil(err)
    for rows.Next() {
        var lastVisitTime int64
        rows.Scan(&lastVisitTime)
        d := time.Duration(time.Microsecond * time.Duration(lastVisitTime))
        t := chromeEpochStart.Add(d)
        fmt.Println(t, lastVisitTime)
    }

    err = rows.Close()
    comp.MustBeNil(err)
    err = rows.Err()
    comp.MustBeNil(err)
}

But for some reason, my .Add(d) is setting the times before 1601, which I have never seen before.

1439-07-05 20:00:21.462742384 +0000 UTC 13350512095172294
1439-07-05 19:58:20.377916384 +0000 UTC 13350511974087468
1439-07-05 19:57:58.539932384 +0000 UTC 13350511952249484
1439-07-05 19:57:48.539540384 +0000 UTC 13350511942249092
1439-07-05 19:52:09.587445384 +0000 UTC 13350511603296997

What's happening here and, more importantly, how do I do this correctly?

6
  • 3
    13350511952249484 * time.Microsecond overflows int64 (the underlying type for time.Duration): go.dev/play/p/8mQRRwT0gSt Commented Jan 23, 2024 at 20:00
  • Unfortunate that I didn't get a panic for this in my code. Thank you. – Commented Jan 23, 2024 at 20:58
  • Arithmetic overflow is not a cause for panic. Commented Jan 23, 2024 at 21:27
  • It causes a compiler error for the code @Peter linked. If something causes a compiler error, it seems reasonable that it would cause a panic if encountered in runtime. Commented Jan 24, 2024 at 22:21
  • There is no panic. In my code compilation fails because I used constants, not variables. Constants are checked by the compiler. Variables overflow. That's why you get dates before 1601; the duration becomes negative. Commented Jan 25, 2024 at 10:06

1 Answer 1

2

Thanks to Peter's comment pointing out the overflow in my original code, I found a different approach.

If you convert the Chrome start date to UnixMicro(), you get the negative offset from regular epoch time:

chromeMicroOffset := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC).UnixMicro()
fmt.Println(chromeMicroOffset)
-11644473600000000

Adding these to the database values and converting them to nanoseconds in time.Unix() gets you the correct time in UTC:

microFromEpoch := chromeMicroOffset + lastVisitTime
t := time.Unix(0, microFromEpoch*1000)

A full example converted to Pacific time:

package main

import (
    "fmt"
    "time"
)

var (
    chromeMicroOffset = time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC).UnixMicro()
)

func main() {
    chromeTimestamp := int64(13350516239099543)

    microFromEpoch := chromeMicroOffset + chromeTimestamp
    t := time.Unix(0, microFromEpoch*1000)
    loc, err := time.LoadLocation("America/Los_Angeles")
    if err != nil {
        panic(err)
    }
    fmt.Println(t.In(loc))
}
2024-01-23 12:43:59.099543 -0800 PST
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.