1

I'm trying to test an extension designed to work only in my workplace (intranet). More specifically, I placed breakpoints in points of an alarm-triggered routine, where I read the system time at 2 specific times of the day; one close to midnight and the other around 05:00 P.M. In order not to have to wait for these two moments of the day, I would like to move the system time close to these two times, but I can't do it because system administrators have disabled this option.

So I'm here to ask for your help. It is possible to "override" the Date object so that it returns a fake time shifted (forward or backward) by a constant value decided by me on the spot.

Furthermore, time must flow normally.

Taking a practical example, if I now launch this command in the console:
dt = new Date()

I get

Fri Apr 14 2023 10:50:00 GMT+0200

after overriding it should display

Fri Apr 14 2023 23:50:00 GMT+0200

I want the time moved forward 13 hours. Of course I should activate this movement with a command like:

shiftDate.move(13)

and to make things right again something like:

shiftDate.reset();

All methods\properties of the Date object must remain unchanged.

Can you give me a hand please?

Thanks in advance

syncmate
  • 160
  • 9
  • are you testing on browsers? – Khairani F Apr 14 '23 at 09:57
  • Why not just wrap the date in your own function that can return whatever you'd like? Don't access `Date` directly outside of that function. – user229044 Apr 14 '23 at 11:14
  • That's basically a good part of what I'd like to achieve. I'm not afraid to replace the word "Date" with "myDate" (or another word), but I want to keep all the methods and properties of the Date class. I hope that to get what I want I don't actually have to rewrite all the "get" and "set" methods of a new class that refers to a date that is shifted from the real one. I really hope it's simpler, but I really don't know where to start. – syncmate Apr 14 '23 at 11:25
  • The ironic thing is that if I try to test my code from home using a VPN, the moment I change the system time the VNP connection drops as it detects a different time than the real time and therefore a potential security threat. – syncmate Apr 14 '23 at 11:33

3 Answers3

1

This article might help. https://www.browserstack.com/guide/change-time-zone-in-chrome-for-testing

Try Method 1: Using Developer Tools to Change Chrome Timezone in particular.

  1. Open DevTools in Chrome -> Open the Console drawer.
  2. Click on the three-dotted menu -> Click on More tools -> Sensors.
  3. From the Sensors tab, set the location according to your preference and define the specific timezone.
Khairani F
  • 248
  • 2
  • 7
  • Hi @Khair and thank you for your suggestion. Unfortunately this does not work as it is only a representation of the date\time and nothing more. If you try to invoke the **.now()** or **.getTime()** method with and without the sensor timezone override you will see that the number indicating milliseconds since January 1, 1970 remains the same. Might be fine if you just want to test the hours with .getHours(). Overriding would return a different number in this case. With tests like: if (Date.now() > mySavedTime) ... it wouldn't change anything – syncmate Apr 14 '23 at 11:09
1

I found a solution, perhaps trivial but it seems to work.

const fakeDate = {
    set:        function(y, m, d, h, m, s) {
                    if (typeof DateObjBck !== 'undefined')
                        this.reset();

                    /*Saving the original Date object */
                    DateObjBck = Date;

                    /* set the clock closed to midnight */
                    var startFrom = new Date(...arguments);

                    /*Calculating the constat offset between real time and the fake one */
                    const offsetMs = startFrom.getTime() - (new DateObjBck).getTime();
                    
                    /* Now I rewrite the Date object */
                    Date =  function(...args) {
                                if (args.length > 0)
                                    return new DateObjBck(...args);
                                else {
                                    var veryNow = (new DateObjBck).getTime();
                                    return new DateObjBck(veryNow + offsetMs)                                   
                                }
                            };
                    Date.now =  function() {
                                    var veryNow = (new DateObjBck).getTime();
                                    return veryNow + offsetMs
                                }
                },
    reset:  function() {
                    Date = DateObjBck;
                    DateObjBck = undefined
            }
}

fakeDate.set(2023, 3, 13, 23, 55, 0);
console.log('0', new Date());
console.log('1', new Date);
console.log('2', Date.now());
console.log('3', new Date(2020, 5, 15, 22, 50, 0));
console.log('4', new Date);
fakeDate.reset();
console.log('5', new Date);
syncmate
  • 160
  • 9
  • Careful! You've completely overridden the internal Date function and properties, losing quite a bit of functionality in doing so. (ex. `Date.now()`) Generally speaking, [changing the behavior of native objects isn't recommended](https://stackoverflow.com/a/14034242/13171687). – cirex Apr 14 '23 at 23:09
  • you're right, there are many other corners to round off. I rewrite a bit the code snippet, now I'm going to edit my previous answer. – syncmate Apr 15 '23 at 10:04
1

Because Date is a class, we can extend it to provide additional functionality without tampering with the existing static properties/methods.

For instance, you can write a new class like ShiftedDate below:

class ShiftedDate extends Date{
    static #offsetMs = 0; //private static field
    static move(ms){
        this.#offsetMs = ms;
    }
    static moveHours(hours){
        this.move(hours*60*60*1000); 
    }
    static setTime(...args){
        this.move(new Date(...args)-new Date());
    }
    static now(){ //The only static function I can think of that doesn't depend on instance time. 
        return super.now()+this.#offsetMs;
    }
    constructor(...args){
        super(...args); 
        if(args.length===0)this.setTime(this.getTime()+ShiftedDate.#offsetMs); //Don't shift explicit dates
    }
}

And use it as such:

const originalDate = new ShiftedDate();
console.log(new ShiftedDate()); //2023-04-15T11:49:01.943Z

ShiftedDate.moveHours(2);
console.log(new ShiftedDate()); //2023-04-15T13:49:02.018Z

ShiftedDate.setTime("7/12/2012");
console.log(new ShiftedDate()); //2012-07-12T00:00:00.000Z

console.log(originalDate); //2023-04-15T11:49:01.943Z - Old dates are not updated
console.log(ShiftedDate.now()); //1342051200000 (7/12/12)
cirex
  • 66
  • 6
  • Good, the only drawback is that I have to replace many occurrences of "Date" with "ShiftedDate", but that's not a big deal because the operation is easily reversible. Thank you – syncmate Apr 15 '23 at 11:22
  • @syncmate No problem! I've added an additional setTime function as well. – cirex Apr 15 '23 at 11:53