【问题标题】:How to fake time in javascript?如何在javascript中伪造时间?
【发布时间】:2019-01-07 16:04:40
【问题描述】:

我想模拟 Date 构造函数,这样每当我调用 new Date() 时,它总是返回特定的时间。

我发现 Sinon.js 提供了 useFakeTimers 来模拟时间。但是下面的代码对我不起作用。

sinon.useFakeTimers(new Date(2011,9,1));

//expect : 'Sat Oct 01 2011 00:00:00' ,

//result : 'Thu Oct 27 2011 10:59:44‘
var d = new Date();

【问题讨论】:

  • 只需覆盖DateDate = function(){return 'Sat Oct 01 2011 00:00:00'};

标签: javascript


【解决方案1】:

sinon.useFakeTimers 接受时间戳(整数)作为参数,而不是 Date 对象。

试试

clock = sinon.useFakeTimers(new Date(2011,9,1).getTime());
new Date(); //=> return the fake Date 'Sat Oct 01 2011 00:00:00'

clock.restore();
new Date(); //=> will return the real time again (now)

如果您使用 setTimeout 之类的内容,请务必阅读文档,因为 useFakeTimers 会破坏该代码的预期行为。

【讨论】:

  • 这里是问题的确切link
【解决方案2】:

这样的事情怎么样?

var oldDate = Date;
Date = function (fake)
{
   return new oldDate('03/08/1980');
}

var x = new Date();
document.write(x);

你当然会运行:

Date = oldDate;

当您想恢复正常行为时。

【讨论】:

  • 这很简洁,但不应该用于大型和复杂的测试套件。在这种情况下首选 Sinon.js,专门用于处理“恢复”(恢复原始 Date 构造函数)
  • afterEach期间不要忘记Date = oldDate
  • @tothemario 为什么Sinon比这种方法更受欢迎?
  • @guptron - 可能是因为他是 Sinon.js 的作者 :)
  • @MikeChristensen 这似乎不是github.com/sinonjs/sinon/graphs/contributors
【解决方案3】:

你也可以使用Proxies:

window.Date = new Proxy(Date, {
    construct: function(target, args) {
        if (args.length === 0) {
            return new target(2017, 04, 13, 15, 03, 0);
        }
        return new target(...args);
    }
});

【讨论】:

  • 这个答案效果最好,只要你只需要在 JS 中伪造时间用于测试目的,除非你需要 Sinon.js 的其他功能
  • 实际上这并没有处理 Date.now(),所以我添加了它并将它作为一个小工具在 npm 上发布:github.com/capaj/proxy-date
【解决方案4】:

这是我的项目所需要的。有点复杂,但据我所知,这都是必需的。内部 Date() 是一个奇怪的野兽。下面的代码也使用了下划线。

(window || global).Date = (function (orgDate) {
    var fakeDate = function (y, m, d, ho, mi, se, mil) {
        var backendDate;
        if (arguments.length > 3) {
            backendDate = new orgDate(y, m, d, ho || 0, mi || 0, se || 0, mil || 0);
        } else if (arguments.length > 1) {
            backendDate = new orgDate(y, m || 0, d || 0);
        } else if (arguments.length > 0) {
            backendDate = new orgDate(y);
        } else {
            backendDate = new orgDate();
            backendDate.setFullYear(2015);  // <-- Your year here
            backendDate.setMonth(1);        // <-- Your month here
            backendDate.setDate(2);         // <-- Your day here
        }
        if (this) {
            this.backendDate = backendDate;
        }
        return backendDate.toString();
    }
    _.each(("getDate getDay getFullYear getHours getMilliseconds getMinutes " +
            "getMonth getSeconds getTime getTimezoneOffset getUTCDate getUTCDay " +
            "getUTCFullYear getUTCHours getUTCMilliseconds getUTCMinutes " +
            "getUTCMonth getUTCSeconds getYear parse setDate setFullYear setHours " +
            "setMilliseconds setMinutes setMonth setSeconds setTime setUTCDate " +
            "setUTCFullYear setUTCHours setUTCMilliseconds setUTCMinutes " +
            "setUTCMonth setUTCSeconds setYear toDateString toGMTString " +
            "toISOString toJSON toLocaleDateString toLocaleTimeString " +
            "toLocaleString toString toTimeString toUTCString UTC valueOf").split(" "),
        function (fnName) {
            fakeDate.prototype[fnName] = function () {
                return this.backendDate[fnName].apply(this.backendDate, arguments);
            }
        });
    return fakeDate;
})(window.Date);

【讨论】:

    【解决方案5】:

    我最终做了:

    var oldDate = Date;
    Date = function (fake)
    {
        if( ! fake ) return new oldDate('02/26/2017');
    
        return new oldDate(fake);
    }
    Date.prototype = oldDate.prototype;
    

    【讨论】:

      【解决方案6】:

      sinon.useFakeTimers 在内部使用 lolex。所以它支持对象作为lolex的参数

      sinon.useFakeTimers(new Date(2019,1,1)) 
      

      等价于

      sinon.useFakeTimers({
      now:new Date(2019,1,1)
      }) 
      

      我的任务是在每个集成测试中使用相同的开始日期(因为日期应该与文件中的数据相关联) 那我怎么用呢

       clock = sinon.useFakeTimers({
        now,
        shouldAdvanceTime: true,
        advanceTimeDelta: 20
      });
      

      shouldAdvanceTime 将允许 lolex 和 sinon 在我的集成测试中不停止计时器。 另请查看config.toFake 参数。它允许避免模拟一些函数,如setTimeout。或者只是模拟 Date 构造函数

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-01
        • 1970-01-01
        • 2018-06-03
        • 1970-01-01
        • 1970-01-01
        • 2010-11-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多