mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-23 18:42:24 +00:00
80 lines
2.6 KiB
C
80 lines
2.6 KiB
C
/*
|
|
* SPDX-License-Identifier: MIT
|
|
* Display timezone offset: validation and text, shared by the CLI, both UIs
|
|
* and the prefs loaders (C and C++).
|
|
*
|
|
* NodePrefs::tz_offset holds float hours from UTC, upstream MeshCore's type and
|
|
* prefs.json value. ZephCore accepts quarter hours only and every consumer
|
|
* works in whole minutes. The offset is applied only when a clock is formatted
|
|
* for the local display; it never reaches RTCClock or a timestamp.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
/* Range in hours, as upstream's `set tz.offset`. */
|
|
#define TZ_OFFSET_MIN (-12)
|
|
#define TZ_OFFSET_MAX 14
|
|
|
|
/* Buffer size for tz_offset_format_hours() and tz_offset_format_label(). */
|
|
#define TZ_OFFSET_TEXT_LEN 12
|
|
|
|
/* Nearest quarter hour; 0 (UTC) for NaN or a value outside the range. */
|
|
static inline float tz_offset_sanitize(float hours)
|
|
{
|
|
if (hours != hours || hours < TZ_OFFSET_MIN || hours > TZ_OFFSET_MAX) {
|
|
return 0.0f;
|
|
}
|
|
float q = hours * 4.0f;
|
|
return (float)(int32_t)(q < 0.0f ? q - 0.5f : q + 0.5f) * 0.25f;
|
|
}
|
|
|
|
/* In range and a whole number of quarter hours (within 0.0001 h). */
|
|
static inline bool tz_offset_valid(float hours)
|
|
{
|
|
if (hours != hours || hours < TZ_OFFSET_MIN || hours > TZ_OFFSET_MAX) {
|
|
return false;
|
|
}
|
|
float d = hours - tz_offset_sanitize(hours);
|
|
return d > -0.0001f && d < 0.0001f;
|
|
}
|
|
|
|
/* Offset in whole minutes, from a sanitized value. */
|
|
static inline int16_t tz_offset_minutes(float hours)
|
|
{
|
|
float m = tz_offset_sanitize(hours) * 60.0f;
|
|
return (int16_t)(m < 0.0f ? m - 0.5f : m + 0.5f);
|
|
}
|
|
|
|
/* Decimal hours, exact for every quarter hour: "0.0", "2.0", "-3.5", "5.75".
|
|
* Same text as upstream's "%.1f" wherever that is exact. */
|
|
static inline void tz_offset_format_hours(int16_t minutes, char *buf, size_t n)
|
|
{
|
|
static const char *const frac[4] = { "0", "25", "5", "75" };
|
|
unsigned a = (unsigned)(minutes < 0 ? -minutes : minutes);
|
|
|
|
snprintf(buf, n, "%s%u.%s", minutes < 0 ? "-" : "", a / 60, frac[(a % 60) / 15]);
|
|
}
|
|
|
|
/* Zone label for a clock display, at most 8 characters: "UTC", "UTC+2",
|
|
* "UTC-3:30", and "UTC+1245" where the h:mm form would be longer. */
|
|
static inline void tz_offset_format_label(int16_t minutes, char *buf, size_t n)
|
|
{
|
|
unsigned a = (unsigned)(minutes < 0 ? -minutes : minutes);
|
|
char sign = minutes < 0 ? '-' : '+';
|
|
|
|
if (a == 0) {
|
|
snprintf(buf, n, "UTC");
|
|
} else if (a % 60 == 0) {
|
|
snprintf(buf, n, "UTC%c%u", sign, a / 60);
|
|
} else if (a / 60 < 10) {
|
|
snprintf(buf, n, "UTC%c%u:%02u", sign, a / 60, a % 60);
|
|
} else {
|
|
snprintf(buf, n, "UTC%c%02u%02u", sign, a / 60, a % 60);
|
|
}
|
|
}
|