Comments 34
1999 год программист успешно решает проблемы 2000-года, рубит деньги мешками и вот наступает 30 декабря 1999 и его посещает мысль, а если все что не дал не сработает все же рухнет! И решает себя заморозить и разморозить в январе.
Ну и замораживается….
Просыпает и первый вопрос: Проблемы с моим кодом были?
Ему в ответ: Проблем с кодом не было, но есть другая проблема?
Программист: Какая?
Ему в ответ: Сегодня 10 января 9999 года….
Linux там не используется, ибо он совсем не система реального времени. Счетчики времени там очень точные, то есть переполнение идет часто. Посчитаем. При обновлении счетчика раз в 1 мкс (размер импульса GPS), 32битный счетчик переполняется раз в 4.9 дней. Так что там все штатно.
Отгадка простая — не нужна спутнику дата. От слова «совсем» не нужна.
GPS передает время с начала недели и 10 битный номер недели (0-1023). Таким образом внутри 19.6 летнего периода все чисто. А вот дата с точностью 19.6 лет (эпоха GPS) — зашивается в приемник. Или берется из ГЛОНАСС-М. Ближайшая смена эпохи — полночь по гринвичу с 6 на 7 апреля 2019 года.
ГЛОНАСС передает время с начала суток по Москве и номер дня в четырехлетнем периоде. Ближайшая смена эпохи — в полночь по Москве с 31 декабря 2019 года на 1 января 2020 года. Собственно ни одно ГЛОНАСС уже не летает.
ГЛОНАСС-М дополнительно передает 5 бит номера четырехлетнего периода, «первый год первого четырехлетия соответствует 1996 году.» Переход через 0 будет в 2116 году.
GALILEO очень похож на GPS, но номер недели у него 12 битный, а период счета — 78 лет. Ноль отсчета 22 августа 1999 года (точка смены эпохи GPS), а смена эпохи GALILEO нас ждет в 2078 году.
Собственно со спутниками проблемы нет никакой, календарное время им не нужно, а смену эпохи, все, кроме GALILEO уже переносили.
С современными бытовыми приемниками довольно просто — они все GPS + ГЛОНАСС-М. Проблем есть с двуями типами приемников:
- GPS-приемники без ГЛОНАСС, выпущенные до августа 1999 года, то есть уже пережившую одну смену эпохи.
- ГЛОНАСС-приемники, не понимающие номер четырехлетия.
К первому типу относится авиационная аппаратура, например на А-320 стоит приемник GPS разработки примерно 1992 года. Второй тип — это разные приемники минобороны РФ.
К счастью, для расчетов координат дата не нужна. И точное время GPS — это отметка начала секунды (1PPS), а не полная дата. Так что дата на индикаторе полетит, но в целом никаких проблем не будет.
Так сказать — подготовится к использованию машин времени.
Историю тоже стоит переписать на конкретные года, а то там путаница с маркерами «наша эра», «меловой период», и так далее.
Я хоть сварщик и не самого высокого разряда, но гари чуть понюхать
успел и могу высказать своё скромное мнение на этот счёт.
Первое — это вопрос "откуда вообще проблема возникает"? Может она
надумана? Нет, не надумана и виноваты в ней в первую очередь говнокодеры:
в подавляющем большинстве объект типа time_t преобразуется в int/long
и рассматривается как количество секунд, пройденных с начала эпохи. Почему
же я, такой надменный, смею называть этих лапшаделов негативным словом?
Просто в силу того, что в документации сказано, что внутренее строение
типа time_t
не задано! [http://en.cppreference.com/w/c/chrono/time_t]
Раз не задано, то и работать с ним напрямую нельзя, только
с использованием специального API:
- time;
- localtime;
- gmtime;
- mktime;
- difftime — из-за чего, собственно, и преобразовывают к целому:
чтобы вычислить период времени, измеряемый в секундах. Да, раньше 89/90го
стандарта этой функции не было, но её возможно реализовать через
предыдущие, но это же сложнее!
Во вторую очередь — это само API является кривым. Даже если бы все
работали с объектами time_t "правильно", то решить проблему 2038го года
получилось бы костыльно:
- текущее АПИ предполагает, что объекты копируются по значению.
Это мешает сделать простое using time_t = std::uint64_t; - нет функций по созданию и удалению объектов типа time_t. Это
означает, что при попытке сохранять в time_t индекс объекта в некой
таблице, придётся либо выделить память процессу сразу под всё
возможное их количество, либо выделять по мере необходимости — вызов
mktime; и освобождать весь этот массив по завершении процесса.
В-третьих, как должно выглядеть нормальное АПИ. Оно должно выглядеть
также, как и CreateFile/CloseHandle из WinAPI:
/* да, для красоты можно и сказать, что есть некий тип, но
его кишки вам смотреть запрещено!
struct TimeType;
using time_t = TimeType *;
*/
using time_t = void *;
const auto INVALID_TIMET_VALUE = /* ... */;
time_t create_time(/* some arguments */);
/* код ошибки - на всякий случай */
int free_time(time_t time_);
int mktime(struct tm * time_, time_t outTime_);
/* sample */
time_t currentTime = create_time(/* ... */);
if (INVALID_TIMET_VALUE == currentTime)
{
fprintf(stderr, "create_time failed; errno = %d\n", errno);
return;
}
const auto result = mktime(anotherTimeRepresentation, currentTime);
if (0 != result)
{
fprintf(stderr, "mktime failed; errno = %d\n", errno);
return;
}
/* работаем с currentTime */
const auto freeResult = free_time(currentTime);
И естественно, что эти функции должны быть экспортируемыми из
разделяемой библиотеки (dll, so, dylib, etclib).
Вот только при таком подходе замена нижележащей реализации не сломала
бы текущие скомпилированные программы.
Я понимаю, что всё это для user-space, однако и для ядрёных программ
бы подошло, но тут возникают вопросы производительности. Также ещё
можно подискутировать, сильным ли ограничением в ядре является 32х
битность представления диапазона времени.
А в-четвёртых — байка! Произошло это не непосредственно со мной, а
с моим другом по работе и горело за соседним столом так, что аж я учуял.
Понадобилось ребятам в json сериализовать время — то ли промежуток,
то ли прямо метку времени, не сильно важно. Важно то, что диалог был
примерно таким:
- Предлагаем хранить время прямо в строком представлении.
- А что, зачем, почему? Давайте прям time_t запишем, там же инт
и количество секунд с бороды 1970х... - Лёша, как бы это implementation defined! 2038й год там, все дела...
- Да пофигу, я к тому времени уже на пенсии буду.
(На одной стороне передачи был C++-ный код, с другой — Java. Работало
всё лишь только потому, что повезло.)
Рукалицо в общем и занавес. Между собой мы всегда вспоминаем с улыбкой, но
друг ещё добавляет: "Вот это не наши! Хоть бы в следующем обновлении
студии/стандартной либы/етс изменили нижележащий тип и у них всё накрылось!
Чтобы до конца пенсии поминали!!1 "
Не знаю, серьёзно уж или нет, но ПО для торговли на бирже.
2038: остался всего 21 год