Set the hardware clock in Python?

后端 未结 4 1085
星月不相逢
星月不相逢 2020-12-17 23:32

How do I set the hardware clock with Python on embedded Linux systems?

相关标签:
4条回答
  • 2020-12-17 23:44

    An updated version on Ubuntu 16.04:

    import subprocess
    import shlex
    
    subprocess.call(shlex.split("timedatectl set-ntp false"))  # May be necessary
    subprocess.call(shlex.split("sudo date -s '2 OCT 2006 18:00:00'"))
    subprocess.call(shlex.split("sudo hwclock -w"))
    

    Important note: you may need to change the time/date settings to manually set (set-ntp false) or else it will immediately change it back to the current time.

    hwclock -w sets the hardware clock based on the current system time (set by date)

    It is required that date & hwclock are run as sudo as well.

    0 讨论(0)
  • 2020-12-17 23:45

    This uses ioctl to set the hardware clock as requested (but not the system clock). It avoids extra processes but is more involved. I am using pytz and dateutil to handle local/utc conversions. Feel free to use the code (3-clause BSD License). Get the clock with get_hwclock() and set it with set_hwclock()...

    from collections import namedtuple
    from datetime import datetime
    from fcntl import ioctl
    import struct
    from dateutil.tz import tzutc
    from pytz import timezone
    
    
    # From `uapi/asm-generic/ioctl.h`
    _IOC_NRBITS = 8
    _IOC_TYPEBITS = 8
    _IOC_SIZEBITS = 14
    _IOC_DIRBITS = 2
    
    _IOC_NRMASK = (1 << _IOC_NRBITS) - 1
    _IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
    _IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
    _IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1
    
    _IOC_NRSHIFT = 0
    _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
    _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
    _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
    
    _IOC_NONE = 0
    _IOC_WRITE = 1
    _IOC_READ = 2
    
    
    def _IOC(dir, type, nr, size):
        return ((dir << _IOC_DIRSHIFT) |
                (type << _IOC_TYPESHIFT) |
                (nr << _IOC_NRSHIFT) |
                (size << _IOC_SIZESHIFT))
    
    
    def _IOC_TYPECHECK(t):
        return len(t)
    
    
    def _IO(type, nr):
        return _IOC(_IOC_NONE, type, nr, 0)
    
    
    def _IOR(type, nr, size):
        return _IOC(_IOC_READ, type, nr, _IOC_TYPECHECK(size))
    
    
    def _IOW(type, nr, size):
        return _IOC(_IOC_WRITE, type, nr, _IOC_TYPECHECK(size))
    
    
    def to_utc(dtobj):
        if dtobj.tzinfo is None:
            dtobj = timezone("UTC").localize(
                dtobj.replace(tzinfo=None) - tzlocal().utcoffset(dtobj))
        return dtobj.astimezone(timezone("UTC"))
    
    
    class RtcTime(namedtuple(
        # man(4) rtc
        "RtcTime",
        "tm_sec tm_min tm_hour "
        "tm_mday tm_mon tm_year "
        "tm_wday tm_yday tm_isdst"  # Last row is unused.
    )):
    
        _fmt = 9 * "i"
    
        def __new__(cls, tm_sec=0, tm_min=0, tm_hour=0,
                    tm_mday=0, tm_mon=0, tm_year=0,
                    tm_wday=0, tm_yday=0, tm_isdst=0):
            return super(RtcTime, cls).__new__(cls, tm_sec, tm_min, tm_hour,
                                                tm_mday, tm_mon, tm_year,
                                                tm_wday, tm_yday, tm_isdst)
    
        def __str__(self):
            return self.to_datetime().isoformat()
    
        @classmethod
        def from_datetime(cls, dtobj):
            dt = to_utc(dtobj)
            return cls(tm_sec=dt.second, tm_min=dt.minute, tm_hour=dt.hour,
                       tm_mday=dt.day, tm_mon=dt.month - 1, tm_year=dt.year - 1900)
    
        def to_datetime(self):
            # From `hwclock.c`.
            return datetime(
                year=self.tm_year + 1900, month=self.tm_mon + 1, day=self.tm_mday,
                hour=self.tm_hour, minute=self.tm_min, second=self.tm_sec,
                tzinfo=tzutc())
    
        def pack(self):
            return struct.pack(self._fmt, *self)
    
        @classmethod
        def unpack(cls, buffer):
            return cls._make(struct.unpack(cls._fmt, buffer))
    
    
    # From `uapi/linux/rtc.h`
    rtc_time = RtcTime().pack()
    RTC_RD_TIME = _IOR(ord("p"), 0x09, rtc_time)   # 0x80247009
    RTC_SET_TIME = _IOW(ord("p"), 0x0a, rtc_time)  # 0x4024700a
    del rtc_time
    
    
    def get_hwclock(devrtc="/dev/rtc"):
        with open(devrtc) as rtc:
            ret = ioctl(rtc, RTC_RD_TIME, RtcTime().pack())
        return RtcTime.unpack(ret).to_datetime()
    
    
    def set_hwclock(dt, devrtc="/dev/rtc"):
        with open(devrtc) as rtc:
            ioctl(rtc, RTC_SET_TIME, RtcTime.from_datetime(dt).pack())
    
    0 讨论(0)
  • 2020-12-17 23:48

    Use Python's os.system function to call the hwclock command.

    0 讨论(0)
  • 2020-12-18 00:04

    Probably no easy way other than doing an os.system() call.

    import os
    os.system('hwclock --set %s' % date_str)
    

    or using the 'date' command

    import os
    os.system('date -s %s' % date_str)
    

    or if you are dying to do some c coding, wrapping the system calls with swig... but I think that would be more work than its worth.

    0 讨论(0)
提交回复
热议问题