···176176 tz_data_list = sorted(processed_zones.values(), key=lambda x: (x["std_offset_s"], x["dst_offset_s"]))
177177 print(f"Generated data for {len(tz_data_list)} unique offset/DST rule combinations.")
178178179179- # --- C Code Generation ---
180180- # Build C code string (no obvious dead code here)
179179+ # --- C Code Generation: Flatten name pool and tz_list entries ---
180180+ # Build a flat pool of city names and compute offsets
181181+ names_pool = []
182182+ for zone in tz_data_list:
183183+ sorted_names = sorted(zone['names'])
184184+ zone['name_offset'] = len(names_pool)
185185+ zone['name_count'] = len(sorted_names)
186186+ names_pool.extend(sorted_names)
187187+188188+ # Begin C output
181189 c_code = "// Generated by Python script using zoneinfo\n"
182182- c_code += f"// Includes Standard & DST offsets and UTC transition timestamps for {target_year}.\n"
190190+ c_code += f"// Contains Standard & DST offsets for {target_year}.\n"
183191 c_code += "// WARNING: DST rules accurate only for the generated year.\n\n"
184184- # Include stdint.h for int64_t type used below
185192 c_code += "#include <stdint.h>\n\n"
186186- c_code += "// Holds a single city name string\n"
187187- c_code += "typedef struct {\n"
188188- c_code += " const char* name;\n"
189189- c_code += "} TzCityName;\n\n"
190190- c_code += "// Holds offset info and points to an array of names\n"
193193+194194+ # Flattened list of all city names
195195+ c_code += "static const char* tz_name_pool[] = {\n"
196196+ for name in names_pool:
197197+ c_code += f" \"{name}\",\n"
198198+ c_code += "};\n\n"
199199+200200+ # TzInfo struct with name pool indices
191201 c_code += "typedef struct {\n"
192192- c_code += " float std_offset_hours; // Offset during standard time\n"
193193- c_code += " float dst_offset_hours; // Offset during daylight time (if applicable)\n"
194194- # Using int64_t for Pebble time_t safety, check SDK if 32-bit preferred
195195- c_code += " int64_t dst_start_utc; // UTC timestamp (time_t) for DST start (0 if N/A)\n"
196196- c_code += " int64_t dst_end_utc; // UTC timestamp (time_t) for DST end (0 if N/A)\n"
197197- c_code += " const TzCityName* names; // Pointer to the array of names\n"
198198- c_code += " int name_count; // How many names are in the array\n"
202202+ c_code += " float std_offset_hours;\n"
203203+ c_code += " float dst_offset_hours;\n"
204204+ c_code += " int64_t dst_start_utc;\n"
205205+ c_code += " int64_t dst_end_utc;\n"
206206+ c_code += " int name_offset;\n"
207207+ c_code += " int name_count;\n"
199208 c_code += "} TzInfo;\n\n"
200209201201- # Generate the static arrays of names first
202202- name_array_definitions = ""
203203- unique_names_id = 0
204204- for zone_data in tz_data_list:
205205- c_array_name = f"tz_names_{unique_names_id}"
206206- zone_data["c_array_name"] = c_array_name # Store for later use
207207- unique_names_id += 1
208208- name_array_definitions += f"static const TzCityName {c_array_name}[] = {{\n"
209209- # Sort names alphabetically for consistency
210210- for name in sorted(zone_data["names"]):
211211- name_array_definitions += f" {{ \"{name}\" }},\n"
212212- name_array_definitions += "};\n\n"
213213- c_code += name_array_definitions
214214-215215- # Generate the main tz_list array
216216- c_code += "// Main list mapping offsets/DST info to their respective name arrays\n"
210210+ # Main tz_list entries
217211 c_code += "static const TzInfo tz_list[] = {\n"
218218- for zone_data in tz_data_list:
219219- # Convert offsets to hours ONLY for C code generation
220220- std_offset_h_c = zone_data['std_offset_s'] / 3600.0
221221- dst_offset_h_c = zone_data['dst_offset_s'] / 3600.0
222222- c_array_name = zone_data["c_array_name"]
223223- name_count = len(zone_data["names"])
224224- # Use 'LL' suffix for int64_t timestamp constants in C
225225- c_code += (f" {{ {std_offset_h_c:.2f}f, {dst_offset_h_c:.2f}f, "
226226- f"{zone_data['start_utc']}LL, {zone_data['end_utc']}LL, "
227227- f"{c_array_name}, {name_count} }},\n")
228228-212212+ for zone in tz_data_list:
213213+ std_h = zone['std_offset_s'] / 3600.0
214214+ dst_h = zone['dst_offset_s'] / 3600.0
215215+ start = zone['start_utc']
216216+ end = zone['end_utc']
217217+ offs = zone['name_offset']
218218+ cnt = zone['name_count']
219219+ c_code += f" {{ {std_h:.2f}f, {dst_h:.2f}f, {start}LL, {end}LL, {offs}, {cnt} }},\n"
229220 c_code += "};\n\n"
230230- c_code += f"#define TZ_LIST_COUNT {len(tz_data_list)}\n"
231231-221221+ c_code += f"#define TZ_LIST_COUNT (sizeof(tz_list)/sizeof(tz_list[0]))\n"
222222+ c_code += f"#define TZ_NAME_POOL_COUNT (sizeof(tz_name_pool)/sizeof(tz_name_pool[0]))\n"
232223 return c_code
233224234225# --- Main execution ---
+38-106
src/c/clock_closest_noon.c
···3636 * @param current_utc_t The current UTC time as time_t.
3737 */
3838static void update_selected_timezone_and_city(time_t current_utc_t) {
3939- // Seed random number generator (important for random selection)
3939+ // Seed for consistent randomness when multiple zones tie
4040 srand(current_utc_t);
4141-4242- // Find the minimum local time that is >= noon
4343- long min_valid_local_seconds = DAY_SECONDS; // Initialize higher than any possible time
4444-4545- // Structure to hold candidate timezone info
4646- typedef struct {
4747- int index; // Index in tz_list
4848- long local_secs_today; // Local time in seconds past midnight
4949- float active_offset_h; // The offset used for calculation
5050- } ZoneCandidate;
5151-5252- ZoneCandidate candidates[TZ_LIST_COUNT];
5353- int candidate_count = 0; // Count of zones with time >= noon
5454-5555- uint32_t utc_seconds_today = current_utc_t % DAY_SECONDS;
5656-5757- // --- Pass 1: Calculate local time for all zones, filter >= noon, find minimum valid time ---
5858- for (int i = 0; i < TZ_LIST_COUNT; ++i) {
4141+ uint32_t utc_secs = current_utc_t % DAY_SECONDS;
4242+ long best_delta = LONG_MAX;
4343+ int best_count = 0;
4444+ int best_candidates[TZ_LIST_COUNT];
4545+ // Find zones that have local time >= noon and minimal seconds past noon
4646+ for (int i = 0; i < (int)TZ_LIST_COUNT; ++i) {
5947 const TzInfo *tz = &tz_list[i];
6060- bool is_dst_active = false;
6161-6262- // --- Determine if DST is active ---
6363- if (tz->dst_start_utc != 0LL && tz->dst_end_utc != 0LL) {
6464- int64_t start_time = tz->dst_start_utc;
6565- int64_t end_time = tz->dst_end_utc;
6666- int64_t current_time_64 = (int64_t)current_utc_t;
6767- // Standard check for non-wrapping interval
6868- if (start_time <= end_time) {
6969- if (current_time_64 >= start_time && current_time_64 < end_time) {
7070- is_dst_active = true;
7171- }
7272- }
7373- // Check for wrapping interval (e.g., Southern Hemisphere DST)
7474- else {
7575- if (current_time_64 >= start_time || current_time_64 < end_time) {
7676- is_dst_active = true;
7777- }
7878- }
7979- }
8080-8181- float active_offset_hours = is_dst_active ? tz->dst_offset_hours : tz->std_offset_hours;
8282- long offset_seconds = (long)(active_offset_hours * 3600.0f);
8383-8484- // Calculate local time in seconds past local midnight
8585- long local_seconds_today = ((long)utc_seconds_today + offset_seconds);
8686- // Ensure positive modulo result within the day
8787- local_seconds_today %= DAY_SECONDS;
8888- if (local_seconds_today < 0) {
8989- local_seconds_today += DAY_SECONDS;
9090- }
9191-9292- // --- Check if local time is at or after noon ---
9393- if (local_seconds_today >= NOON_SECONDS) {
9494- // Store as a potential candidate
9595- if (candidate_count < TZ_LIST_COUNT) {
9696- candidates[candidate_count].index = i;
9797- candidates[candidate_count].local_secs_today = local_seconds_today;
9898- candidates[candidate_count].active_offset_h = active_offset_hours;
9999- candidate_count++; // Increment count of valid candidates
100100- }
101101- // Update the minimum valid local time found so far
102102- if (local_seconds_today < min_valid_local_seconds) {
103103- min_valid_local_seconds = local_seconds_today;
4848+ // Determine DST active
4949+ bool is_dst = false;
5050+ if (tz->dst_start_utc && tz->dst_end_utc) {
5151+ int64_t now = (int64_t)current_utc_t;
5252+ if ((tz->dst_start_utc <= tz->dst_end_utc && now >= tz->dst_start_utc && now < tz->dst_end_utc) ||
5353+ (tz->dst_start_utc > tz->dst_end_utc && (now >= tz->dst_start_utc || now < tz->dst_end_utc))) {
5454+ is_dst = true;
10455 }
10556 }
106106- }
107107-108108- // --- Pass 2: Collect all candidates matching the minimum valid local time ---
109109- int best_candidates_indices[TZ_LIST_COUNT]; // Stores indices into 'candidates' array
110110- int best_candidate_count = 0;
111111- if (candidate_count > 0) { // Only proceed if we found any zones >= noon
112112- for (int k = 0; k < candidate_count; ++k) {
113113- // Check if this candidate's time is the minimum valid time we found
114114- if (candidates[k].local_secs_today == min_valid_local_seconds) {
115115- if (best_candidate_count < TZ_LIST_COUNT) {
116116- best_candidates_indices[best_candidate_count++] = k; // Store index into 'candidates' array
117117- }
118118- }
5757+ float off_h = is_dst ? tz->dst_offset_hours : tz->std_offset_hours;
5858+ long local_secs = (long)utc_secs + (long)(off_h * 3600.0f);
5959+ local_secs %= DAY_SECONDS;
6060+ if (local_secs < 0) local_secs += DAY_SECONDS;
6161+ if (local_secs < NOON_SECONDS) continue;
6262+ long delta = local_secs - NOON_SECONDS;
6363+ if (delta < best_delta) {
6464+ best_delta = delta;
6565+ best_count = 0;
6666+ best_candidates[best_count++] = i;
6767+ } else if (delta == best_delta && best_count < (int)TZ_LIST_COUNT) {
6868+ best_candidates[best_count++] = i;
11969 }
12070 }
121121-122122-123123- // --- Select the winning timezone and city ---
124124- if (best_candidate_count > 0) {
125125- // Randomly select one of the best candidates
126126- int list_pos = (best_candidate_count == 1) ? 0 : (rand() % best_candidate_count);
127127- int winning_candidate_idx_in_candidates = best_candidates_indices[list_pos]; // Index in 'candidates' array
128128-129129- int chosen_zone_list_index = candidates[winning_candidate_idx_in_candidates].index; // Index in tz_list
130130- const TzInfo *chosen_tz = &tz_list[chosen_zone_list_index];
131131-132132- // Randomly select a city name from the winning timezone
133133- if (chosen_tz->name_count > 0) {
134134- int name_index = (chosen_tz->name_count == 1) ? 0 : (rand() % chosen_tz->name_count);
135135- // Basic bounds check (should always be true if rand() works correctly)
136136- if (name_index >= 0 && name_index < chosen_tz->name_count) {
137137- s_selected_city_name = chosen_tz->names[name_index].name;
138138- } else {
139139- s_selected_city_name = "ERR:NAME"; // Safety fallback
140140- }
141141- } else {
142142- s_selected_city_name = "ERR:NO_NM"; // Safety fallback
143143- }
144144- // Store the active offset that was used for this winning timezone
145145- s_selected_offset_hours = candidates[winning_candidate_idx_in_candidates].active_offset_h;
146146-7171+ if (best_count == 0) {
7272+ s_selected_city_name = "Wait...";
7373+ s_selected_offset_hours = 0.0f;
14774 } else {
148148- // This case handles when NO timezone has local time >= 12:00:00 PM
149149- s_selected_city_name = "Wait..."; // Indicate searching or fallback state
150150- s_selected_offset_hours = 0.0f; // Reset offset
7575+ int pick = (best_count == 1) ? 0 : (rand() % best_count);
7676+ int idx = best_candidates[pick];
7777+ const TzInfo *tz = &tz_list[idx];
7878+ bool is_dst = (current_utc_t >= tz->dst_start_utc && current_utc_t < tz->dst_end_utc);
7979+ s_selected_offset_hours = is_dst ? tz->dst_offset_hours : tz->std_offset_hours;
8080+ int cnt = tz->name_count;
8181+ int ni = (cnt == 1) ? 0 : (rand() % cnt);
8282+ s_selected_city_name = tz_name_pool[tz->name_offset + ni];
15183 }
152152- s_last_re_evaluation_time = current_utc_t; // Record when we last did this
8484+ s_last_re_evaluation_time = current_utc_t;
15385}
1548615587