从Date对象计算BST时间?

时间:2016-01-15 20:24:39

标签: javascript date dst timezone-offset

我已经回顾了几个关于类似主题的问题,但没有一个问题涉及计算目的地时区,将 DST(夏令时)考虑在内。我正在尝试编写一个简单的小部件,向访问该页面的任何人显示特定时区的实时本地时间。感兴趣的时区是BST(what is BST?),但如果可能的话,我很乐意看到任何语言环境的通用实现。这是我的尝试,使用vanilla JavaScript:

function getBST() {
    var date = new Date(),
        utc = date.getTime() + date.getTimezoneOffset() * 60000,
        local = new Date(utc), // this is GMT, not BST
        day = local.getDate(),
        mon = local.getMonth() + 1,
        year = local.getFullYear(),
        hour = local.getHours(),
        minute = ('0' + local.getMinutes()).slice(-2),
        second = ('0' + local.getSeconds()).slice(-2),
        suffix = hour < 12 ? 'AM' : 'PM';

    hour = (hour - 24) % 12 + 12;

    return mon + '/' + day + '/' + year + ', ' + hour + ':' + minute + ':' + second + ' ' + suffix;
}

setInterval(function () {
  document.body.textContent = getBST();
}, 1000);

根据@ RobG的回答,我写了这段代码:

function resetDay(date) {
  date.setUTCMilliseconds(0);
  date.setUTCSeconds(0);
  date.setUTCMinutes(0);
  date.setUTCHours(1);

  return date;
}

function lastDay(date, day) {
  while (date.getUTCDay() !== day) {
    date.setUTCDate(date.getUTCDate() - 1);
  }

  return date;
}

function adjustDST(date, begin, end) {
  if (date >= begin && date < end) {
    date.setUTCHours(date.getUTCHours() + 1);
  }

  return date;
}

function updateBST() {
  var date = new Date();
  var begin = resetDay(new Date());

  begin.setUTCMonth(3, -1);
  begin = lastDay(begin, 0);

  var end = resetDay(new Date());

  end.setUTCMonth(10, -1);
  end = lastDay(end, 0);

  date = adjustDST(date, begin, end);

  var day = date.getUTCDate(),
    mon = date.getUTCMonth() + 1,
    year = date.getUTCFullYear(),
    hour = date.getUTCHours(),
    minute = ('0' + date.getUTCMinutes()).slice(-2),
    second = ('0' + date.getUTCSeconds()).slice(-2),
    suffix = hour < 12 ? 'AM' : 'PM';

  hour = (hour - 24) % 12 + 12;

  return mon + '/' + day + '/' + year + ', ' + hour + ':' + minute + ':' + second + ' ' + suffix;
}

setInterval(function () {
  document.body.textContent = updateBST();
}, 1000);

我通过在调试器中暂停并更改当前日期的月份来测试BST,并且输出是一小时后因此它似乎正常工作。感谢大家的帮助!

2 个答案:

答案 0 :(得分:5)

纯JS中不可能,只使用var babel = require('gulp-babel'); var es2015 = require('babel-preset-es2015'); gulp.task('babel', function() { return gulp.src('./app/main.js') .pipe(babel({ presets: [es2015] })) .pipe(gulp.dest('dist')); }); 方法,但当然有一个lib:http://momentjs.com/timezone/

示例:

  "devDependencies": {
    "babel-preset-es2015": "^6.3.13",
    "babel-preset-es2015-node5": "^1.1.1",
    "browser-sync": "^2.11.0",
    "gulp": "^3.9.0",
    "gulp-babel": "^6.1.1",
    "gulp-stylus": "^2.2.0"
  }

答案 1 :(得分:2)

支持一个时区并不困难,前提是您知道何时进入和退出夏令时。

javascript日期包含UTC时间值和基于主机系统设置的时区偏移量。因此,您需要做的就是将您想要的时区偏移量应用于UTC时间和时间,这是您在任何时区的时间。

虽然有一些事实上的标准(例如IATA timezone codesIANA timezones),但没有用于缩短时区的标准化系统。我猜BST你的意思是英国夏令时,也被称为英国夏令时(BDT)和英国夏令时(BDST)。它也可能是孟加拉国标准时间或布干维尔标准时间,也被称为&#34; BST&#34;。

有各种库(例如Moment Timezone)使用IANA代码,可以随时(或多或少)为任何支持的时区提供时间。

BST从3月的最后一个星期日的01:00 UTC开始,到每年10月的最后一个星期日的01:00 UTC结束,因此算法是:

  1. 根据系统的本地设置(例如new Date()
  2. 创建新日期
  3. 根据UTC值(今年,2016-03-27T01:00:00Z和2016-03-30T02:00:00Z)创建BST开始和结束的日期
  4. 查看当前UTC时间是否在该范围内
  5. 如果是,请在#1
  6. 中创建的日期的UTC时间加1小时
  7. 根据日期的UTC值
  8. 输出格式化的字符串

    那就是它,唯一困难的部分是找到合适的星期日。您根本不需要考虑本地时区偏移,因为所有内容都基于UTC和Date对象。

    现在我没有时间提供代码,所以请一试,我可以在大约10小时内回复你。

    修改

    所以这里是代码。前两个函数是帮助程序,一个是一个月中的最后一个星期日,另一个是带有偏移量的ISO 8601字符串。大多数工作都在这两个功能中。希望评论足够,如果需要更多解释,请问。

    我还没有在字符串中包含毫秒,如果需要,可以随意添加它们,在格式化字符串的偏移部分之前添加+ '.' + ('00' + d.getUTCMilliseconds()).slice(-3)

    请注意,如果更改启动或停止夏令时的日期,则需要修改该功能,但这种情况并不常见。当然,历史日期需要一个小型数据库,说明何时开始和停止特定年份和时段的夏令时。

    &#13;
    &#13;
    /* Return a Date for the last Sunday in a month
    ** @param {number} year - full year number (e.g. 2015)
    ** @param {number} month - calendar month number (jan=1)
    ** @returns {Date} date for last Sunday in given month
    */
    function getLastSunday(year, month) {
      // Create date for last day in month
      var d = new Date(year, month, 0);
      // Adjust to previous Sunday
      d.setDate(d.getDate() - d.getDay());
      return d;
    }
    
    /* Format a date string as ISO 8601 with supplied offset
    ** @param {Date} date - date to format
    ** @param {number} offset - offset in minutes (+east, -west), will be
    **                          converted to +/-00:00
    ** @returns {string} formatted date and time
    **
    ** Note that javascript Date offsets are opposite: -east, +west but 
    ** this function doesn't use the Date's offset.
    */
    function formatDate(d, offset) {
      function z(n){return ('0'+n).slice(-2)}
      // Default offset to 0
      offset = offset || 0;
      // Generate offset string
      var offSign = offset < 0? '-' : '+';
      offset = Math.abs(offset);
      var offString = offSign + ('0'+(offset/60|0)).slice(-2) + ':' + ('0'+(offset%60)).slice(-2);
      // Generate date string
      return d.getUTCFullYear() + '-' + z(d.getUTCMonth()+1) + '-' + z(d.getUTCDate()) +
             'T' + z(d.getUTCHours()) + ':' + z(d.getUTCMinutes()) + ':' + z(d.getUTCSeconds()) +
             offString;
    }
    
    /* Return Date object for current time in London. Assumes
    ** daylight saving starts at 01:00 UTC on last Sunday in March
    ** and ends at 01:00 UTC on the last Sunday in October.
    ** @param {Date} d - date to test. Default to current
    **                   system date and time
    ** @param {boolean, optional} obj - if true, return a Date object. Otherwise, return
    **                        an ISO 8601 formatted string
    */
    function getLondonTime(d, obj) {
      // Use provided date or default to current date and time
      d = d || new Date();
    
      // Get start and end dates for daylight saving for supplied date's year
      // Set UTC date values and time to 01:00
      var dstS = getLastSunday(d.getFullYear(), 3);
      var dstE = getLastSunday(d.getFullYear(), 10);
      dstS = new Date(Date.UTC(dstS.getFullYear(), dstS.getMonth(), dstS.getDate(),1));
      dstE = new Date(Date.UTC(dstE.getFullYear(), dstE.getMonth(), dstE.getDate(),1));
      // If date is between dstStart and dstEnd, add 1 hour to UTC time
      // and format using +60 offset
      if (d > dstS && d < dstE) {
        d.setUTCHours(d.getUTCHours() +1);
        return formatDate(d, 60);
      }
      // Otherwise, don't adjust and format with 00 offset
      return obj? d : formatDate(d);
    }
    
    document.write('Current London time: ' + getLondonTime(new Date()));
    &#13;
    &#13;
    &#13;