Random header image... Refresh for more!

Temporal Mechanics: Changing the Speed of Time, Part II

So, you want to change the speed of time, eh?  Now, I trust that you’re only going to change this on your own computer and not do anything to your coworker’s computer when they go for coffee and leave their machine unlocked and unattended for a few minutes, correct?  Okay, let’s begin.

First, before you go changing the speed of time, let’s see how fast time is going.  In order to do that, there’s a Win32 function called “GetSystemTimeAdjustment”.  Here’s the signature:

BOOL WINAPI GetSystemTimeAdjustment(
    __out PDWORD lpTimeAdjustment,
    __out PDWORD lpTimeIncrement,
    __out PBOOL lpTimeAdjustmentDisabled
);

Of course, Win32 C is terribly ugly and nasty to work with, so I’m going to do this in C#.  That means a P/Invoke, but at least I won’t have to deal with __out PDWORDs and the like.  Here’s that bit:

[DllImport("kernel32.dll")]
public static extern bool GetSystemTimeAdjustment(out uint timeAdjustment, out uint timeIncrement, out bool timeAdjustmentDisabled);

It’s still sort of ugly, but not nearly as totally ugly, so it’s all right.  If you’re not completely familiar with all of this DllImport stuff and static externs and out parameters, that’s okay.  I’m going to mock your ignorance of the language, but aside from that, it’s no big deal.  Now let’s give it a call and see who answers.

uint timeAdjustment;
uint timeIncrement;
bool timeAdjustmentDisabled;

GetSystemTimeAdjustment(out timeAdjustment, out timeIncrement, out timeAdjustmentDisabled);

Console.WriteLine("Adjustment: {0} Increment: {1} Adjustment Disabled: {2}", timeAdjustment, timeIncrement, timeAdjustmentDisabled);

On my current home machine (XP, not on a domain), I get this as the output:

Adjustment: 156250  Increment: 156250  Adjustment Disabled: True

If you recall my previous entry on this topic, you’ll remember that the Windows Time Service would add a certain number of 100ns units to the system clock every 15.6 ms or so.  The Adjustment number is the number of 100ns ticks it will add, and the Increment number is the number of 100ns ticks of supposedly “real” time that will elapse between time adjustments.  Obviously, Increment is not completely accurate, it doesn’t mean precisely 15.625 ms of real world time, because if it did, then Adjustment would always equal Increment, and your clock would be completely accurate with no drift whatsoever, so there would be no need for automatic adjustments.  In this case, Adjustment does equal Increment.  However, if you look at the final value, Adjustment Disabled is true.  That means the automatic time adjustments are disabled.  When that’s disabled, the Windows Time Service isn’t doing any of the gradual corrections that I talked about in the last post, instead, it considers your physical clock ticks to be good enough.  Your computer clock will likely drift over time.  On my machine, I’m not joined to a domain or anything like that.  Instead, I’m configured to talk to time.windows.com once a week and resync my clock.

Of course, printing that information out just once is somewhat boring.  I strongly recommend putting it in a loop and printing it out every couple of seconds.

while (true)
{
    GetSystemTimeAdjustment(out timeAdjustment, out timeIncrement, out timeAdjustmentDisabled);
    Console.WriteLine("Adjustment: {0} Increment: {1} Adjustment Disabled: {2}", timeAdjustment, timeIncrement, timeAdjustmentDisabled);
    Thread.Sleep(5000);
}

If you’re on a domain or otherwise have your system clock actively and frequently being kept in line by something, I would strongly urge you to do the following fun experiment at this point.

  1. Compile this program.
  2. Run this program.
  3. If Adjustment Disabled == false, put your computer’s clock ahead or back a minute or so.
  4. Watch the program for a while.

You’ll see something like this over the course of the next 20 minutes or so (Your numbers will vary).

Adjustment: 156250  Increment: 156250  Adjustment Disabled: False
Adjustment: 145125  Increment: 156250  Adjustment Disabled: False
Adjustment: 154412  Increment: 156250  Adjustment Disabled: False
Adjustment: 156159  Increment: 156250  Adjustment Disabled: False
Adjustment: 156225  Increment: 156250  Adjustment Disabled: False
Adjustment: 156247  Increment: 156250  Adjustment Disabled: False
Adjustment: 156249  Increment: 156250  Adjustment Disabled: False
Adjustment: 156250  Increment: 156250  Adjustment Disabled: False

Remember that adjustment is how much time is being added to your system’s clock at each tick.  The Windows Time Service synced with your domain controller and realized that your system time was off by about a minute.  Because of that, it decided that it needed to run slow for a bit to allow reality to catch up.  When Adjustment went to 145125, it meant that every 15.6 ms, the computer only added 14.5 ms to its timer.  A difference of only 1.1 ms per tick, but when you consider that there are about 64 ticks in a second and 60 seconds in a minute, you’re talking a difference of over 4 seconds per minute of real time.  Which means that at a rate like that, every minute of real time will only be 56 seconds in warped computer time.  That will very quickly add up and within 15 minutes, that minute you set your clock off will be made up.

However, the Time Service is cautious and doesn’t wish to over correct, so it will shoot for lower than the full time offset.  That means basically that instead of trying to close the full minute in one shot, it’ll pull back only 50 seconds.  Then it will go seven seconds, then two seconds, then a fraction of a second.  My experience with the time service is that the adjust will try to softly land on Increment, getting closer and closer until the two are even.

Under normal circumstances, if Adjustment is higher than Increment, it means that your clock is running slow and the Time Service is speeding up your system’s time to catch up with reality.  If Adjustment is lower than Increment, your clock is ahead and the Windows Time Service will put on the brakes and decelerate time to allow reality to catch up.

Normal circumstances aren’t much fun, though.  Let’s go for a few abnormal circumstances, shall we?

I did promise that you would be able to change the speed of time on your own.  That means no Time Service involvement.  If you want your clock to take off like a Prius with a stuck accelerator and janky brakes, I can help you make that happen.

There’s a GetSystemTimeAdjustment, so naturally, there’s gotta be a SetSystemTimeAdjustment.

BOOL WINAPI SetSystemTimeAdjustment(
    __in DWORD dwTimeAdjustment,
    __in BOOL bTimeAdjustmentDisabled
);

Let’s sharpen that up a bit…

[DllImport("kernel32.dll")]
public static extern bool SetSystemTimeAdjustment(uint timeAdjustment, bool timeAdjustmentDisabled);

It should be noted that the DWORD parameter of the C turns into a uint argument.  Initially, I had written the P/Invoke signature using a signed integer.  I thought it would be fun to set the time adjustment to -156250, to watch the clock go backwards.  Unfortunately, when -156250 gets treated as an unsigned integer, it becomes, well, 4294811045.  So, instead of watching my computer’s clock run backwards, I saw it zoom to the future at a rate of a day every 3.14 seconds.  Which, I have to admit, was totally awesome.

Anyway, I strongly suggest that you first call GetSystemTimeAdjustment and see what the adjustment value is first, so that you’ll have a good idea of where you want to set the value to get the effect you want.  Rememember, double the base and the clock goes twice as fast, cut the base in half and your clock moves at half speed.  I haven’t found a way to go back in time yet, but that sort of thing only causes universe destroying paradoxes, so perhaps that’s for the best.

So, now, if you run it, giving some reasonable (or unreasonable) number as the value of Adjustment, what you’ll probably find is that ABSOLTELY NOTHING happens.  This is, of course, the unseen impact of the Temporal Security Agency preventing you from tampering with time. 1  They don’t like it when you mess with that sort of thing.  To get around that, you have to ask for the “SE_SYSTEMTIME_NAME” privilege beforehand.  I have no idea at all what that means, I just know that the documentation says you need it and offers you no practical guidance whatsoever as to how you’re supposed to acquire it.

What to do when you’re faced with obtuse documentation on an obscure subject like Win32 Privilege Tokens?  Steal the code from the Internet, of course.

        //The code in this block is not mine and I make no claims to it.
        //I don't really even know what it's doing...
        #region Code stolen from the Internet.
        private const int ANYSIZE_ARRAY = 1;
        private const string SE_SYSTEMTIME_NAME = "SeSystemtimePrivilege";
        private const int SE_PRIVILEGE_ENABLED = 0x00000002;
        private const int TOKEN_QUERY = 0x0008;
        private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public int LowPart;
            public int HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID_AND_ATTRIBUTES
        {
            public LUID Luid;
            public int Attributes;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct TOKEN_PRIVILEGES
        {
            public int PrivilegeCount;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)]
            public LUID_AND_ATTRIBUTES[] Privileges;
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool OpenProcessToken(int ProcessHandle, int DesiredAccess, ref int TokenHandle);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public static extern int GetCurrentProcess();

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
        public static extern bool AdjustTokenPrivileges(int TokenHandle, int DisableAllPrivileges, [MarshalAs(UnmanagedType.Struct)] ref TOKEN_PRIVILEGES NewState, int BufferLength, [MarshalAs(UnmanagedType.Struct)] ref TOKEN_PRIVILEGES PreviousState, ref int ReturnLength);

        public static bool AdjustPrivileges()
        {
            TOKEN_PRIVILEGES tkNew = new TOKEN_PRIVILEGES();
            tkNew.Privileges = new LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY];
            TOKEN_PRIVILEGES tkOld = new TOKEN_PRIVILEGES();
            tkOld.Privileges = new LUID_AND_ATTRIBUTES[ANYSIZE_ARRAY];

            LUID luid = new LUID();
            int token = -1;
            int oldluidSize = 0;

            if (LookupPrivilegeValue(null, SE_SYSTEMTIME_NAME, ref luid))
            {
                if (OpenProcessToken(GetCurrentProcess(),
                TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref token))
                {
                    tkNew.PrivilegeCount = 1;
                    tkNew.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                    tkNew.Privileges[0].Luid = luid;
                    int luidSize = Marshal.SizeOf(typeof(TOKEN_PRIVILEGES));
                    if (AdjustTokenPrivileges(token, 0, ref tkNew, luidSize, ref tkOld, ref oldluidSize))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        #endregion Code stolen from the Internet.

That code isn’t mine.  I don’t know whose it is and I don’t know what it does exactly.  All I know is it magically makes all the time stuff work, and for that I am grateful.  Anyway, now all you should have to do is add a call to AdjustPrivileges() at some point before you try to call SetSystemTimeAdjustment.  Like so:

    if (!AdjustPrivileges())
    {
        throw new Exception("AdjustPrivileges failed.");
    }

    if (!SetSystemTimeAdjustment(312500, false))
    {
        throw new Exception("SetSystemTimeAdjustment failed.");
    }

 

Before you run this, let me just warn you not to run this.  I don’t know what it’s going to do to your computer.  You’re changing time randomly.  That can never be a good thing.  So don’t do it.

Since you’re going to do it anyway, here’s two ways to try to get yourself out of an uncontrolled time slide.  Kill the program first, then try to resynchronize your clock by going into your taskbar clock and telling it to update the time.  If that doesn’t work, stop and restart the Windows Time Service.  And if that doesn’t work, well, I told you not to do it and you didn’t listen to me, so don’t go blaming me.

The source code is located here, in case you don’t feel like typing in everything by hand: http://www.mathpirate.net/svn/Projects/SpeedOfTime/

Now, make sure you have a watch or a clock or something that will display seconds and that’s not tied to your computer in any way.  Make sure it’s roughly synchronized (within a second or two) of your computer.  Then press play and do the time warp.

What’s checked in will cause your computer to travel through time twice as fast as reality.  You can, of course, tweak the number and modify how fast or slow you want to go.  Pay attention to the read-out, though.  If the Windows Time Service is actively adjusting your time, it will likely override your temporal anomaly and either fix the clock outright, or at least modify the adjustment so you start to return to normality.  To prevent unwanted chronometric realignment, you may want to stop the Windows Time Service while you’re messing around.

For those of you smart enough not to play the home game, here’s a video which will demonstrate the effects of time compression and dilation.

And now, here’s the effects of a non-linear temporal anomaly.

  1. I know you’re there, Agent Blackwood! []

0 comments

There are no comments yet...

Kick things off by filling out the form below.

Leave a Comment