【问题标题】:js, get the local time at midnight for a different timezonejs,获取不同时区的当地时间午夜
【发布时间】:2018-07-10 10:49:59
【问题描述】:

我想计算洛杉矶第二天 24:00 时的当前当地时间。目的是设置一个 cookie 直到下一个午夜。

我使用了时刻和时刻时区,但是,我无法证明单个函数的构建大小的开销是合理的。

这是我正在使用的,但我坚持将时间从洛杉矶​​午夜转换回当地时间,因为当我转换回来时,它是在当前时间之前。我认为倒车时convertToOtherTimezone 函数不会有问题,但我不太确定还有什么要探索的。

非常感谢任何帮助。

const convertToOtherTimezone = (date, from, to) => {
  const utc = date.getTime() + (3600000 * from)
  return new Date(utc + (3600000 * to))
}

console.log(
  'native local time in LA',
  new Date().toLocaleString('en-US', { timeZone: 'America/Los_Angeles' })
)

const LA_OFFSET = -7
// I'm using the AEST timezone -10
const LOCAL_OFFSET = new Date().getTimezoneOffset() / 60

const midnightInLA = (localOffset) => {
  // get the current time in LA
  const la = convertToOtherTimezone(new Date(), localOffset, LA_OFFSET)
  console.log('current time in LA', la)
  // set date to midnight in LA's timezone
  la.setHours(24,0,0,0)
  console.log('next midnight in LA', la)
  // convert back to local time
  return convertToOtherTimezone(la, LA_OFFSET, localOffset)
  // Ulias Hunka gave the correct answer, but deleted his post.
  // reverse the offsets
  return convertToOtherTimezone(la, LA_OFFSET * -1, localOffset * -1)
}

console.log(
  'la midnight in local time',
  midnightInLA(LOCAL_OFFSET)
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>

【问题讨论】:

  • moment 和 moment-timezone 压缩后一起小于 20 KB。您的头像为 58 KB。真的有那么大的开销吗?
  • 使用时区插件我得到大约 200kb,删除时刻对最终构建产生了巨大的影响。
  • 刚刚看到 with locales 选项 - 我明白你的意思
  • 由于您只对洛杉矶和未来感兴趣,您可以为未来 50 年的标准时间和夏令时创建一个 UTC 偏移量文件,并将其与本地主机一起使用偏移量。
  • 我即将发布答案,但您能否准确说明“第二天 24:00”的含义。示例 - 7 月 11 日上午 8:00 在伦敦,洛杉矶将从 10 日过渡到 11 日 - 这是您想要的时间吗?还是洛杉矶从 11 日过渡到 12 日的时候?

标签: javascript date time timezone


【解决方案1】:

洛杉矶标准时间是 UTC-0800。它在 3 月的第二个星期日凌晨 2 点更改为夏令时 (DST),此时偏移量更改为 UTC-0700。它在 11 月的第一个星期日凌晨 2 点(夏令时)结束。

这些规则很可能会在未来持续一段时间,如果您只对当前日期感兴趣,则可以使用这些规则直到它们发生变化。您可以计算出给定日期和时间的偏移量,然后为洛杉矶的下一个午夜创建一个日期。我希望您将这些信息放在问题中而不是 cmets 中。见下文。

/**
 *  Calculate the offset in LA for the given date and time.
 *  LA DST starts on the second Sunday in March at
 *  10:00 UTC. After that, the offset is UTC-0700
 *  LA DST ends on the first Sunday in November at 09:00
 *  UTC. After that the offset is UTC-0800
 *
 *  @param {Date} date - date object
 *  @returns (boolean} true if DST is being observed
 */
function getLAOffset(date) {
  // Get DST start in UTC
  var start = new Date(Date.UTC(date.getUTCFullYear(), 2, 1, 10));
  start.setUTCDate(start.getUTCDate() + (7-start.getUTCDay())%7 + 7);
  // Get DST end in UTC
  var end = new Date(Date.UTC(date.getUTCFullYear(), 10, 1, 9));
  end.setUTCDate(end.getUTCDate() + (7-end.getUTCDay())%7);
  return (date >= start && date < end)? -7 : -8;
}

/** Return a Date object set to midnight in LA
 *  for the next midnight after the given date.
 *  Offset comes from getLAOffset
 *
 *  @param {Date} date to use for local date values
 *  @returns {Date} set to midnight in LA
 */
function getLAMidnight(date) {
  var d = new Date(+date);
  
  // Get offset. If hour is before offset, set to offset
  // If hour is after offset, set to offset tomorrow
  // Re-check offset and adjust if necessary
  var offset = getLAOffset(d);
  var midLA = d.setUTCHours(-offset, 0, 0, 0);
  if (d < date) d.setUTCDate(d.getUTCDate() + 1);
  d.setUTCHours(-getLAOffset(d));
  return d;
}

// Local date and time for midnight LA tomorrow:
[new Date(2018,0, 1),     //  1 Jan 2018
 new Date(2018,2,11),     // 11 Mar 2018
 new Date(2018,2,11, 12), // 11 Mar 2018, noon
 new Date(2018,2,12),     // 12 Mar 2018
 new Date(2018,5, 1),     //  1 Jun 2018
 new Date(2018,10,4),     //  4 Nov 2018
 new Date(2018,11,1),     //  1 Dec 2018
 new Date()               // Current
].forEach(function(date) {
  console.log('Local date       : ' + date.toString() +
            '\nNext LA midnight : ' + getLAMidnight(date).toString());
});

【讨论】:

    【解决方案2】:

    我相信您问题中的 sn-p 非常接近,但您似乎在错误的方向添加偏移量。

    您可能会遇到夏令时问题 - 例如,洛杉矶在夏季月份是 UTC-7h,但通常是 UTC-8h。如果您不想使用moment.js,那么我能想到的唯一选择是解析时间的区域设置格式字符串。

    这不是最可靠的方法,仅适用于(按原样)en-US 格式化时间。 America/Los_Angeles 时区也可能不可用,具体取决于浏览器。

    let now = new Date()
    
    // Get the current time in LA using string matching to enable the offset to be calculated
    // This allows for daylight savings to be considered
    // Caution the LocaleTimeString is en-US formatted. Take care if using a different locale
    let timeInLA = now.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })
      .match(/([0-1]?[0-9])\:([0-5]?[0-9])\:[0-5]?[0-9]\s(AM|PM)/)
      // trim first element of match
      .slice(1)
       // take account of AM/PM and convert values to integers
      .map( (e,i,a) => i==0 && a[3] =='PM' ? +e+12 : +e)
      // trim AM/PM
      .slice(0,-1)
      
    // positive values mean local time is ahead of LA
    let offsets = [now.getHours(),now.getMinutes()].map((e,i) => e-timeInLA[i])
    
    // sum up hours and minutes to get totalOffset and convert to ms
    let totalOffsetMS = (offsets[0]*3600 + offsets[1]*60)*1000
    
    // local midnight Tomorrow - add 24 hours and zero other values
    let localMidnightTomorrow = new Date(+now.setHours(24,0,0,0))
    
    // LA midnight will happen at the local midnight time with the offset added
    let localTimeWhenMidnightInLA = new Date(+localMidnightTomorrow + totalOffsetMS)
    
    console.log(`It will be "${localTimeWhenMidnightInLA.toDateString()} ${localTimeWhenMidnightInLA.toTimeString()}" in your location when it is midnight in LA tomorrow`)

    【讨论】:

      猜你喜欢
      • 2013-04-05
      • 2013-04-27
      • 2010-09-27
      • 2018-12-15
      • 2017-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多