3#ifdef USE_TIME_TIMEZONE
12static ParsedTimezone global_tz_{};
26static constexpr int count_leap_years_up_to(
int year) {
return year / 4 -
year / 100 +
year / 400; }
34static inline int64_t days_to_year_start(
int year) {
43static int days_to_year(int64_t &
days) {
45 int64_t year_start = days_to_year_start(
year);
46 while (
days < year_start) {
48 year_start = days_to_year_start(
year);
50 while (
days >= year_start + days_in_year(
year)) {
51 year_start += days_in_year(
year);
59static int epoch_to_year(time_t epoch) {
63 return days_to_year(
days);
89 int h = (
day + (13 * (
month + 1)) / 5 + k + k / 4 +
j / 4 - 2 *
j) % 7;
135 int remaining = julian_day;
140 if (remaining <=
dim) {
153 int remaining = day_of_year;
158 if (remaining < days_this_month) {
162 remaining -= days_this_month;
191 int first_occurrence = 1 + days_until_first;
196 day = first_occurrence;
239 int year = internal::epoch_to_year(utc_epoch);
259 int32_t display = -posix_offset;
260 char sign = display >= 0 ?
'+' :
'-';
263 int h = display / 3600;
264 int m = (display % 3600) / 60;
265 snprintf(buf, buf_size,
"%c%02d%02d", sign,
h,
m);
278 time_t local_epoch = utc_epoch - offset;
281 out_tm->tm_isdst = in_dst ? 1 : 0;
295extern "C" struct tm *
localtime_r(
const time_t *timer,
struct tm *result) {
296 if (timer ==
nullptr || result ==
nullptr) {
306 static struct tm localtime_buf;
int day_of_week(int year, int month, int day)
Calculate day of week for any date (0 = Sunday) Uses a simplified algorithm that works for years 1970...
int days_in_month(int year, int month)
Get the number of days in a month.
constexpr int LEAP_YEARS_BEFORE_EPOCH
time_t const DSTRule & rule
constexpr int SECONDS_PER_DAY
void julian_to_month_day(int julian_day, int &month, int &day)
Convert Julian day (J format, 1-365 not counting Feb 29) to month/day.
void day_of_year_to_month_day(int day_of_year, int year, int &month, int &day)
Convert day of year (plain format, 0-365 counting Feb 29) to month/day.
bool is_leap_year(int year)
Check if a year is a leap year.
time_t const DSTRule int32_t base_offset_seconds
constexpr int DAYS_PER_YEAR
time_t calculate_dst_transition(int year, const DSTRule &rule, int32_t base_offset_seconds)
Calculate the epoch timestamp for a DST transition in a given year.
void epoch_to_tm_utc(time_t epoch, struct tm *out_tm)
Convert epoch to year/month/day/hour/min/sec (UTC)
void set_global_tz(const ParsedTimezone &tz)
Set the global timezone used by epoch_to_local_tm() when called without a timezone.
bool is_in_dst(time_t utc_epoch, const ParsedTimezone &tz)
Check if a given UTC epoch falls within DST for the parsed timezone.
const ParsedTimezone & get_global_tz()
Get the global timezone.
ESPTime __attribute__((noinline)) RealTimeClock
@ JULIAN_NO_LEAP
J format: Jn (day 1-365, Feb 29 not counted)
@ NONE
No DST rule (used to indicate no DST)
@ DAY_OF_YEAR
Plain number: n (day 0-365, Feb 29 counted in leap years)
@ MONTH_WEEK_DAY
M format: Mm.w.d (e.g., M3.2.0 = 2nd Sunday of March)
bool const ParsedTimezone & tz
bool epoch_to_local_tm(time_t utc_epoch, const ParsedTimezone &tz, struct tm *out_tm)
Convert a UTC epoch to local time using the parsed timezone.
void format_designation(int32_t posix_offset, char *buf, size_t buf_size)
Format a POSIX offset as "+HHMM"/"-HHMM" into buf (must be >= 6 bytes).
struct tm * localtime_r(const time_t *timer, struct tm *result)
struct tm * localtime(const time_t *timer)
Rule for DST transition (packed for 32-bit: 12 bytes)
uint16_t day
Day of year (for JULIAN_NO_LEAP and DAY_OF_YEAR)
DSTRuleType type
Type of rule.
uint8_t week
Week 1-5, 5 = last (for MONTH_WEEK_DAY)
int32_t time_seconds
Seconds after midnight (default 7200 = 2:00 AM)
uint8_t day_of_week
Day 0-6, 0 = Sunday (for MONTH_WEEK_DAY)
uint8_t month
Month 1-12 (for MONTH_WEEK_DAY)
Parsed POSIX timezone information (packed for 32-bit: 32 bytes)
bool has_dst() const
Check if this timezone has DST rules.
DSTRule dst_end
When DST ends.
DSTRule dst_start
When DST starts.
int32_t dst_offset_seconds
DST offset from UTC in seconds.
int32_t std_offset_seconds
Standard time offset from UTC in seconds (positive = west)