【问题标题】:Python module to change system date and time用于更改系统日期和时间的 Python 模块
【发布时间】:2012-08-18 08:38:09
【问题描述】:

如何在 Python 中更改系统日期、时间、时区?有没有可用的模块?

  1. 我不想执行任何系统命令
  2. 我想要一个通用的解决方案,它应该适用于 Unix 和 Windows。

【问题讨论】:

  • 鉴于系统权限和身份验证,这对于 Unix 和 Windows 来说都比您想象的要难。
  • @EngHamoud,我不认为datetime 模块可以设置系统时间。以下是WindowsLinux 中的一些方法。
  • @benhoyt :正确... datetime 在这种情况下没有用...感谢这两个解决方案.. 但我需要一个针对两个平台的组合解决方案。所以这不符合我的要求..
  • @Blender:感谢您再次教育我 :-) 如果有任何可用的东西可以使用,我不想浪费时间编写自己的东西。

标签: python date time


【解决方案1】:
import sys
import datetime

time_tuple = ( 2012, # Year
                  9, # Month
                  6, # Day
                  0, # Hour
                 38, # Minute
                  0, # Second
                  0, # Millisecond
              )

def _win_set_time(time_tuple):
    import pywin32
    # http://timgolden.me.uk/pywin32-docs/win32api__SetSystemTime_meth.html
    # pywin32.SetSystemTime(year, month , dayOfWeek , day , hour , minute , second , millseconds )
    dayOfWeek = datetime.datetime(time_tuple).isocalendar()[2]
    pywin32.SetSystemTime( time_tuple[:2] + (dayOfWeek,) + time_tuple[2:])


def _linux_set_time(time_tuple):
    import ctypes
    import ctypes.util
    import time

    # /usr/include/linux/time.h:
    #
    # define CLOCK_REALTIME                     0
    CLOCK_REALTIME = 0

    # /usr/include/time.h
    #
    # struct timespec
    #  {
    #    __time_t tv_sec;            /* Seconds.  */
    #    long int tv_nsec;           /* Nanoseconds.  */
    #  };
    class timespec(ctypes.Structure):
        _fields_ = [("tv_sec", ctypes.c_long),
                    ("tv_nsec", ctypes.c_long)]

    librt = ctypes.CDLL(ctypes.util.find_library("rt"))

    ts = timespec()
    ts.tv_sec = int( time.mktime( datetime.datetime( *time_tuple[:6]).timetuple() ) )
    ts.tv_nsec = time_tuple[6] * 1000000 # Millisecond to nanosecond

    # http://linux.die.net/man/3/clock_settime
    librt.clock_settime(CLOCK_REALTIME, ctypes.byref(ts))


if sys.platform=='linux2':
    _linux_set_time(time_tuple)

elif  sys.platform=='win32':
    _win_set_time(time_tuple)

我没有 windows 机器,所以我没有在 windows 上测试它……但你明白了。

【讨论】:

  • 使用if sys.platform.startswith('linux') 使用 Python >= 3.3。
  • 根据@jk987 的回答,正确的模块名称是win32api,而不是pywin32。此外,SetSystemTime 接受 8 个参数;您可以添加*,或者您可以添加remote_time = datetime.datetime.fromtimestamp(response.tx_time) + datetime.datetime.utcnow() - datetime.datetime.now(),然后添加win32api.SetSystemTime(remote_time.year, remote_time.month, remote_time.isoweekday(), remote_time.day, remote_time.hour, remote_time.minute, remote_time.second, remote_time.microsecond // 1000)
  • 干得好!但是 datetime.datetime() 接受微秒,而不是毫秒,所以你应该乘以 1000 而不是 1000000 才能将它们转换为纳秒。
  • 请注意,从 python 3.3 开始,此代码的 linux 部分可以使用 python time.clock_settime() 函数进行简化,而不是使用 ctypes 调用系统库。
【解决方案2】:

tMC 的回答似乎很棒。但是,它不适合我。我发现它需要一些更新,适用于 Linux 和 Windows + python 3。这是我更新的模块:

import sys
from _datetime import datetime

time_tuple = (2012,  # Year
              9,  # Month
              6,  # Day
              0,  # Hour
              38,  # Minute
              0,  # Second
              0,  # Millisecond
              )


def _win_set_time(time_tuple):
    import win32api
    dayOfWeek = datetime(*time_tuple).isocalendar()[2]
    t = time_tuple[:2] + (dayOfWeek,) + time_tuple[2:]
    win32api.SetSystemTime(*t)


def _linux_set_time(time_tuple):
    import subprocess
    import shlex

    time_string = datetime(*time_tuple).isoformat()

    subprocess.call(shlex.split("timedatectl set-ntp false"))  # May be necessary
    subprocess.call(shlex.split("sudo date -s '%s'" % time_string))
    subprocess.call(shlex.split("sudo hwclock -w"))


if sys.platform == 'linux2' or sys.platform == 'linux':
    _linux_set_time(time_tuple)

elif sys.platform == 'win32':
    _win_set_time(time_tuple)

对于 Linux,请阅读以下答案:Set the hardware clock in Python?

【讨论】:

  • 如上所述,datetime.datetime() 似乎接受微秒,而不是毫秒,因此您应该乘以 1000 而不是 1000000 才能将它们转换为纳秒。
  • @daghemo 你是什么意思?我在哪里繁殖?
  • 请忘记我:也许意大利的 CODIV-19 社交距离让我发疯! :(您似乎使用 datetime.isoformat() 来转换日期并将其传递给 date 命令,因此这里没有乘法(上面的示例使用了它)。请记住,您的 time_tuple 中的最后一个 0 保留微秒,而不是毫秒。仅此而已。不是真正的错误。:)
  • 您正在执行系统命令,而 OP 明确要求避免这种情况。
【解决方案3】:

我不得不稍微修改一下tMC的win32版本的回答:

def _win_set_time(time_tuple):
    import win32api
    dayOfWeek = datetime(*time_tuple).isocalendar()[2]
    t = time_tuple[:2] + (dayOfWeek,) + time_tuple[2:]
    win32api.SetSystemTime(*t)

例如。当我根据旧时间服务器(时间协议,RFC868)使用它来设置时间时,我正在这样做:

data = s.recv(4)
remote_time = (ord(data[0])<<24) + (ord(data[1])<<16) + (ord(data[2])<<8) + ord(data[3])
remote_time -= 2208988800
_win_set_time(time.gmtime(remote_time)[0:6] + (0,))

【讨论】:

  • 错过 from datetime import datetime 否则在安装 pywin32 后工作
【解决方案4】:

这对我有用

  • 自动转换为 UTC 时间
  • 将字符串转换为日期时间
  • 使用日期时间输入
  • 可读性更强
def _win_set_time(datetime_obj: datetime):  
    import win32api  
    # http://timgolden.me.uk/pywin32-docs/win32api__SetSystemTime_meth.html  
    # win32api.SetSystemTime(year, month , dayOfWeek , day , hour , minute , second , millisecond )  
    utc_datetime = datetime_obj.astimezone().astimezone(timezone.utc).replace(tzinfo=None)
    day_of_week = utc_datetime.isocalendar()[2]
    win32api.SetSystemTime(utc_datetime.year, utc_datetime.month, day_of_week, 
    utc_datetime.day, utc_datetime.hour, utc_datetime.minute, utc_datetime.second,
    int(utc_datetime.microsecond / 1000))
    
real_time_str = "2020 12 24 13 11 10 321"  
real_time = datetime.strptime(real_time_str, '%Y %m %d %H %M %S %f')  
_win_set_time(real_time)  

【讨论】:

    【解决方案5】:

    现在我认为这是最好的解决方案

    import sys,os
    def change(s):
        if s == 1:os.system('date -s "2 OCT 2006 18:00:00"')#don't forget to change it , i've used date command for linux 
        elif s == 2:
            try:
              import pywin32
            except ImportError:
              print 'pywin32 module is missing'
              sys.exit(1)
            pywin32.SetSystemTime(year, month , dayOfWeek , day , hour , minute , second , millseconds )# fill all Parameters with int numbers
        else:print 'wrong param'
    def check_os():
        if sys.platform=='linux2':change(1)
        elif  sys.platform=='win32':change(2)
        else:print 'unknown system'
    

    暂时是临时解决办法,希望对你有帮助,也看看

    http://timgolden.me.uk/pywin32-docs/win32api__SetSystemTime_meth.html

    http://timgolden.me.uk/pywin32-docs/win32api__SetLocalTime_meth.html

    【讨论】:

    • 如果系统是 linux,这当然会创建一个子进程来运行date 系统命令。 OP 不想做的事情。