Во многих языках (Java, JS, C/C++&hellip если возникает необходимость получить текущую дату, то мы будем иметь что-то типа такой структуры:


struct rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday; /* не используется */
int tm_yday; /* не используется */
int tm_isdst; /* не используется */
};


При этом, Январю и воскресенью соответствует число 0.
Я задался вопросом: «почему так?». Вопрос этот возник потому, что я знаком со многими RTC контроллерами, в том числе и со встроенными в микроконтроллеры. Смотрите что получается:


man RTC - русский man по /dev/rtc
Отсюда узнаем, что:



Все ПК i386 и системы с ACPI содержат RTC, которые совместимы с микросхемой Motorola MC146818 из первоначальной модели PC/AT. Сегодня такие RTC обычно встраивают в чипсет материнской платы (в южный мост), и они используют заменяемую резервную батарею (типа «таблетки»).



Открываем даташит на MC146818, и видим таблицу 3 на странице 12, из которой узнаем, что диапазон месяцев находится в переделе от 1 до 12. То есть MC146818 знает, что Январю соответствует число 1.


Включаем компьютер. На каком-то этапе (на каком?) через BIOS считываются данные из RTC контроллера, складываются в вышеописанную структуру rtc_time, вычисляется epoch, устанавливает системный таймер по вычисленному epoch. И мы имеем текущее время в системе.


Пишем программу на Си(любом языке). Используем time.h. Как я понимаю, при использовании любой функции из библиотеки для получения текущей даты/времени, будет использован системный вызов time, который вернет epoch. Посмотрим на функции для работы со временем. Есть функции, которые преобразуют время в строку для вывода на экран, а есть функция gmtime, которая позволяет получить структуру tm, в которой будет все, что касается времени и даты, но только месяц и день недели будут идти с 0 . Теперь, если мы хотим работать с этим форматом, то мы должны всегда помнить об этом нюансе. Да, работать с массивом удобно: нулевой элемент не пустой, и вроде как экономия памяти. Но очень многие программисты наступают на грабли, когда работают с датой в разных ЯП из-за того, что Январь - нулевой месяц.


Причем, эти грабли кладутся так: RTC -> (JAN(01)->epoch) -> Kernel -> SysCall -> epoch -> App -> JAN(00). И, не дай бог, придется где-то работать с этим Январем (месяцем) в виде числа и отдельно в виде строки (вывод).
Кстати, если посмотреть как работает /dev/rtc ,то можно увидеть, что после чтения из RTC контроллера происходит декремент месяца. А при записи в контроллер происходит инкремент.
Основной вопрос: зачем сделаны такие мучения над временем? Для совместимости с чем? Почему бы через /dev/rtc не выдавать дату без изменений, считанную с RTC? Ведь я, как электронщик, ожидаю получить от RTC модуля именно то, что есть в даташите.


В итоге, в JS и JAVA часто приходится вертеть этими числами прибавляя и убавляя единицу. В Си/Си++ аналогично.
Я всю голову сломал, пытаясь понять зачем все это так сделано. Разъясните.









 , , ,






URL записи