[1] Boot Linux | v
Linux writes RTC = UTC | | Example: | Real local time = 15:00 | Timezone = UTC+2 | RTC stored = 13:00 (UTC) v [2] Reboot into Windows | v
Windows reads same RTC value as LOCAL TIME | | Reads RTC 13:00 | Interprets it as local time v [3] Windows shows wrong clock | | Displayed time = 13:00 | Expected time = 15:00 | Error = -2 hours v
(Not tested yet, but intuitively expected - the next steps)
[4] Windows may write RTC back as LOCAL TIME | | RTC becomes 15:00 (but stored as localtime) v [5] Reboot back into Linux | v
Linux reads RTC again as UTC | | Reads RTC 15:00 | Interprets it as UTC v [6] Linux shows wrong clock too | | 15:00 UTC = 17:00 local time (UTC+2) | Linux clock is now wrong v
Result:
Linux and Windows keep reinterpreting the same hardware clock
in different ways, so the system time differs after rebooting.
[1] Boot Linux | v
Linux writes RTC = UTC | | Example: | Real local time = 15:00 | Timezone = UTC+2 | RTC stored = 13:00 (UTC) v [2] Reboot into Windows | v
Windows reads same RTC value as LOCAL TIME | | Reads RTC 13:00 | Interprets it as local time v [3] Windows shows wrong clock | | Displayed time = 13:00 | Expected time = 15:00 | Error = -2 hours v
(Not tested yet, but intuitively expected - the next steps)
[4] Windows may write RTC back as LOCAL TIME | | RTC becomes 15:00 (but stored as localtime) v [5] Reboot back into Linux | v
Linux reads RTC again as UTC | | Reads RTC 15:00 | Interprets it as UTC v [6] Linux shows wrong clock too | | 15:00 UTC = 17:00 local time (UTC+2) | Linux clock is now wrong v
Result:
Linux and Windows keep reinterpreting the same hardware clock
in different ways, so the system time differs after rebooting.
[1] Boot Linux | v
Linux writes RTC = UTC | | Example: | Real local time = 15:00 | Timezone = UTC+2 | RTC stored = 13:00 (UTC) v [2] Reboot into Windows | v
Windows reads same RTC value as LOCAL TIME | | Reads RTC 13:00 | Interprets it as local time v [3] Windows shows wrong clock | | Displayed time = 13:00 | Expected time = 15:00 | Error = -2 hours v
(Not tested yet, but intuitively expected - the next steps)
[4] Windows may write RTC back as LOCAL TIME | | RTC becomes 15:00 (but stored as localtime) v [5] Reboot back into Linux | v
Linux reads RTC again as UTC | | Reads RTC 15:00 | Interprets it as UTC v [6] Linux shows wrong clock too | | 15:00 UTC = 17:00 local time (UTC+2) | Linux clock is now wrong v
Result:
Linux and Windows keep reinterpreting the same hardware clock
in different ways, so the system time differs after rebooting.
timedatectl set-local-rtc 1
timedatectl set-local-rtc 1
timedatectl set-local-rtc 1
Linux running | +--> system clock synced by Chrony | +--> RTC written in UTC |
Linux shutdown | +--> RTC not written at shutdown (see note) |
Boot Windows | +--> Windows reads RTC as local time | +--> Windows system clock is wrong
Linux running | +--> system clock synced by Chrony | +--> RTC written in UTC |
Linux shutdown | +--> RTC not written at shutdown (see note) |
Boot Windows | +--> Windows reads RTC as local time | +--> Windows system clock is wrong
Linux running | +--> system clock synced by Chrony | +--> RTC written in UTC |
Linux shutdown | +--> RTC not written at shutdown (see note) |
Boot Windows | +--> Windows reads RTC as local time | +--> Windows system clock is wrong
+-----------------------------------------------------------+
| System setup |
+-----------------------------------------------------------+ +------------------- machine -------------------+ | | | Dual boot: Linux <-> Windows | | | +--------------------+--------------------------+ | v +----------------------+ | Hardware clock | | (RTC) | +----------------------+ ^ | rtcsync on | (chrony config) | |
+------------------------- Linux side -------------------------+
| |
| +-------------------+ syncs time +---------+ |
| | chronyd | -----------------------> | System | |
| | (Chrony) | | Clock | |
| +-------------------+ +---------+ |
| |
| - Chrony manages Linux time |
| - rtcsync takes care of RTC through kernel 11 minutes | +--------------------------------------------------------------+ +----------------------- Windows side -------------------------+
| |
| Windows also reads the same RTC |
| but may interpret it differently than Linux |
| |
+--------------------------------------------------------------+
+-----------------------------------------------------------+
| System setup |
+-----------------------------------------------------------+ +------------------- machine -------------------+ | | | Dual boot: Linux <-> Windows | | | +--------------------+--------------------------+ | v +----------------------+ | Hardware clock | | (RTC) | +----------------------+ ^ | rtcsync on | (chrony config) | |
+------------------------- Linux side -------------------------+
| |
| +-------------------+ syncs time +---------+ |
| | chronyd | -----------------------> | System | |
| | (Chrony) | | Clock | |
| +-------------------+ +---------+ |
| |
| - Chrony manages Linux time |
| - rtcsync takes care of RTC through kernel 11 minutes | +--------------------------------------------------------------+ +----------------------- Windows side -------------------------+
| |
| Windows also reads the same RTC |
| but may interpret it differently than Linux |
| |
+--------------------------------------------------------------+
+-----------------------------------------------------------+
| System setup |
+-----------------------------------------------------------+ +------------------- machine -------------------+ | | | Dual boot: Linux <-> Windows | | | +--------------------+--------------------------+ | v +----------------------+ | Hardware clock | | (RTC) | +----------------------+ ^ | rtcsync on | (chrony config) | |
+------------------------- Linux side -------------------------+
| |
| +-------------------+ syncs time +---------+ |
| | chronyd | -----------------------> | System | |
| | (Chrony) | | Clock | |
| +-------------------+ +---------+ |
| |
| - Chrony manages Linux time |
| - rtcsync takes care of RTC through kernel 11 minutes | +--------------------------------------------------------------+ +----------------------- Windows side -------------------------+
| |
| Windows also reads the same RTC |
| but may interpret it differently than Linux |
| |
+--------------------------------------------------------------+
adjtimex --print
adjtimex --print
adjtimex --print
status & 0x0040 != 0 -> clock is UNSYNCHRONIZED
status & 0x0040 == 0 -> clock is synchronized
status & 0x0040 != 0 -> clock is UNSYNCHRONIZED
status & 0x0040 == 0 -> clock is synchronized
status & 0x0040 != 0 -> clock is UNSYNCHRONIZED
status & 0x0040 == 0 -> clock is synchronized
status = 0 -> synchronized -> RTC sync can be active
status = 1 -> synchronized -> RTC sync can be active
status = 64 -> unsynchronized -> RTC sync not active
status = 65 -> unsynchronized -> RTC sync not active
status = 0 -> synchronized -> RTC sync can be active
status = 1 -> synchronized -> RTC sync can be active
status = 64 -> unsynchronized -> RTC sync not active
status = 65 -> unsynchronized -> RTC sync not active
status = 0 -> synchronized -> RTC sync can be active
status = 1 -> synchronized -> RTC sync can be active
status = 64 -> unsynchronized -> RTC sync not active
status = 65 -> unsynchronized -> RTC sync not active
asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __user *tz)
{ if (likely(tv != NULL)) { struct timeval ktv; do_gettimeofday(&ktv); if (copy_to_user(tv, &ktv, sizeof(ktv))) return -EFAULT; } if (unlikely(tz != NULL)) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;
}
/* * Adjust the time obtained from the CMOS to be UTC time instead of * local time. * * This is ugly, but preferable to the alternatives. Otherwise we * would either need to write a program to do it in /etc/rc (and risk * confusion if the program gets run more than once; it would also be * hard to make the program warp the clock precisely n hours) or * compile in the timezone information into the kernel. Bad, bad.... * * - TYT, 1992-01-01 * * The best thing to do is to keep the CMOS clock in universal time (UTC) * as real UNIX machines always do it. This avoids all headaches about * daylight saving times and warping kernel clocks. */
static inline void warp_clock(void)
{ write_seqlock_irq(&xtime_lock); wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60; xtime.tv_sec += sys_tz.tz_minuteswest * 60; time_interpolator_reset(); write_sequnlock_irq(&xtime_lock); clock_was_set();
}
/* * In case for some reason the CMOS clock has not already been running * in UTC, but in some local time: The first time we set the timezone, * we will warp the clock so that it is ticking UTC time instead of * local time. Presumably, if someone is setting the timezone then we * are running in an environment where the programs understand about * timezones. This should be done at boot time in the /etc/rc script, * as soon as possible, so that the clock can be set right. Otherwise, * various programs will get confused when the clock gets warped. */
int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{ static int firsttime = 1; int error = 0; if (tv && !timespec_valid(tv)) return -EINVAL; error = security_settime(tv, tz); if (error) return error; if (tz) { /* SMP safe, global irq locking makes it work. */ sys_tz = *tz; if (firsttime) { firsttime = 0; if (!tv) warp_clock(); } } if (tv) { /* SMP safe, again the code in arch/foo/time.c should * globally block out interrupts when it runs. */ return do_settimeofday(tv); } return 0;
}
asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __user *tz)
{ if (likely(tv != NULL)) { struct timeval ktv; do_gettimeofday(&ktv); if (copy_to_user(tv, &ktv, sizeof(ktv))) return -EFAULT; } if (unlikely(tz != NULL)) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;
}
/* * Adjust the time obtained from the CMOS to be UTC time instead of * local time. * * This is ugly, but preferable to the alternatives. Otherwise we * would either need to write a program to do it in /etc/rc (and risk * confusion if the program gets run more than once; it would also be * hard to make the program warp the clock precisely n hours) or * compile in the timezone information into the kernel. Bad, bad.... * * - TYT, 1992-01-01 * * The best thing to do is to keep the CMOS clock in universal time (UTC) * as real UNIX machines always do it. This avoids all headaches about * daylight saving times and warping kernel clocks. */
static inline void warp_clock(void)
{ write_seqlock_irq(&xtime_lock); wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60; xtime.tv_sec += sys_tz.tz_minuteswest * 60; time_interpolator_reset(); write_sequnlock_irq(&xtime_lock); clock_was_set();
}
/* * In case for some reason the CMOS clock has not already been running * in UTC, but in some local time: The first time we set the timezone, * we will warp the clock so that it is ticking UTC time instead of * local time. Presumably, if someone is setting the timezone then we * are running in an environment where the programs understand about * timezones. This should be done at boot time in the /etc/rc script, * as soon as possible, so that the clock can be set right. Otherwise, * various programs will get confused when the clock gets warped. */
int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{ static int firsttime = 1; int error = 0; if (tv && !timespec_valid(tv)) return -EINVAL; error = security_settime(tv, tz); if (error) return error; if (tz) { /* SMP safe, global irq locking makes it work. */ sys_tz = *tz; if (firsttime) { firsttime = 0; if (!tv) warp_clock(); } } if (tv) { /* SMP safe, again the code in arch/foo/time.c should * globally block out interrupts when it runs. */ return do_settimeofday(tv); } return 0;
}
asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __user *tz)
{ if (likely(tv != NULL)) { struct timeval ktv; do_gettimeofday(&ktv); if (copy_to_user(tv, &ktv, sizeof(ktv))) return -EFAULT; } if (unlikely(tz != NULL)) { if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) return -EFAULT; } return 0;
}
/* * Adjust the time obtained from the CMOS to be UTC time instead of * local time. * * This is ugly, but preferable to the alternatives. Otherwise we * would either need to write a program to do it in /etc/rc (and risk * confusion if the program gets run more than once; it would also be * hard to make the program warp the clock precisely n hours) or * compile in the timezone information into the kernel. Bad, bad.... * * - TYT, 1992-01-01 * * The best thing to do is to keep the CMOS clock in universal time (UTC) * as real UNIX machines always do it. This avoids all headaches about * daylight saving times and warping kernel clocks. */
static inline void warp_clock(void)
{ write_seqlock_irq(&xtime_lock); wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60; xtime.tv_sec += sys_tz.tz_minuteswest * 60; time_interpolator_reset(); write_sequnlock_irq(&xtime_lock); clock_was_set();
}
/* * In case for some reason the CMOS clock has not already been running * in UTC, but in some local time: The first time we set the timezone, * we will warp the clock so that it is ticking UTC time instead of * local time. Presumably, if someone is setting the timezone then we * are running in an environment where the programs understand about * timezones. This should be done at boot time in the /etc/rc script, * as soon as possible, so that the clock can be set right. Otherwise, * various programs will get confused when the clock gets warped. */
int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
{ static int firsttime = 1; int error = 0; if (tv && !timespec_valid(tv)) return -EINVAL; error = security_settime(tv, tz); if (error) return error; if (tz) { /* SMP safe, global irq locking makes it work. */ sys_tz = *tz; if (firsttime) { firsttime = 0; if (!tv) warp_clock(); } } if (tv) { /* SMP safe, again the code in arch/foo/time.c should * globally block out interrupts when it runs. */ return do_settimeofday(tv); } return 0;
}
rtcfile /var/lib/chrony/rtc
rtcautotrim 20
#rtcsync disabled
rtcfile /var/lib/chrony/rtc
rtcautotrim 20
#rtcsync disabled
rtcfile /var/lib/chrony/rtc
rtcautotrim 20
#rtcsync disabled - No timezone parameter
- No localtime/UTC flag
- No RTC mode field
- No hardware clock conversion setting - When offline or without NTP server set, RTC will not be written by chrony. Systemd does not write the RTC at shutdown anymore (see archieve)so any manual time set on system will happen for system clock and perhaps nothing will write the system clock to RTC.