显示不同时区的数据

Displaying data in different timezone

总结

我收集了大量具有不同日期时间的数据。目前我已经能够将所有数据分组以在本地时区正确显示;然而,当尝试在不同的时区显示此数据时,折线图上的线条会变得不稳定,并且它们之间的连接不如在本地时区时那么流畅。

我发现这个 link 在这里详细说明了一个可能的解决方案,但遗憾的是,如果我不复制我的整个数据集并使用与 utc 的时间偏移然后像往常一样复制一次,这将无法工作。我拥有的数据不仅用于多个图表中以获取有关趋势和统计数据的见解,而且还有用于 display/editing/reviewing 特定数据成员的原始 table。因此,将一个转换为 utc 时间并计算 utc 时间的时间变化会使另一个消失。

https://groups.google.com/forum/#!msg/d3-js/iWmP9Npv2Go/xyypdLjWu2QJ

我的问题是:有没有一种方法可以跨时区转换日期时间数据并dc.js尊重您想要显示的时区。我希望调整后的图表看起来与本地图表相同根据时区查看线条不是单向的。

代码和照片

fiddle: https://jsfiddle.net/spacarar/j0urt9sy/49/

这是我当地时区的正确显示图像。线条是日期之间的平滑过渡。

这是任何其他时区的错误显示图像(取决于我当地的哪一侧改变方向从左倾到右倾)

我的数据的简化版本如下所示:

var data = [
  {
    value: 42,
    datetime: '2019-10-24T07:18:00.000000'
  },
  {
    value: 10,
    datetime: '2019-10-24T07:19:12.000000'
  },
  {
    value: 12,
    datetime: '2019-10-29T04:18:00.000000'
  },
  {
    value: 8,
    datetime: '2019-10-29T09:18:00.000000'
  }
]

然后我伪造分组以填充数据中可能不存在的任何日期,并使用 moment-timezone 转换它们以得到类似于此的数据结构

{
  value: 0,
  datetime: moment timezone object with full datetime,
  date: moment timezone object representing only date (0 hours, minutes, seconds, ms)
}

然后使用这个伪造的 grouped/fixed 数据通过以下代码创建图表

var ndx = dc.crossfilter(fakeGroupedData)

var dateDim = ndx.dimension(dc.pluck('date'))
var top = dateDim.top(1)[0] ? dateDim.top(1)[0].date : null
var bottom = dateDim.bottom(1)[0] ? dateDim.bottom(1)[0].date : null

var chart = dc.lineChart('#date-chart')
chart.yAxis().tickFormat(dc.d3.format(',.0f'))
chart.xAxis().ticks(10).tickFormat(d => moment(d).format('M/D'))

chart.dimension(dateDim)
  .group(dateDim.group().reduceSum(dc.pluck('value')))
  .x(dc.d3.scaleTime().domain([bottom, top]).nice())
  .elasticY(true)
  .renderArea(true)
  .render()

关于您填写日期的几点说明。

  1. 这不是 "fake group" 的通常含义。您正在填写源数据,并且所有交叉过滤器组都完全 "real" :)

  2. 以高于您打算显示的分辨率进行填充没有任何意义。为了简化问题,我将您的代码更改为按天填充,结果完全一样:

    let start = moment.tz(startDate, tzSelection).startOf('day')
    let end = moment.tz(endDate, tzSelection).endOf('day')
    let hours = end.diff(start, 'days')
    for (let i = 0; i < hours; i++) {
      let fakeTime = moment(start).add(i, 'days')
      let date = moment(fakeTime.format('YYYY-MM-DD'))
      fakeGroupedData.push({
        value: 0,
        datetime: fakeTime,
        date
      })
    }
    

使用 d3-time 可能更容易,因为它与 dc.js 集成得更紧密,但我不想对您的代码进行大的更改。

但是,您基本上是按天量化,因此您可以设置维度以量化到当前时区当天的开始,这将修复您的图表:

var dateDim = ndx.dimension(d => d3.timeDay(dc.pluck('date')(d)))

如果你这样做,你不需要修改你输入的日期:

el.date = el.datetime //.clone().startOf('day')

D3 将截断到当天,然后交叉过滤器将以该分辨率进行分类。

https://jsfiddle.net/gordonwoodhull/Lxvcoq3h/19/

请注意,它将两个 10/29 条目合并为一个。

在我的时区 UTC-5 中,startOf('day') 舍入的那一刻导致这些条目中的第一个在 28 日登陆,这与您所说的相符:

https://jsfiddle.net/gordonwoodhull/Lxvcoq3h/21/

您必须决定哪一个适合您的应用程序。要点是,如果您在本地时区显示图表,则数据应量化为本地日期。