<===

ProNotes

2026-02-16 10:33:48
# Простая логика времени для Украины под CircuitPython.
# Вход: UTC-дата/время (обычно из GPS)
# Выход: локальное время (часы, минуты, секунды) и флаг летнего времени.

def is_leap_year(year):
    # Год високосный?
    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)

def days_in_month(year, month):
    # Количество дней в месяце
    if month == 2:
        return 29 if is_leap_year(year) else 28
    if month in (1, 3, 5, 7, 8, 10, 12):
        return 31
    return 30

def date_to_ordinal(year, month, day):
    # Переводим дату в "номер дня" с 0001‑01‑01 (как в datetime.toordinal)
    # Чтобы можно было узнать день недели.
    # 0001‑01‑01 считаем днём 1.
    n = day
    for m in range(1, month):
        n += days_in_month(year, m)
    # Грубая формула количества дней в предыдущих годах:
    # year - 1 полных лет
    y = year - 1
    n += y * 365 + y // 4 - y // 100 + y // 400
    return n

def weekday(year, month, day):
    # День недели: 0=понедельник, ..., 6=воскресенье
    # В Python datetime.toordinal().weekday() даёт ровно это.
    ord_day = date_to_ordinal(year, month, day)
    return (ord_day - 1) % 7

def last_sunday(year, month):
    # Находим последнюю воскресенье в месяце
    d = days_in_month(year, month)
    while weekday(year, month, d) != 6:  # 6 = воскресенье
        d -= 1
    return d

def is_summer_time_ukraine(year, month, day, hour, minute, second):
    """
    Возвращает True, если в Украине действовало летнее время (UTC+3),
    и False — если зимнее (UTC+2).

    Правило:
      - до конца 2024 года включительно: стандарт Европа (последнее воскресенье марта/октября);[web:25][web:34][web:22]
      - с 2025 года и далее летнего времени НЕТ (всегда UTC+2).[web:14][web:15][web:17][web:36]
    """

    # С 2025 года Украина остаётся на постоянном UTC+2, без летнего времени.
    if year >= 2025:
        return False

    # Переходы до отмены:
    # начало DST: последняя воскресенье марта в 03:00 по UTC (подгоняем под обычные EU‑правила)
    # конец DST: последняя воскресенье октября в 04:00 по UTC (примерно так для EET/EEST).[web:25][web:34]

    # найдём даты переходов для этого года
    start_day = last_sunday(year, 3)
    end_day = last_sunday(year, 10)

    # Сравниваем "момент времени" по UTC с точками перехода.
    # Приведём всё к кортежу (month, day, hour, minute, second) для сравнения.

    current = (month, day, hour, minute, second)
    start = (3, start_day, 3, 0, 0)   # 03:00 в марте
    end = (10, end_day, 4, 0, 0)      # 04:00 в октябре

    # Летнее время действует между start (включительно) и end (исключая end).
    return current >= start and current < end

def utc_to_kyiv(utc_year, utc_month, utc_day, utc_hour, utc_minute, utc_second):
    """
    Переводит UTC в киевское время.
    Возвращает (year, month, day, hour, minute, second, is_summer).

    is_summer = True -> летнее время (UTC+3)
    is_summer = False -> зимнее время (UTC+2)
    """

    is_summer = is_summer_time_ukraine(
        utc_year, utc_month, utc_day, utc_hour, utc_minute, utc_second
    )

    offset_hours = 3 if is_summer else 2

    # Добавляем сдвиг к UTC
    total_seconds = utc_hour * 3600 + utc_minute * 60 + utc_second
    total_seconds += offset_hours * 3600

    # Нормализуем день/дату
    # Шаг 1: сдвиг по дням
    extra_days = 0
    while total_seconds >= 24 * 3600:
        total_seconds -= 24 * 3600
        extra_days += 1
    while total_seconds < 0:
        total_seconds += 24 * 3600
        extra_days -= 1

    # Шаг 2: добавляем extra_days к дате
    year = utc_year
    month = utc_month
    day = utc_day

    # вперёд
    while extra_days > 0:
        dim = days_in_month(year, month)
        if day < dim:
            day += 1
            extra_days -= 1
        else:
            day = 1
            month += 1
            if month > 12:
                month = 1
                year += 1
            extra_days -= 1

    # назад
    while extra_days < 0:
        if day > 1:
            day -= 1
            extra_days += 1
        else:
            month -= 1
            if month < 1:
                month = 12
                year -= 1
            day = days_in_month(year, month)
            extra_days += 1

    # Разбираем обратно время
    hour = total_seconds // 3600
    minute = (total_seconds % 3600) // 60
    second = total_seconds % 60

    return year, month, day, hour, minute, second, is_summer

# -------------------------------
# Пример использования с GPS‑UTC
# -------------------------------
def gps_utc_to_kyiv(date_str, time_str):
    """
    date_str: 'DDMMYY' или 'YYYYMMDD' — подстрой под свой формат
    time_str: 'HHMMSS'
    Тут пример для формата NMEA GPRMC: DDMMYY и HHMMSS.
    """

    # Разбор NMEA‑формата DDMMYY
    # ВНИМАНИЕ: подстрой под то, что у тебя реально в коде!
    day = int(date_str[0:2])
    month = int(date_str[2:4])
    year = 2000 + int(date_str[4:6])  # NMEA даёт год как 2 цифры

    hour = int(time_str[0:2])
    minute = int(time_str[2:4])
    second = int(time_str[4:6])

    return utc_to_kyiv(year, month, day, hour, minute, second)

# Если хочешь просто сейчас:
if __name__ == "__main__":
    # пример: UTC 27.10.2024 00:30:00 (ещё лето, перед переводом)
    y, m, d, hh, mm, ss, summer = utc_to_kyiv(2024, 10, 27, 0, 30, 0)
    print("Kyiv:", y, m, d, hh, mm, ss, "summer:", summer)   
← Previous Next →
Back to list