1

My program needs to be able to change the SystemDate on the machine. After looking around I found this code and implemented it, however it does not seem to change the date at all. The VM it is running on has time sync turned off, so I know the issue does not lie there. Have I made a small mistake, or is there an easier way to change the system date?

[StructLayout(LayoutKind.Sequential)]
private struct SYSTEMTIME
{
    public short wYear;
    public short wMonth;
    public short wDayOfWeek;
    public short wDay;
    public short wHour;
    public short wMinute;
    public short wSecond;
    public short wMilliseconds;
}

// Return Type: BOOL
[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "SetSystemTime")]
[return:System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
private static extern bool SetSystemTime([InAttribute()] ref SYSTEMTIME lpSystemTime);



public bool SetSystemDateTime(DateTime newDateTime)
{
    bool result = false;

    try
    {
        newDateTime = newDateTime.ToUniversalTime();

        SYSTEMTIME sysTime = new SYSTEMTIME() 
            { wYear = (short)newDateTime.Year /* must be short */, 
            wMonth = (short)newDateTime.Month, 
            wDayOfWeek = (short)newDateTime.DayOfWeek, 
            wDay = (short)newDateTime.Day, 
            wHour = (short)newDateTime.Hour, 
            wMinute = (short)newDateTime.Minute, 
            wSecond = (short)newDateTime.Second, 
            wMilliseconds = (short)newDateTime.Millisecond };

        result = SetSystemTime(ref sysTime);
    }
    catch (Exception)
    {
        result = false;
    }
    return result;
}
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
JBelter
  • 415
  • 2
  • 5
  • 13

2 Answers2

2

Run this as administrator as it works for me. The code is from the Pinvoke.net documentation for SetSystemTime, although I've added an extra Console.Read after setting the time so that it's possible to see that the system time has changed before it's set back to the original time.

public struct SYSTEMTIME
{
   public ushort wYear, wMonth, wDayOfWeek, wDay,
          wHour, wMinute, wSecond, wMilliseconds;
}

[DllImport("kernel32.dll")]
public extern static void GetSystemTime(ref SYSTEMTIME lpSystemTime);

[DllImport("kernel32.dll")]
public extern static uint SetSystemTime(ref SYSTEMTIME lpSystemTime);

Console.WriteLine(DateTime.Now.ToString());
SYSTEMTIME st = new SYSTEMTIME();
GetSystemTime(ref st);

Console.WriteLine("Adding 1 hour...");
st.wHour = (ushort)(st.wHour + 1 % 24);
if (SetSystemTime(ref st) == 0)
    Console.WriteLine("FAILURE: SetSystemTime failed");

Console.WriteLine(DateTime.Now.ToString());
Console.Read();

Console.WriteLine("Setting time back...");
st.wHour = (ushort)(st.wHour - 1 % 24);
SetSystemTime(ref st);
Console.WriteLine(DateTime.Now.ToString());
Console.WriteLine("Press Enter to exit");
Console.Read();
keyboardP
  • 68,824
  • 13
  • 156
  • 205
1

The application is being run as an administrator

That doesn't mean much these days, lots of users login to Windows with an admin account. What matters is that you run this code elevated. Which requires a manifest with the "requireAdministrator" attribute so the user gets the UAC elevation prompt.

Significant flaws in the code is that it is way to easy to ignore the return value of the function. Also without any way to find out why it returned false. The [DllImport] is flawed, it doesn't set the SetLastError property to true. Catching Exception without generating a diagnostic is a plain bad idea, remove that. Fix:

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetSystemTime(ref SYSTEMTIME lpSystemTime);
...
if (!SetSystemTime(ref sysTime)) {
   throw new System.ComponentModel.Win32Exception();
}
Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • If I add in the manifest, will that mess things up running the application on my VM (which is running Windows Server 2003 R2) since there isn't UAC on Windows Server 2003? – JBelter Jul 08 '13 at 17:33
  • 1
    No, it will just ignore entries in the manifest it doesn't understand. – Hans Passant Jul 08 '13 at 17:35