通过程序更改系统日期

65

如何使用C#编程更改本地系统的日期和时间?

10个回答

97

这里是我找到答案的地方。我在这里重新发布它以提高阅读清晰度。

定义这个结构:

[StructLayout(LayoutKind.Sequential)]
public 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;
}

向你的类中添加以下extern方法:

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetSystemTime(ref SYSTEMTIME st);

然后使用您的结构的实例调用该方法,如下:

SYSTEMTIME st = new SYSTEMTIME();
st.wYear = 2009; // must be short
st.wMonth = 1;
st.wDay = 1;
st.wHour = 0;
st.wMinute = 0;
st.wSecond = 0;

SetSystemTime(ref st); // invoke this method.

4
编写自定义的C++/CLI包装器并引入另一个程序集比编写一个近乎9行的结构体更容易吗? - Lucas
不要让 Marc Gravell 看到你的结构体!;-) - si618
3
我的答案编辑因某些原因被拒绝了,但至少对于Win 7,我发现我需要以管理员身份运行程序才能使其正常工作。请参见:https://dev59.com/m3E85IYBdhLWcg3wXCIv - Dan W
10
这个方法会将时间设置为UTC时间。因此,如果您使用Datetime.Now获取本地时间,则会设置错误的时间。我遇到了这个问题很长一段时间都不能理解出错在哪里...... - Denis Koreyba
5
需要提醒的是,该程序需要管理员权限才能正常运行... - Christopher Smit
答案中的链接已失效。 - faheem khan

18

这里已经有很多好的观点和方法,但是有一些规范目前被忽略了,我感到这可能会使一些人出现问题并感到困惑。

  1. Windows Vista、7、8操作系统上,为了成功执行SetSystemTime函数,需要UAC提示框以获取必要的管理员权限。原因在于调用进程需要SE_SYSTEMTIME_NAME特权。
  2. SetSystemTime函数期望以协调世界时(UTC)为基础的SYSTEMTIME结构。否则它将无法按预期工作。

根据你从哪里/如何获得你的DateTime值,最好在设置相应值之前使用ToUniversalTime()以保险起见。

代码示例:

DateTime tempDateTime = GetDateTimeFromSomeService();
DateTime dateTime = tempDateTime.ToUniversalTime();

SYSTEMTIME st = new SYSTEMTIME();
// All of these must be short
st.wYear = (short)dateTime.Year;
st.wMonth = (short)dateTime.Month;
st.wDay = (short)dateTime.Day;
st.wHour = (short)dateTime.Hour;
st.wMinute = (short)dateTime.Minute;
st.wSecond = (short)dateTime.Second;

// invoke the SetSystemTime method now
SetSystemTime(ref st); 

我不能直接使用这个更改系统时间。 - Hiren Raiyani
2
我已经成功地在多个项目中使用了这段代码。你是以管理员身份运行可执行文件吗?否则,这段代码肯定无法工作。 - Derek W
3
哇,这个解决了我的问题。问题在于本地时间的时区妨碍了获取正确的时间,所以“DateTime dateTime = tempDateTime.ToUniversalTime();”这行代码解决了所有问题。 - Daren Delima

16

你可以使用调用DOS命令的方式,但在Windows dll中调用该函数是更好的方法。

public struct SystemTime
{
    public ushort Year;
    public ushort Month;
    public ushort DayOfWeek;
    public ushort Day;
    public ushort Hour;
    public ushort Minute;
    public ushort Second;
    public ushort Millisecond;
};

[DllImport("kernel32.dll", EntryPoint = "GetSystemTime", SetLastError = true)]
public extern static void Win32GetSystemTime(ref SystemTime sysTime);

[DllImport("kernel32.dll", EntryPoint = "SetSystemTime", SetLastError = true)]
public extern static bool Win32SetSystemTime(ref SystemTime sysTime);

private void button1_Click(object sender, EventArgs e)
{
    // Set system date and time
    SystemTime updatedTime = new SystemTime();
    updatedTime.Year = (ushort)2009;
    updatedTime.Month = (ushort)3;
    updatedTime.Day = (ushort)16;
    updatedTime.Hour = (ushort)10;
    updatedTime.Minute = (ushort)0;
    updatedTime.Second = (ushort)0;
    // Call the unmanaged function that sets the new date and time instantly
    Win32SetSystemTime(ref updatedTime);
}  

9

使用此函数更改系统时间(在Windows 8中测试过)

 void setDate(string dateInYourSystemFormat)
    {
        var proc = new System.Diagnostics.ProcessStartInfo();
        proc.UseShellExecute = true;
        proc.WorkingDirectory = @"C:\Windows\System32";
        proc.CreateNoWindow = true;
        proc.FileName = @"C:\Windows\System32\cmd.exe";
        proc.Verb = "runas";
        proc.Arguments = "/C date " + dateInYourSystemFormat;
        try
        {
            System.Diagnostics.Process.Start(proc);
        }
        catch
        {
            MessageBox.Show("Error to change time of your system");
            Application.ExitThread();
        }
    }
void setTime(string timeInYourSystemFormat)
    {
        var proc = new System.Diagnostics.ProcessStartInfo();
        proc.UseShellExecute = true;
        proc.WorkingDirectory = @"C:\Windows\System32";
        proc.CreateNoWindow = true;
        proc.FileName = @"C:\Windows\System32\cmd.exe";
        proc.Verb = "runas";
        proc.Arguments = "/C time " + timeInYourSystemFormat;
        try
        {
            System.Diagnostics.Process.Start(proc);
        }
        catch
        {
            MessageBox.Show("Error to change time of your system");
            Application.ExitThread();
        }
    }

例子: 在表单的load方法中调用 设置日期为"92年5月6日" 设置时间为"上午2点4分5秒"


这是一个经过测试、准备好编译和运行的代码版本,您可以在以下链接中找到:https://github.com/jtara1/MiscScripts/blob/master/MiscScripts/UpdateOSTime.cs。由于我不熟悉C#或这些库,所以我至少查阅了4个StackOverflow页面。 - James T.

7
  1. 使用PInvoke调用Win32 API SetSystemTime,(示例)。
  2. 使用System.Management类和WMI类Win32_OperatingSystem,并在该类上调用SetDateTime。

两者都要求调用者已被授予SeSystemTimePrivilege权限并启用此权限。


5
一个复制/粘贴类,适用于其他需要的人。
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public static class SystemDateTime
{
    [DllImport("kernel32.dll", EntryPoint = "SetSystemTime", SetLastError = true)]
    private static extern bool Win32SetSystemTime(ref SystemTime sysTime);

    [StructLayout(LayoutKind.Sequential)]
    public struct SystemTime
    {
        public ushort Year;
        public ushort Month;
        public ushort DayOfWeek;
        public ushort Day;
        public ushort Hour;
        public ushort Minute;
        public ushort Second;
        public ushort Millisecond;
    };

    public static void SetSystemDateTime(int year, int month, int day, int hour,
        int minute, int second, int millisecond)
    {
        SystemTime updatedTime = new SystemTime
        {
            Year = (ushort) year,
            Month = (ushort) month,
            Day = (ushort) day,
            Hour = (ushort) hour,
            Minute = (ushort) minute,
            Second = (ushort) second,
            Millisecond = (ushort) millisecond
        };

        // If this returns false, then the problem is most likely that you don't have the 
        // admin privileges required to set the system clock
        if (!Win32SetSystemTime(ref updatedTime))
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
    }

    public static void SetSystemDateTime(DateTime dateTime)
    {
        SetSystemDateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute,
            dateTime.Second, dateTime.Millisecond);
    }
}

运行得非常完美。 - Nick Chan Abdullah

3

因为我在评论中提到了它,这里有一个C++/CLI包装器:

#include <windows.h>
namespace JDanielSmith
{
    public ref class Utilities abstract sealed /* abstract sealed = static */
    {
    public:
        CA_SUPPRESS_MESSAGE("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")
        static void SetSystemTime(System::DateTime dateTime) {
            LARGE_INTEGER largeInteger;
            largeInteger.QuadPart = dateTime.ToFileTimeUtc(); // "If your compiler has built-in support for 64-bit integers, use the QuadPart member to store the 64-bit integer."


            FILETIME fileTime; // "...copy the LowPart and HighPart members [of LARGE_INTEGER] into the FILETIME structure."
            fileTime.dwHighDateTime = largeInteger.HighPart;
            fileTime.dwLowDateTime = largeInteger.LowPart;


            SYSTEMTIME systemTime;
            if (FileTimeToSystemTime(&fileTime, &systemTime))
            {
                if (::SetSystemTime(&systemTime))
                    return;
            }


            HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
            throw System::Runtime::InteropServices::Marshal::GetExceptionForHR(hr);
        }
    };
}

C#客户端代码现在非常简单:

JDanielSmith.Utilities.SetSystemTime(DateTime.Now);

我试了一下你的代码,但好像不起作用。https://gist.github.com/jtara1/07cfd5ebffab8296564f86000c50510e 无论如何,我找到了我想要的解决方案并测试了一下 https://github.com/jtara1/MiscScripts/blob/00a5d330d784d7e423c0f8a83172ddfc31aad3fa/MiscScripts/UpdateOSTime.cs - James T.

1

请注意!如果您从结构中删除未使用的属性,则会设置错误的时间。我因此失去了一天。我认为结构的顺序很重要。

这是正确的结构:

public struct SystemTime
        {
            public ushort Year;
            public ushort Month;
            public ushort DayOfWeek;
            public ushort Day;
            public ushort Hour;
            public ushort Minute;
            public ushort Second;
            public ushort Millisecond;

        };

如果您运行SetSystemTime(),它会按预期工作。为了测试,我将时间设置如下;
SystemTime st = new SystemTime();
st.Year = 2019;
st.Month = 10;
st.Day = 15;
st.Hour = 10;
st.Minute = 20;
st.Second = 30;

SetSystemTime(ref st);

时间设置为:2019年10月15日 10:20,没问题。

但我删除了未使用的DayOfWeek属性;

public struct SystemTime
            {
                public ushort Year;
                public ushort Month;
                public ushort Day;
                public ushort Hour;
                public ushort Minute;
                public ushort Second;
                public ushort Millisecond;

            };

SystemTime st = new SystemTime();
    st.Year = 2019;
    st.Month = 10;
    st.Day = 15;
    st.Hour = 10;
    st.Minute = 20;
    st.Second = 30;

    SetSystemTime(ref st);

运行相同的代码,但将时间设置为:2019年10月10日20:30

请注意SystemTime结构的顺序和所有字段。

Yusuf


SetSystemTime 函数需要一个具有精确字段的结构体。如果您传递一个具有不同字段的结构体(少字段,顺序不同,类型不同等),它将无法正常工作。如果您删除 DayOfWeek 字段,则 SetSystemTime 仍然期望该字段存在,因此从 Day 开始的字段都会被移位,最后一个字段也会丢失。 - user276648

0

另一个选项(受this answer启发)是引用Microsoft.VisualBasic程序集:

public bool isTimeCorrected;
public string errorMessage;
public void SetLocalClock(DateTime newLocalTime)
{
    try
    {
        Microsoft.VisualBasic.DateAndTime.TimeOfDay = newLocalTime;
        Microsoft.VisualBasic.DateAndTime.Today = newLocalTime;
        isTimeCorrected = true;
    }
    catch (Exception e)
    {
        errorMessage = e.Message;
        isTimeCorrected = false;
    }
}

注意:项目中必须添加对 Microsoft.VisualBasic 的引用。
<Reference Include="Microsoft.VisualBasic" />

-5

proc.Arguments = "/C 日期:" + dateInYourSystemFormat;

这是工作函数:

void setDate(string dateInYourSystemFormat)
{
    var proc = new System.Diagnostics.ProcessStartInfo();
    proc.UseShellExecute = true;
    proc.WorkingDirectory = @"C:\Windows\System32";
    proc.CreateNoWindow = true;
    proc.FileName = @"C:\Windows\System32\cmd.exe";
    proc.Verb = "runas";
    proc.Arguments = "/C Date:" + dateInYourSystemFormat;
    try
    {
        System.Diagnostics.Process.Start(proc);
    }
    catch
    {
        MessageBox.Show("Error to change time of your system");
        Application.ExitThread();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接