1

I set system time and RTC to the following values.

date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null //set system time
hwclock -w //sync RTC to system time

Also, /etc/TZ (which is the same file as /etc/localtime in busybox) is saved as

LMT0:00LMT-1:00,M5.5.1/10,M8.5.1/10

where it means that DST will be in effect at 10:00 a.m. on Monday, last week in May; and will be deactivated at 10:00 a.m. on Monday, last week in August.

I deliberately set the system time and RTC to 30 seconds earlier than the end date of DST, so as to observe system behaviour.

When DST is gone, system time (also RTC maybe?) should be substracted by one hour back.

The following is the result, and it's obvious that only system time is subtracted by one hour, NOT both system time and RTC.

~ # cat /etc/TZ
LMT0:00LMT-1:00,M5.5.1/10,M8.5.1/10
~ # date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null
~ # hwclock -w
~ # 
~ # date
Mon Aug 30 09:59:36 LMT 2021
~ # hwclock
Mon Aug 30 09:59:42 2021  0.000000 seconds
~ # 
~ # 
~ # date
Mon Aug 30 09:59:49 LMT 2021
~ # hwclock
Mon Aug 30 09:59:53 2021  0.000000 seconds

~ # date
Mon Aug 30 09:00:00 LMT 2021
~ # hwclock
Mon Aug 30 10:00:03 2021  0.000000 seconds

~ # date
Mon Aug 30 09:00:05 LMT 2021
~ # hwclock
Mon Aug 30 10:00:06 2021  0.000000 seconds

However, it behaves differently on the other hand! This time I want to observe system behaviour when entering DST.

With /etc/TZ being saved as

LMT0:00LMT-1:00,M8.5.1/10,M12.5.1/10

where it means that DST will be in effect at 10:00 a.m. on Monday, last week in August; and will be deactivated at 10:00 a.m. on Monday, last week in December.

Also, I set system time and RTC to the following values.

date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null //set system time
hwclock -w //sync RTC to system time

When DST is in effect, system time (also RTC maybe?) should be added by one hour ahead.

The following is the result, and it's obvious that BOTH system time and RTC is added by one hour.

~ # cat /etc/TZ
LMT0:00LMT-1:00,M8.5.1/10,M12.5.1/10
~ # date -s 2021.08.30-09:59:30 >/dev/null 2>/dev/null
~ # hwclock -w
~ # 
~ # date
Mon Aug 30 09:59:35 LMT 2021
~ # hwclock
Mon Aug 30 09:59:37 2021  0.000000 seconds
~ # date
Mon Aug 30 09:59:48 LMT 2021
~ # hwclock
Mon Aug 30 09:59:51 2021  0.000000 seconds
~ # date
Mon Aug 30 11:00:04 LMT 2021
~ # hwclock
Mon Aug 30 11:00:06 2021  0.000000 seconds

I wonder why this contradictory behavior occurs.

10
  • Did you check whether this is a known bug in busybox?
    – Philippos
    Aug 30 at 10:43
  • I just searched keyword hwclock on busybox bugzilla and found nothing similar to this.
    – Andy Lin
    Aug 30 at 11:06
  • RTC should always be in UTC. You're using a multiuser system and those users could be from anywhere in the world.
    – Bib
    Aug 30 at 18:01
  • @Bib I didn't get it. Do you mean this is a normal behaviour?
    – Andy Lin
    Aug 31 at 2:54
  • Person A is in New York, person B is in Sydney. They both must have consistency of the RTC, and that mean UTC, If you make the hw clock the time in Paris, no one will have a clue what the true time is. It is normal to have the hw clock set to UTC.
    – Bib
    Aug 31 at 7:44
2

You're thinking that hwclock displays the exact value the hardware clock has in its registers.

It does not do that.

Proof:

# date; hwclock; TZ=UTC hwclock; grep rtc_time /proc/driver/rtc
Wed  1 Sep 18:33:18 EEST 2021
2021-09-01 18:33:18.870798+03:00
2021-09-01 15:33:18.981738+00:00
rtc_time        : 15:33:20

Note how the outputs of hwclock and TZ=UTC hwclock are different?

hwclock displays the value of the hardware clock converted to current timezone as necessary (including both the DST offset and the timezone). If you want to see the raw value, you must use cat /proc/driver/rtc: depending on whether your system uses classic PC CMOS clock driver, UEFI clock interface, or some other real-time-clock driver, there might or might not be a conversion to time_t (or time64_t) and back in the clock setting process too.

You also don't use the --utc nor --local options when getting/setting the hardware clock, so the local/UTC state of the hardware clock is determined by the third line of the /etc/adjtime file, if it exists.


In your first test, you are setting the hardware clock while DST is in effect, and so the UTC offset is -1 (UTC=local - 1 hour). If the HW clock is set to use local time, it will be set to 09:59:30 as expected.

But if the HW clock is set to use UTC, the actual value set to the clock registers will be 08:59:30. When you view the clock before the DST transition, this offset is automatically taken back out by hwclock, and so you will see 09:59:** as expected.

When the transition off DST happens, if the HW clock was set to local time, the clock register will increment to the value of 10:00:00. Since it's already local time and DST offset is now 0 anyway, hwclock will display it as 10:00:00.

But if the HW clock was set to UTC time, the value in the clock registers would now be 09:00:00. Since after the DST transition the UTC offset is now 0, hwclock would also display it as 09:00:00.

The OS clock always runs internally in UTC and converts to local time according to the timezone+DST rules, so it will display 09:00:00 (non-DST) as expected.

Since you got the hwclock result of 10:00:00 here, it appears the third line of your /etc/adjtime file must say LOCAL.


In your second test, you set the clock while DST is not in effect, and so the total UTC offset is 0. Now, the clock registers will be set to 09:59:30 regardless of whether it's set to use UTC or local time. From the previous test, we know you have it set to local time.

When the DST transition time arrives, the HW clock registers will read 10:00:00... and as the register value is formatted for display according to the current timezone, there is a problem: according to the timezone rules in effect, 10:00:00 local time does not exist today!

Because of the DST transition, there is no possible UTC timestamp value that could represent the value of 10:00:00 local time on this special day: 09:59:59 UTC is 09:59:59 local time, but 10:00:00 UTC is 11:00:00 local time. As the time value goes through glibc's timezone translation and formatting routines, the non-existent 10:00:00 gets pushed to 11:00:00.

And so, if you query the hardware clock during the first hour after the DST-to-standard-time transition, hwclock may tell you an incorrect time because the actual value in the clock registers cannot be represented as a valid local time value. This is just a display artifact: /proc/driver/rtc should still show the correct value even during this magic hour.


This was a great example of the kinds of surprise headaches that can be caused by having the hardware clock set to local time.

I'll end with a link to this very applicable 10-minute YouTube video by Tom Scott on computer timekeeping. I'm sure you'll appreciate the conclusion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.