| 
32 | 32 | import firebase_functions.options as _options  | 
33 | 33 | import firebase_functions.private.util as _util  | 
34 | 34 | from firebase_functions.core import _with_init  | 
35 |  | -import dateutil.parser as dateutil_parser  | 
36 | 35 | 
 
  | 
37 | 36 | # Re-export Timezone from options module so users can import it directly from scheduler_fn  | 
38 | 37 | # This provides a more convenient API: from firebase_functions.scheduler_fn import Timezone  | 
@@ -105,11 +104,24 @@ def on_schedule_wrapped(request: _Request) -> _Response:  | 
105 | 104 |                 schedule_time = _dt.datetime.utcnow()  | 
106 | 105 |             else:  | 
107 | 106 |                 try:  | 
108 |  | -                    # Robust RFC 3339 parsing  | 
109 |  | -                    schedule_time = dateutil_parser.isoparse(schedule_time_str)  | 
110 |  | -                except ValueError as e:  | 
111 |  | -                    print(f"Failed to parse RFC 3339 timestamp: {e}")  | 
112 |  | -                    schedule_time = _dt.utcnow()  | 
 | 107 | +                    # Try to parse with the stdlib which supports fractional  | 
 | 108 | +                    # seconds and offsets in Python 3.11+ via fromisoformat.  | 
 | 109 | +                    # Normalize RFC3339 'Z' to '+00:00' for fromisoformat.  | 
 | 110 | +                    iso_str = schedule_time_str  | 
 | 111 | +                    if iso_str.endswith("Z"):  | 
 | 112 | +                        iso_str = iso_str[:-1] + "+00:00"  | 
 | 113 | +                    schedule_time = _dt.datetime.fromisoformat(iso_str)  | 
 | 114 | +                except Exception:  | 
 | 115 | +                    # Fallback to strict parsing without fractional seconds  | 
 | 116 | +                    try:  | 
 | 117 | +                        schedule_time = _dt.datetime.strptime(  | 
 | 118 | +                            schedule_time_str,  | 
 | 119 | +                            "%Y-%m-%dT%H:%M:%S%z",  | 
 | 120 | +                        )  | 
 | 121 | +                    except Exception as e:  | 
 | 122 | +                        # If all parsing fails, log and use current UTC time  | 
 | 123 | +                        _logging.exception(e)  | 
 | 124 | +                        schedule_time = _dt.datetime.utcnow()  | 
113 | 125 |             event = ScheduledEvent(  | 
114 | 126 |                 job_name=request.headers.get("X-CloudScheduler-JobName"),  | 
115 | 127 |                 schedule_time=schedule_time,  | 
 | 
0 commit comments