Search code examples
javajavascriptpostgresqld3.jstimestamp-with-timezone

How to format D3 axis using a unix timestamp with timezone from postgres


I'm trying to format my x-axis on a D3 line chart, but the values are completely wrong. The data originates from a Postgres database 'timestamp with timezone' column which I'm converting to json to serve up via D3.

D3 snippet

data.forEach(function(d) {
    d.timestamp = new Date(d.timestamp*1000);
    d.close=+d.close;
}
var timeFormat = d3.time.format("%d %b %y %X");
var x = d3.time.scale().range([ 0, width ]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(timeFormat);
x.domain(d3.extent(data, function(d) {
        return d.timestamp;
    }));

Java conversion to JSON

ResultSet rs = st.executeQuery("select * from price_data order by timestamp);
...     
String.format("{\"timestamp\":\"%d\",\"close\":\"%f\"}",rs.getTimestamp("timestamp").getTime(),rs.getDouble("price"));

Result of axis formatting for timestamp with value 1426014732000 Incorrect axis display format interpretation

What I don't understand though is that the timeFormat function works fine when stepping through my javascript and calling it via a watch expression in Chrome... enter image description here


Solution

  • Why this is happening I still don't know, but the fix was changing the data transformation to not multiply the timestamp by 1000 as suggested everywhere online.

    data.forEach(function(d) {
      //d.timestamp = new Date(d.timestamp*1000);
      d.close=+d.close;
    }
    var timeFormat = d3.time.format("%d %b %y %X");
    var x = d3.time.scale().range([ 0, width ]);
    var xAxis = d3.svg.axis().scale(x).orient("bottom").tickFormat(timeFormat);
    x.domain(d3.extent(data, function(d) {
            return d.timestamp;
        }));
    

    Now the the timestamps are drawn correctly. Perhaps PostgreSql timestamps are already using milliseconds as expected in Javascript. I will investigate and report back for anyone who might be interested in this in future.