@@ -266,6 +266,25 @@ def get_data_for_time(target_dt):
266266 # 4. Weather Alert
267267 alert_msg = ""
268268 upcoming_alerts = []
269+
270+ # Precipitation code sets
271+ RAIN_CODES = {61 , 63 , 65 , 80 , 81 , 82 , 66 , 67 }
272+ SNOW_CODES = {71 , 73 , 75 , 85 , 86 , 77 }
273+ STORM_CODES = {95 , 96 , 99 }
274+ DRIZZLE_CODES = {51 , 53 , 55 }
275+ ALL_PRECIP_CODES = RAIN_CODES | SNOW_CODES | STORM_CODES | DRIZZLE_CODES
276+
277+ def get_precip_type (wcode ):
278+ if wcode in RAIN_CODES :
279+ return "雨" if Config .LANGUAGE != 'EN' else "Rain"
280+ elif wcode in SNOW_CODES :
281+ return "雪" if Config .LANGUAGE != 'EN' else "Snow"
282+ elif wcode in STORM_CODES :
283+ return "雷雨" if Config .LANGUAGE != 'EN' else "T-Storm"
284+ elif wcode in DRIZZLE_CODES :
285+ return "小雨" if Config .LANGUAGE != 'EN' else "Drizzle"
286+ return None
287+
269288 try :
270289 now_hour_idx = - 1
271290 for i , t_str in enumerate (times ):
@@ -276,52 +295,67 @@ def get_data_for_time(target_dt):
276295
277296 if now_hour_idx != - 1 :
278297 max_hours = min (now_hour_idx + 49 , len (times ))
279- for i in range (now_hour_idx + 1 , max_hours ):
280- t_dt = datetime .datetime .fromisoformat (times [i ])
281- hours_from_now = i - now_hour_idx
282- code = codes [i ]
283- weather_type = None
284-
285- # Simple alert logic
286- if code in [61 , 63 , 65 , 80 , 81 , 82 , 66 , 67 ]:
287- weather_type = "雨" if Config .LANGUAGE != 'EN' else "Rain"
288- elif code in [71 , 73 , 75 , 85 , 86 , 77 ]:
289- weather_type = "雪" if Config .LANGUAGE != 'EN' else "Snow"
290- elif code in [95 , 96 , 99 ]:
291- weather_type = "雷雨" if Config .LANGUAGE != 'EN' else "T-Storm"
292- elif code in [51 , 53 , 55 ]:
293- weather_type = "小雨" if Config .LANGUAGE != 'EN' else "Drizzle"
294-
295- if weather_type :
296- upcoming_alerts .append ((hours_from_now , weather_type , t_dt ))
298+ current_code = codes [now_hour_idx ] if now_hour_idx < len (codes ) else code
299+ is_currently_precip = current_code in ALL_PRECIP_CODES
300+ current_precip_type = get_precip_type (current_code )
297301
298- if upcoming_alerts :
299- first_alert = upcoming_alerts [0 ]
300- hours , wtype , alert_dt = first_alert
302+ if is_currently_precip and current_precip_type :
303+ # Currently precipitating -> find when it STOPS
304+ stop_hour = None
305+ for i in range (now_hour_idx + 1 , max_hours ):
306+ if codes [i ] not in ALL_PRECIP_CODES :
307+ stop_hour = i - now_hour_idx
308+ break
301309
302- label_today = "今天" if Config .LANGUAGE != 'EN' else "Today"
303- label_tmr = "明天" if Config .LANGUAGE != 'EN' else "Tmrrw"
304-
305- if hours <= 3 :
306- if Config .LANGUAGE == 'EN' :
307- alert_msg = f"{ wtype } in { hours } h"
308- else :
309- alert_msg = f"{ hours } H后有{ wtype } "
310- elif alert_dt .day == now_dt .day :
310+ if stop_hour :
311311 if Config .LANGUAGE == 'EN' :
312- alert_msg = f"{ wtype } at { alert_dt . hour } :00 "
312+ alert_msg = f"{ current_precip_type } stops in { stop_hour } H "
313313 else :
314- alert_msg = f"{ label_today } { alert_dt .hour } 点有{ wtype } "
315- elif alert_dt .day == now_dt .day + 1 :
316- if Config .LANGUAGE == 'EN' :
317- alert_msg = f"{ wtype } tom. at { alert_dt .hour } :00"
318- else :
319- alert_msg = f"{ label_tmr } { alert_dt .hour } 点有{ wtype } "
314+ alert_msg = f"{ stop_hour } H后{ current_precip_type } 停"
320315 else :
316+ # Precipitation lasts the entire forecast window
317+ remaining = max_hours - now_hour_idx - 1
321318 if Config .LANGUAGE == 'EN' :
322- alert_msg = f"{ wtype } in { hours } h"
319+ alert_msg = f"{ current_precip_type } for { remaining } H+"
320+ else :
321+ alert_msg = f"{ current_precip_type } 将持续至少{ remaining } H"
322+ else :
323+ # Not currently precipitating -> find when next precipitation STARTS
324+ for i in range (now_hour_idx + 1 , max_hours ):
325+ t_dt = datetime .datetime .fromisoformat (times [i ])
326+ hours_from_now = i - now_hour_idx
327+ weather_type = get_precip_type (codes [i ])
328+
329+ if weather_type :
330+ upcoming_alerts .append ((hours_from_now , weather_type , t_dt ))
331+
332+ if upcoming_alerts :
333+ first_alert = upcoming_alerts [0 ]
334+ hours , wtype , alert_dt = first_alert
335+
336+ label_today = "今天" if Config .LANGUAGE != 'EN' else "Today"
337+ label_tmr = "明天" if Config .LANGUAGE != 'EN' else "Tmrrw"
338+
339+ if hours <= 3 :
340+ if Config .LANGUAGE == 'EN' :
341+ alert_msg = f"{ wtype } in { hours } h"
342+ else :
343+ alert_msg = f"{ hours } H后有{ wtype } "
344+ elif alert_dt .day == now_dt .day :
345+ if Config .LANGUAGE == 'EN' :
346+ alert_msg = f"{ wtype } at { alert_dt .hour } :00"
347+ else :
348+ alert_msg = f"{ label_today } { alert_dt .hour } 点有{ wtype } "
349+ elif alert_dt .day == now_dt .day + 1 :
350+ if Config .LANGUAGE == 'EN' :
351+ alert_msg = f"{ wtype } tom. at { alert_dt .hour } :00"
352+ else :
353+ alert_msg = f"{ label_tmr } { alert_dt .hour } 点有{ wtype } "
323354 else :
324- alert_msg = f"{ hours } H后有{ wtype } "
355+ if Config .LANGUAGE == 'EN' :
356+ alert_msg = f"{ wtype } in { hours } h"
357+ else :
358+ alert_msg = f"{ hours } H后有{ wtype } "
325359 except Exception as e :
326360 print (f"Alert Logic Error: { e } " )
327361
@@ -611,42 +645,69 @@ def get_calendar_info():
611645 if hasattr (holidays , Config .HOLIDAY_COUNTRY ):
612646 country_holidays = getattr (holidays , Config .HOLIDAY_COUNTRY )(years = now .year )
613647 else :
614- # Fallback to SG
615648 country_holidays = holidays .SG (years = now .year )
616649 except :
617650 country_holidays = holidays .SG (years = now .year )
618651
619652 today_holiday = country_holidays .get (now .date ())
620-
621- next_date = now .date () + datetime .timedelta (days = 1 )
622- next_non_working = None
623-
624- for _ in range (30 ):
625- is_weekend = next_date .weekday () >= 5
626- is_holiday = country_holidays .get (next_date )
627-
628- if is_weekend or is_holiday :
629- info = is_holiday if is_holiday else ("Saturday" if next_date .weekday () == 5 else "Sunday" )
630- weekday_en = next_date .strftime ("%A" )
631-
653+ today_is_weekend = now .weekday () >= 5
654+ is_rest_today = bool (today_holiday ) or today_is_weekend
655+
656+ # Determine today's status name when it's a rest day
657+ today_status = None
658+ if is_rest_today :
659+ if today_holiday :
660+ today_status = today_holiday
661+ else :
632662 if Config .LANGUAGE == 'EN' :
633- label = info
663+ today_status = "Saturday" if now . weekday () == 5 else "Sunday"
634664 else :
635- # Basic translation for generic weekends if needed, mostly holiday names are in their lang
636- # If holidays lib returns English for SG holidays, might need translation map but out of scope?
637- # User asked "holiday origin", allowing different countries. Holidays lib usually returns local language or english.
638- # Let's assume the library return is acceptable or we display it as is.
639- if info == "Saturday" : label = "周六"
640- elif info == "Sunday" : label = "周日"
641- else : label = info # Use provided name
642-
643- next_non_working = {
644- "date" : next_date .strftime ("%m-%d" ),
645- "name" : label ,
646- "days_away" : (next_date - now .date ()).days
647- }
648- break
649- next_date += datetime .timedelta (days = 1 )
665+ today_status = "星期六" if now .weekday () == 5 else "星期日"
666+
667+ next_day = None
668+ next_date = now .date () + datetime .timedelta (days = 1 )
669+
670+ if is_rest_today :
671+ # Today is a rest day -> find next WORKDAY
672+ for _ in range (30 ):
673+ d_is_weekend = next_date .weekday () >= 5
674+ d_is_holiday = country_holidays .get (next_date )
675+ if not d_is_weekend and not d_is_holiday :
676+ # This is a workday
677+ weekday_en = next_date .strftime ("%A" )
678+ if Config .LANGUAGE == 'EN' :
679+ label = weekday_en
680+ else :
681+ label = WEEKDAYS_CN .get (weekday_en , weekday_en )
682+ next_day = {
683+ "type" : "workday" ,
684+ "date" : next_date .strftime ("%m-%d" ),
685+ "name" : today_status , # Show today's holiday/weekend name
686+ "days_away" : (next_date - now .date ()).days
687+ }
688+ break
689+ next_date += datetime .timedelta (days = 1 )
690+ else :
691+ # Today is a workday -> find next REST day
692+ for _ in range (30 ):
693+ d_is_weekend = next_date .weekday () >= 5
694+ d_is_holiday = country_holidays .get (next_date )
695+ if d_is_weekend or d_is_holiday :
696+ info = d_is_holiday if d_is_holiday else ("Saturday" if next_date .weekday () == 5 else "Sunday" )
697+ if Config .LANGUAGE == 'EN' :
698+ label = info
699+ else :
700+ if info == "Saturday" : label = "星期六"
701+ elif info == "Sunday" : label = "星期日"
702+ else : label = info
703+ next_day = {
704+ "type" : "rest" ,
705+ "date" : next_date .strftime ("%m-%d" ),
706+ "name" : label ,
707+ "days_away" : (next_date - now .date ()).days
708+ }
709+ break
710+ next_date += datetime .timedelta (days = 1 )
650711
651712 weekday_en = now .strftime ("%A" )
652713 if Config .LANGUAGE == 'EN' :
@@ -658,6 +719,6 @@ def get_calendar_info():
658719 "date_str" : now .strftime ("%Y-%m-%d" ),
659720 "weekday" : weekday_disp ,
660721 "lunar" : lunar_str ,
661- "holiday " : today_holiday ,
662- "next_non_working " : next_non_working
722+ "is_rest_today " : is_rest_today ,
723+ "next_day " : next_day
663724 }
0 commit comments