【问题标题】:moment.js timezones .valueOf() not returning expected valuesmoment.js timezones .valueOf() 未返回预期值
【发布时间】:2015-04-21 20:21:29
【问题描述】:

我有一个使用 highcharts-ng 制作折线图的角度应用程序。 y 轴是数字,x 轴是日期时间。

我正在尝试使用 moment.js 在“America/New_York”和“Europe/London”两个时区之间转换时正确考虑夏令时的变化。

伦敦目前处于英国夏令时(截至发帖时),因此是 +1:00。

tick.TimeStamp
> "2015-04-21T16:06:06.0786392-04:00"

tick.TimeStamp 是我的“美国/纽约”时间(目前在 EDT)。我使用...将其转换为伦敦时间。

moment(tick.TimeStamp).tz("Europe/London").format()
> "2015-04-21T21:06:06+01:00"

我需要我在 Unix Epoch 刻度中的结果来绘制它们在 highcharts-ng 中的 x 轴,所以我使用...

var d = moment(tick.TimeStamp).tz("Europe/London").format()
moment(d).valueOf()

产生

1429646766000

问题是这个刻度值作为日期时间的结果是

格林威治标准时间 2015 年 4 月 21 日星期二 20:06:06

它应该在哪里

格林威治标准时间 2015 年 4 月 21 日星期二 21:06:06

因为伦敦目前在 BST +1:00

是我做错了什么,还是只是时刻计算不正确?

任何帮助将不胜感激。谢谢!

编辑:我应该提到我的 moment-timezones.js 是他们网站上最新的,包含所有时区信息。

【问题讨论】:

    标签: javascript angularjs timezone momentjs highcharts-ng


    【解决方案1】:

    Moment 计算正确。

    Tue, 21 Apr 2015 20:06:06 GMTTue, 21 Apr 2015 21:06:06 BSTTue, 21 Apr 2015 16:06:06 EDT 都指向相同的时间,并且都具有相同的 unix 时间戳。当您致电.tz() 时,您只是在更改该时间的格式。您没有更改实际时间。

    注意:要获取 unix 时间戳,您可以使用 .unix() 例如

    moment(tick.TimeStamp).unix()
    

    否则这将返回相同的值

    moment(tick.TimeStamp).tz("Europe/London").unix()
    

    【讨论】:

    • +1。此外,moment(tick.TimeStamp).valueOf() 如果他需要以毫秒为单位的时间戳而不是秒,则可以使用。你说得对,tz 是多余的,为此目的是不必要的。
    • @rob - 感谢您的回复,这很有帮助。我确实找到了解决方案,您可以在下面查看我的评论。谢谢!
    【解决方案2】:

    我更新了一个 JS fiddle 来提供一个示例。 http://jsfiddle.net/x0z90vqg/(如果不使用 HighStock,则更新小提琴在 xAxis 上显示 type 属性)

    我相信您的问题是您没有正确使用 Highcharts global object 的属性 useUTC 和 timezoneOffset 属性。使用highcharts-ng 控件掩盖了Highcharts 库的一些功能,但您仍然可以很容易地访问您需要的功能。

    小提琴的相关部分是:

    Highcharts.setOptions({
        global : {
            useUTC : false,
            timezoneOffset: -5
        }
    });
    $scope.chartConfig.getHighcharts().redraw();
    

    上面的示例将 Highcharts 全局对象设置为不使用 UTC 作为日期/时间序列,并将偏移量设置为 -5 小时(您可以像现在一样使用 moment.js 获得所需的偏移量),然后告诉图表通过highcharts-ng的暴露getHighcharts()方法重绘。该方法返回实际的图表对象,从那里就像您直接使用 highcharts 而不是通过任何中间组件一样。

    编辑

    @Matt 提出了一个很好的观点。像这样设置 timezoneOffset 与设置真正的时区并不完全相同。真正的时区会考虑 DST 变化等,这只是与 UTC 的静态偏移。像这样设置 UTC 偏移量也会影响整个图表,而不仅仅是一个系列。如果您需要在不同时区的同一图表上显示(和比较)两个或多个系列,并将该数据显示为各自的时区,您可以启用多个 X 轴,并在每个轴的格式标签逻辑中,取 X 值勾选并通过 javascript 函数将其转换为您要显示的时区值和标签。这应该会导致两个 X 轴的标签位于两个不同的时区,但图表中心部分的数据运行在相同的 UTC 刻度上。如果这样做,您可能还希望覆盖工具提示弹出窗口的格式化程序,以便您可以转换工具提示中显示的值以显示每个点的时区值(如果您不希望它)显示 UTC。

    所有这些仍然不能解决显示跨越 DST 切换点的时间序列数据的问题。我不相信 Highcharts 有任何表示方法,而且我不知道另一个图表库也可以。不过,这似乎是一个相当普遍的问题,所以我确信它已经在某个地方得到了解决......

    【讨论】:

    • 这很有趣,除了这意味着偏移量需要在图表覆盖的范围内保持稳定。请参阅the timezone tag wiki 中的“时区!= 偏移量”。如果偏移量稳定,那么就可以正常工作。否则,转换为 UTC 可能是个好主意。
    • @Matt,非常有效的观点。根据我的经验,Highcharts 不处理(甚至似乎不知道)合法时区。最接近的功能似乎是偏移量。使用像 moment.js 这样的库来为要在图表上显示的时区找到适当的 UTC 偏移量,并将其放置在偏移量中,无论是在渲染图表之前还是像上面那样动态地进行,似乎是唯一的方法它显示非 UTC、非当前语言环境时区。就像您提到的那样,它确实会影响整个图表,因此所有数据都应首先使用 UTC 进行正确比较。
    • @sohjsolwin - 这看起来很有希望,但这里的问题是我没有使用 highstocks,所以一旦你设置“useHighStocks: false”,这个方法就不再起作用了。
    • @Corey 这是由于 Highstocks 自动设置的一些默认值。作为日期时间类型的 xAxis 就是其中之一。您只需要这条语句来告诉它 x 点数据是时间而不是数字。我也会用更改来更新示例。 xAxis: { type:'datetime' }
    【解决方案3】:

    只是想快速更新一下我的发现。 由于我在客户端尝试执行此操作时遇到了很多怪癖,因此我在我的控制器代码 (.NET) 中找到了一种在服务器端处理此问题的好方法。我现在不仅返回时间戳 (tick.TimeStamp),还返回 EasternTimeStampLondonTimeStamp。我能够使用 TimeZoneInfo 类的一个不错的方法来完成此操作。

        /// <summary>
        /// Converts the time to eastern standard time.
        /// This should properly account for DST, putting the time in EST (-5:00) or EDT (-4:00)
        /// </summary>
        public static DateTime ConvertTimeToEasternStandardTime(DateTime inputDateTime)
        {
            // US eastern timezone=Eastern Standard Time
            string targetTimeZoneId = "Eastern Standard Time";
            DateTime outputDateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(inputDateTime, targetTimeZoneId);
            return outputDateTime;
        }
    
        /// <summary>
        /// Converts the time to GMT standard time.
        /// This should properly account for DST, putting the time in BST (+1:00) or GMT (+0:00)
        /// </summary>
        public static DateTime ConvertTimeToGMTStandardTime(DateTime inputDateTime)
        {
            // London timezone=GMT Standard Time
            string targetTimeZoneId = "GMT Standard Time";
            DateTime outputDateTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(inputDateTime, targetTimeZoneId);
            return outputDateTime;
        }
    

    希望遇到此问题的任何人都能发现这很有用。在过去的一周里,我发现试图找到一种处理 DST 和时区的好方法是非常有压力的。

    【讨论】:

      猜你喜欢
      • 2013-09-04
      • 2016-02-13
      • 2015-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 2012-11-08
      相关资源
      最近更新 更多