【问题标题】:moment.js and bootstrap-datepicker not respecting a user's timezonemoment.js 和 bootstrap-datepicker 不尊重用户的时区
【发布时间】:2016-10-20 14:12:17
【问题描述】:

我有一个日历应用程序,用户可以在其中选择交货和取货日期。送货和取货需要在司机所在的 PST 中完成,但 bootstrap-datepicker 使用浏览器的时区。我添加了

moment.tz.setDefault("America/Los_Angeles");

到我的application.js 文件,但问题是我从日期选择器返回的日期是在浏览器的时区中返回的(出于测试目的,我已将其设置为 BST)。

var pickupDate = moment($('#pickup-date').datepicker("getDate"))
=> Thu Jul 07 2016 00:00:00 GMT+0100 (BST)
_d: Wed Jul 06 2016 17:00:00 GMT+0100 (BST)
_i: Thu Jul 07 2016 00:00:00 GMT+0100 (BST)
pickupWindows = (
  windowsByDate[pickupDate.format("YYYY-MM-DD HH:mm:ss ZZ")] || {}
).pickupWindows

所以当我实际将日期与系统中的日期进行比较时,它不起作用,因为它不像预期的那样在 PST 中。 windowsByDate 中的键是由 PST 索引的,所以这段代码不起作用并返回 undefined

一个技巧就是将日期重新解析为 PST,但这似乎是超级 hacky。有一个更好的方法吗?强制bootstrap-datepicker 假定日期为太平洋标准时间,还是强制返回的日期为太平洋标准时间?

编辑: 实际上,我什至无法将日期重新解析为 PST,除非我将其视为字符串。

deliveryDateInTimeZone = moment($('#delivery-date').datepicker("getDate"))
deliveryDateInPst = moment(deliveryDateInTimeZone.format("YYYY-MM-DD"), "YYYY-MM-DD").tz("America/Los_Angeles")

这会返回上一个日期,因为deliveryDateInTimeZone 被设置为当前时区,但是当我格式化日期时,它会将其视为 PST 时间并回溯 8 小时。

编辑2: 这是我获取时区的新方法。

deliveryDate = $('#delivery-date').datepicker("getDate")
deliveryDateInPst = moment(deliveryDate.getFullYear() + "-" + (deliveryDate.getMonth() + 1) + "-" + deliveryDate.getDate() + " 00:00:00 " + moment().format("ZZ"))

【问题讨论】:

  • 无论何时处理多个时区,都应始终将日期/时间保存为 UTC。仅在输入/显示时转换为/从 UTC 语言环境。这消除了计算问题。
  • @Peter 这条笼统的建议并非在所有用例中都适用,而且根本无助于解决这个问题——因为这确实是在输入点。
  • @Waynn - Date 对象将始终位于本地时区。这是无法避免的。您必须纯粹使用 moment 对象和字符串。向我们展示您正在使用您创建的 moment 对象做什么。如果您正在评估 _d,那么您做错了。
  • @MattJohnson 感谢您的回复!是的,我正在从日期选择器返回的日期创建moment 对象。我添加了_d_i 键,并在问题中添加了更多信息。让我知道这是否有助于澄清?

标签: jquery twitter-bootstrap datepicker momentjs


【解决方案1】:

关于编辑 2,与其从 Date 中提取值,不如创建一个字符串,然后使用 moment.js 构造函数对其进行解析,而是考虑从 Date中传递值> 直接到moment.js构造函数中的数组,同时设置你想要的位置。

这实际上与创建字符串然后解析相同,只是更直接。它还避免了乱用默认时区。

例如:

// Date as if from date picker, i.e. local time set to 00:00:00
let d = new Date();
d.setHours(0,0,0,0);
console.log('Initial Date as local: ' + myFormat(d));

// Get browser default timezone (not necessarily perfect)
let localTz = moment.tz.guess();
console.log('Local IANA location  : ' + localTz);

// Use values from Date as America/Los_Angeles (or whatever loc suits)
// Year, month, day, etc. are same value but timezone is different
let dLA = moment.tz(getParts(d), "America/Los_Angeles");
console.log('As Los Angeles date  : ' + dLA.format("YYYY-MM-DD HH:mm:ss z"));

// Equivalent local date: create a new moment from dLA using local tz
let dLocal = moment(dLA).tz(localTz);
console.log('Equivalent local date: ' + dLocal.format("YYYY-MM-DD HH:mm:ss z"))

// Helpers
// Format Date
function myFormat(d) {
  return d.toLocaleString('en-ca', {
    year: 'numeric', month:'2-digit', day:'2-digit', hour:'2-digit', minute:'2-digit',
    second:'2-digit', hour12: false, timeZoneName:'long'
  }).replace(',','');
}
// Get [year, month, day, etc.] as array
function getParts(d) {
  return [d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(),
          d.getMinutes(), d.getSeconds(), d.getMilliseconds()];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.33/moment-timezone-with-data-10-year-range.js"></script>

请参阅moment.tz documentation in regard to tz.guess

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 2013-03-22
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多