From fe526cf92d12158b95461feff01f46f5123a2def Mon Sep 17 00:00:00 2001 From: Durable Workflow Date: Wed, 21 Oct 2026 06:07:34 +0000 Subject: [PATCH] List, update and backfill schedules natively as PHP does GET /api/schedules follows ScheduleController::index: status and workflow type filters, the schedule visibility query (equality predicates joined by AND on schedule fields and registered search attributes), Laravel's messages, PHP's refusal bodies and continuation tokens signed with DW_SERVER_KEY or APP_KEY, bound to the namespace, filters and a cursor that must still exist. PUT /api/schedules/{id} merges the action and records PHP's changed fields. POST /api/schedules/{id}/backfill triggers each occurrence in the range as triggerForBackfill does, with PHP's fire times and offsets. Backfill times are read as ISO-8601 exactly as PHP's date rule and DateTimeImmutable read them, checked against a 700-case oracle corpus. Other strtotime spellings are refused. Ranges over 10,000 occurrences are refused instead of running unbounded, and an update to a spec that cannot be evaluated is a 422 where PHP returns 500. Laravel sizes a non-numeric value under a numeric rule by its length; the shared rules engine now does too. The new schedule-catalog fixture compares 72 responses with a reviewed copy of published PHP's. The schedule probe replays its whole sequence in a new namespace when published PHP on SQLite records its own lock failure inside a response. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/server-parity.yml | 6 +- docs/rust-server-port.md | 63 + rust/src/runtime/execution.rs | 3 + rust/src/runtime/http.rs | 13 +- rust/src/runtime/laravel_rules.rs | 45 +- rust/src/runtime/mod.rs | 2 + rust/src/runtime/schedule_backfill.rs | 306 ++ rust/src/runtime/schedule_cron.rs | 11 +- rust/src/runtime/schedule_execution.rs | 10 +- rust/src/runtime/schedule_http.rs | 24 + rust/src/runtime/schedule_list.rs | 817 +++++ rust/src/runtime/schedule_spec.rs | 30 +- rust/src/runtime/schedule_storage.rs | 93 + rust/src/runtime/schedules.rs | 93 + rust/tests/execution/schedules.rs | 135 + .../cron/php-2.5.14-backfill-dates.jsonl | 700 ++++ .../fixtures/cron/php-2.5.14-next-fire.jsonl | 820 ++--- scripts/conformance/cron-oracle/README.md | 6 +- .../cron-oracle/backfill-dates.php | 75 + scripts/conformance/cron-oracle/next-fire.php | 3 + .../conformance/server-parity/contract.mjs | 3 + scripts/conformance/server-parity/probe.php | 7 + .../schedule-catalog-contract.mjs | 86 + .../schedule-policies-contract.mjs | 18 +- .../server-parity/schedule-policies-probe.php | 100 +- .../ServerParity/schedule-catalog.json | 88 + .../ServerParity/schedule-policies.json | 2 +- .../schedule-catalog.json | 3077 +++++++++++++++++ ...erverParityScheduleCatalogContractTest.mjs | 66 + ...rverParitySchedulePoliciesContractTest.mjs | 4 +- 30 files changed, 6221 insertions(+), 485 deletions(-) create mode 100644 rust/src/runtime/schedule_backfill.rs create mode 100644 rust/src/runtime/schedule_list.rs create mode 100644 rust/tests/fixtures/cron/php-2.5.14-backfill-dates.jsonl create mode 100644 scripts/conformance/cron-oracle/backfill-dates.php create mode 100644 scripts/conformance/server-parity/schedule-catalog-contract.mjs create mode 100644 tests/Fixtures/ServerParity/schedule-catalog.json create mode 100644 tests/Fixtures/ServerParityExpected/schedule-catalog.json create mode 100644 tests/Unit/ServerParityScheduleCatalogContractTest.mjs diff --git a/.github/workflows/server-parity.yml b/.github/workflows/server-parity.yml index e730816c1..a09b4ef62 100644 --- a/.github/workflows/server-parity.yml +++ b/.github/workflows/server-parity.yml @@ -27,7 +27,7 @@ on: - tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs - tests/Unit/ServerParityLateWorkflowCompletionContractTest.mjs - tests/Unit/ServerParitySearchAttributeContractTest.mjs - - tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs + - tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs tests/Unit/ServerParityScheduleCatalogContractTest.mjs - tests/Unit/ServerParityWorkerListingContractTest.mjs - tests/Unit/ServerParityWorkerReplacementContractTest.mjs - tests/Unit/ServerParityWaitingHistoryContractTest.mjs @@ -70,7 +70,7 @@ on: - tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs - tests/Unit/ServerParityLateWorkflowCompletionContractTest.mjs - tests/Unit/ServerParitySearchAttributeContractTest.mjs - - tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs + - tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs tests/Unit/ServerParityScheduleCatalogContractTest.mjs - tests/Unit/ServerParityWorkerListingContractTest.mjs - tests/Unit/ServerParityWorkerReplacementContractTest.mjs - tests/Unit/ServerParityWaitingHistoryContractTest.mjs @@ -1462,7 +1462,7 @@ jobs: -e COMPOSER_HOME=/tmp/composer -v "$PWD:/source" -w /source "$image" \ install --working-dir=scripts/conformance/server-parity --no-interaction --no-progress docker run --rm --user=1000:1000 --entrypoint node -v "$PWD:/source:ro" -w /source \ - "$image" --test tests/Unit/ServerParityRunnerTest.mjs tests/Unit/ServerParityCooperativeContractTest.mjs tests/Unit/ServerParityChildCancellationContractTest.mjs tests/Unit/ServerParityScheduleContractTest.mjs tests/Unit/ServerParityVisibilityContractTest.mjs tests/Unit/ServerParityAdmissionContractTest.mjs tests/Unit/ServerParityRoleTokenContractTest.mjs tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs tests/Unit/ServerParitySearchAttributeContractTest.mjs tests/Unit/ServerParityWorkerListingContractTest.mjs tests/Unit/ServerParityWorkerReplacementContractTest.mjs tests/Unit/ServerParityPatchDeploymentContractTest.mjs tests/Unit/ServerParityWaitingHistoryContractTest.mjs tests/Unit/ServerParityTaskRetryContractTest.mjs tests/Unit/ServerParityPublishedPatchContractTest.mjs tests/Unit/ServerParityPublishedPatchTransportTest.mjs tests/Unit/ServerParityRecordFileTest.mjs tests/Unit/ServerParityLateWorkflowCompletionContractTest.mjs tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs > parity-evidence/comparator-tests.txt + "$image" --test tests/Unit/ServerParityRunnerTest.mjs tests/Unit/ServerParityCooperativeContractTest.mjs tests/Unit/ServerParityChildCancellationContractTest.mjs tests/Unit/ServerParityScheduleContractTest.mjs tests/Unit/ServerParityVisibilityContractTest.mjs tests/Unit/ServerParityAdmissionContractTest.mjs tests/Unit/ServerParityRoleTokenContractTest.mjs tests/Unit/ServerParityWorkerDeregistrationContractTest.mjs tests/Unit/ServerParitySearchAttributeContractTest.mjs tests/Unit/ServerParityWorkerListingContractTest.mjs tests/Unit/ServerParityWorkerReplacementContractTest.mjs tests/Unit/ServerParityPatchDeploymentContractTest.mjs tests/Unit/ServerParityWaitingHistoryContractTest.mjs tests/Unit/ServerParityTaskRetryContractTest.mjs tests/Unit/ServerParityPublishedPatchContractTest.mjs tests/Unit/ServerParityPublishedPatchTransportTest.mjs tests/Unit/ServerParityRecordFileTest.mjs tests/Unit/ServerParityLateWorkflowCompletionContractTest.mjs tests/Unit/ServerParityStorageTestContractTest.mjs tests/Unit/ServerParitySchedulePoliciesContractTest.mjs tests/Unit/ServerParityScheduleCatalogContractTest.mjs > parity-evidence/comparator-tests.txt docker run --rm --user=1000:1000 --cpus=1 --memory=256m --memory-swap=256m \ --network=none --entrypoint node -v "$PWD:/source:ro" -w /source \ "$image" --test tests/Unit/ServerParityCodecDeadlineLoadTest.mjs > parity-evidence/codec-load-tests.txt diff --git a/docs/rust-server-port.md b/docs/rust-server-port.md index 281b527fc..ff83243ec 100644 --- a/docs/rust-server-port.md +++ b/docs/rust-server-port.md @@ -229,6 +229,69 @@ support is not evidence of multi-node safety. Newest checkpoints first. Each entry is exact to the source, tree and runs it names, including unsuccessful observations. +October 21, schedule listing, updates and backfill: + +- **Listing.** `schedule_list.rs` serves `GET /api/schedules` as PHP's + `ScheduleController::index` does: + - the `status`, `workflow_type`, `query`, `page_size` and + `next_page_token` filters, with Laravel's rules and messages and PHP's + refusal bodies, including `last_safe_cursor`; + - the visibility query from `ScheduleVisibilityQuery`, which accepts only + equality predicates joined by `AND`. It works on ScheduleId, Status, + WorkflowType, TaskQueue, Note and registered search attributes, with + PHP's literal rules. A search attribute predicate matches no schedule, + because native schedules hold no search attribute values. + - continuation tokens signed as PHP signs them, with `DW_SERVER_KEY`, + then `APP_KEY`. When neither is set, PHP generates a key for each + container; native uses its auth token instead, so tokens survive + restarts and work on every node. Each token is bound to its namespace, + filters and a cursor that must still be present. + - newest-first order, with PHP's list items. + + The SQL is assembled from fixed fragments with bound values for each + database family. +- **Updates.** `PUT /api/schedules/{id}` follows `ScheduleManager::update`: + the action is merged with the stored one, the quota is recomputed, the + next fire time is recalculated, and `ScheduleUpdated` carries PHP's + changed fields. +- **Backfill.** `POST /api/schedules/{id}/backfill` enumerates every + occurrence from the start time up to, but not including, the end time, + and triggers each one as `triggerForBackfill` does: + - no stale check; + - buffering policies start every occurrence; + - a fired occurrence is skipped; + - the run quota ends the backfill. + + Fire times carry the offset PHP formats: the schedule zone's for a cron + occurrence, UTC for an interval. The Laravel `date` rule reads ISO-8601 + dates and date-times exactly as PHP does, including hour 24, second 60, + fractions and offsets. +- **Deliberate differences.** + - Backfill times use ISO-8601 only. PHP's other `strtotime` forms, such as + `2026-04-01 +1 day` or `@1700000000`, get the `date` validation message. + - A backfill range with more than 10,000 occurrences is refused with 422 + `backfill_range_too_large`. PHP has no limit. + - An update to a specification that cannot be evaluated is a 422. PHP + leaves that `LogicException` unhandled and returns 500. +- **Corrected.** Laravel sizes a non-numeric value under a numeric rule by + its length, so `page_size=x` reports only the integer rule. The shared + rules engine now does the same. +- **Evidence.** + - `cron-oracle/backfill-dates.php` records PHP's `date` rule and instant + for 700 seeded strings. Native accepts nothing PHP refuses, reads every + accepted string to the same microsecond, and reads every ISO-8601 shape + PHP accepts, except offsets of a day or more. + - The next-fire corpus now also records PHP's offset, and native matches + all 600 cases. + - The new `schedule-catalog` fixture sends 72 requests. Published PHP and + native agreed on every normalized response locally, and a reviewed copy + is in `tests/Fixtures/ServerParityExpected`. + - A PHP-on-PostgreSQL harness matched native on 81 responses, except the + two deliberate differences above. + - Schedule tests pass on SQLite, PostgreSQL, MySQL 8.4 and MariaDB 10.11. +- **Next.** Narrowing the takeover schedule refusal (#568) to what native + still cannot run. + October 21, PHP schedule specifications and policies: - **Cron.** `schedule_cron.rs` ports `dragonmantank/cron-expression` 3.6.0 as diff --git a/rust/src/runtime/execution.rs b/rust/src/runtime/execution.rs index c0938cc0c..d7db5ec22 100644 --- a/rust/src/runtime/execution.rs +++ b/rust/src/runtime/execution.rs @@ -390,6 +390,9 @@ impl Runtime { delegate!(schedule_history(schedule: &str, after: i64, limit: i64) -> Result); delegate!(edit_schedule(schedule: &str, operation: &str, note: Option, context: Value) -> Result); delegate!(trigger_schedule(schedule: &str, overlap: Option, context: Value) -> Result); + delegate!(update_schedule(schedule: &str, changes: super::schedules::Changes, context: Value) -> Result); + delegate!(list_schedules(raw: Option<&str>, secret: &str) -> Result); + delegate!(backfill_schedule(schedule: &str, range: super::schedule_backfill::Range, context: Value) -> Result); pub(crate) async fn signal( &self, workflow_id: &str, diff --git a/rust/src/runtime/http.rs b/rust/src/runtime/http.rs index 763f8f895..e5ba1bbb1 100644 --- a/rust/src/runtime/http.rs +++ b/rust/src/runtime/http.rs @@ -55,10 +55,15 @@ pub fn router(runtime: Runtime) -> Router { delete(delete_search_attribute), ) .route("/api/workflows", get(list_workflows).post(start)) - .route("/api/schedules", post(super::schedule_http::create)) + .route( + "/api/schedules", + get(super::schedule_list::list).post(super::schedule_http::create), + ) .route( "/api/schedules/{schedule_id}", - get(super::schedule_http::describe).delete(super::schedule_http::remove), + get(super::schedule_http::describe) + .put(super::schedule_http::update) + .delete(super::schedule_http::remove), ) .route( "/api/schedules/{schedule_id}/history", @@ -76,6 +81,10 @@ pub fn router(runtime: Runtime) -> Router { "/api/schedules/{schedule_id}/trigger", post(super::schedule_http::trigger), ) + .route( + "/api/schedules/{schedule_id}/backfill", + post(super::schedule_http::backfill), + ) .route("/api/workflows/{workflow_id}", get(describe_current)) .route( "/api/workflows/{workflow_id}/observation", diff --git a/rust/src/runtime/laravel_rules.rs b/rust/src/runtime/laravel_rules.rs index f4f510aaa..cd068fef3 100644 --- a/rust/src/runtime/laravel_rules.rs +++ b/rust/src/runtime/laravel_rules.rs @@ -16,6 +16,10 @@ use serde_json::{Map, Value, json}; pub(crate) enum Rule { Required, Nullable, + /// Validate only when the attribute is present. + Sometimes, + /// `regex:/\S/`: some character that is not whitespace. + NotBlank, /// Required when the named attribute is present and not empty. RequiredWith(&'static str), String, @@ -26,6 +30,8 @@ pub(crate) enum Rule { Min(i64), Max(i64), In(&'static [&'static str]), + /// `date`, for the ISO-8601 shapes `schedule_backfill::php_date` reads. + Date, } pub(crate) type Rules = [(&'static str, &'static [Rule])]; @@ -182,15 +188,26 @@ fn message(rule: Rule, attribute: &str, rules: &[Rule], value: Option<&Value>) - "array" => format!("The {attribute} field must not have more than {limit} items."), _ => format!("The {attribute} field must not be greater than {limit} characters."), }, - Rule::Nullable => String::new(), + Rule::NotBlank => format!("The {attribute} field format is invalid."), + Rule::Date => format!("The {attribute} field must be a valid date."), + Rule::Nullable | Rule::Sometimes => String::new(), } } +/// Laravel's `getSize`: a numeric value under a numeric rule, otherwise +/// an item count or the string length. fn size(value: &Value, rules: &[Rule]) -> Option { if rules.iter().any(|rule| matches!(rule, Rule::Integer)) { - return integer(value).map(|number| number as f64); + match value { + Value::Number(number) => return number.as_f64(), + Value::String(text) if super::schedule_cron::php_is_numeric(text) => { + return text.trim().parse().ok(); + } + _ => {} + } } match value { + Value::Bool(flag) => Some(f64::from(u8::from(*flag))), Value::Array(items) => Some(items.len() as f64), Value::Object(fields) => Some(fields.len() as f64), Value::String(text) => Some(text.chars().count() as f64), @@ -203,8 +220,12 @@ fn passes(rule: Rule, data: &Value, value: Option<&Value>, rules: &[Rule]) -> bo match rule { Rule::Required => filled(value), Rule::RequiredWith(other) => !filled(lookup(data, other)) || filled(value), - Rule::Nullable => true, + Rule::Nullable | Rule::Sometimes => true, + Rule::NotBlank => value.and_then(Value::as_str).is_some_and(|text| text.chars().any(|character| !character.is_whitespace())), Rule::String => value.is_some_and(Value::is_string), + Rule::Date => value + .and_then(Value::as_str) + .is_some_and(|text| super::schedule_backfill::php_date(text).is_some()), Rule::Array => value.is_some_and(|value| value.is_array() || value.is_object()), Rule::Integer => value.and_then(integer).is_some(), Rule::Boolean => matches!( @@ -229,6 +250,14 @@ fn passes(rule: Rule, data: &Value, value: Option<&Value>, rules: &[Rule]) -> bo /// Validates `body` (already normalized) and returns Laravel's 422 failure, /// or nothing when every rule passes. pub(crate) fn validate(body: &Value, rules: &Rules) -> Result<(), RuntimeError> { + match failure(errors(body, rules)) { + Some(error) => Err(error), + None => Ok(()), + } +} + +/// Every failing attribute and its messages, in Laravel's order. +pub(crate) fn errors(body: &Value, rules: &Rules) -> Vec<(String, Vec)> { let mut checks: Vec<(String, bool, &[Rule])> = Vec::new(); let mut expanded = Vec::new(); for (pattern, list) in rules { @@ -243,11 +272,14 @@ pub(crate) fn validate(body: &Value, rules: &Rules) -> Result<(), RuntimeError> for (attribute, raw, list) in checks { let value = lookup(body, &attribute); let nullable = list.iter().any(|rule| matches!(rule, Rule::Nullable)); + if value.is_none() && list.iter().any(|rule| matches!(rule, Rule::Sometimes)) { + continue; + } let name = display(&attribute, raw); let mut messages = Vec::new(); for rule in list { let implicit = matches!(rule, Rule::Required | Rule::RequiredWith(_)); - if matches!(rule, Rule::Nullable) { + if matches!(rule, Rule::Nullable | Rule::Sometimes) { continue; } // presentOrRuleIsImplicit, then isNotNullIfMarkedAsNullable. @@ -269,10 +301,7 @@ pub(crate) fn validate(body: &Value, rules: &Rules) -> Result<(), RuntimeError> errors.push((attribute, messages)); } } - match failure(errors) { - Some(error) => Err(error), - None => Ok(()), - } + errors } /// Laravel's 422 ValidationException body: the first message, a count of the diff --git a/rust/src/runtime/mod.rs b/rust/src/runtime/mod.rs index b8203a1cf..e1850bbea 100644 --- a/rust/src/runtime/mod.rs +++ b/rust/src/runtime/mod.rs @@ -48,8 +48,10 @@ pub(crate) mod laravel_rules; pub(crate) mod schedule_cron; pub(crate) mod schedule_spec; pub(crate) mod schedule_zones; +mod schedule_backfill; mod schedule_execution; mod schedule_http; +mod schedule_list; mod schedule_storage; mod schedules; mod schema; diff --git a/rust/src/runtime/schedule_backfill.rs b/rust/src/runtime/schedule_backfill.rs new file mode 100644 index 000000000..8fd93cfa3 --- /dev/null +++ b/rust/src/runtime/schedule_backfill.rs @@ -0,0 +1,306 @@ +//! `POST /api/schedules/{id}/backfill` as published PHP's +//! `ScheduleController::backfill` and `ScheduleManager::backfill` run it. +use super::laravel_rules::{Rule, Rules, normalize, validate}; +use super::{ + Result, RuntimeError, + backend::Backend, + schedules, + store::Store, +}; +use axum::http::StatusCode; +use chrono::{DateTime, Duration, NaiveDate, Utc}; +use serde_json::{Map, Value, json}; +use sqlx::{ColumnIndex, Decode, Encode, Executor, IntoArguments, Type}; + +/// The most occurrences one backfill request starts. PHP enumerates without +/// a limit; native refuses a larger range so it can be split. +pub(crate) const MAX_OCCURRENCES: usize = 10_000; + +const RULES: &Rules = &[ + ("start_time", &[Rule::Required, Rule::Date]), + ("end_time", &[Rule::Required, Rule::Date]), + ( + "overlap_policy", + &[Rule::Nullable, Rule::String, Rule::In(schedules::OVERLAP_POLICIES)], + ), +]; + +/// The instant PHP's `new DateTimeImmutable($text)` reads, under the +/// server's UTC default, for an ISO-8601 date or date-time that Laravel's +/// `date` rule accepts: +/// +/// `YYYY-MM-DD`, optionally followed by `T`, `t` or a space and +/// `HH:MM[:SS[.fraction]]`, optionally followed by an optional space and +/// `Z`, `z` or `±HH[[:]MM]`. As in PHP, hour 24 and second 60 carry into the +/// next day or minute, a fraction keeps six digits, and the calendar date +/// must exist. PHP's other spellings (relative words, other orders, zone +/// names, timestamps) are refused. +pub(crate) fn php_date(text: &str) -> Option> { + let bytes = text.as_bytes(); + let number = |from: usize, width: usize| -> Option { + let digits = bytes.get(from..from + width)?; + digits + .iter() + .all(u8::is_ascii_digit) + .then(|| digits.iter().fold(0, |value, digit| value * 10 + i64::from(digit - b'0'))) + }; + let year = number(0, 4)?; + let (month, day) = (number(5, 2)?, number(8, 2)?); + if bytes[4] != b'-' || bytes[7] != b'-' || year == 0 { + return None; + } + let date = NaiveDate::from_ymd_opt(year as i32, month as u32, day as u32)?; + let midnight = date.and_hms_opt(0, 0, 0)?.and_utc(); + if bytes.len() == 10 { + return Some(midnight); + } + if !matches!(bytes[10], b'T' | b't' | b' ') || bytes.get(13) != Some(&b':') { + return None; + } + let (hour, minute) = (number(11, 2)?, number(14, 2)?); + if hour > 24 || minute > 59 { + return None; + } + let mut at = 16; + let mut second = 0; + let mut micros = 0; + if bytes.get(at) == Some(&b':') { + second = number(at + 1, 2)?; + if second > 60 { + return None; + } + at += 3; + if bytes.get(at) == Some(&b'.') { + let digits = bytes[at + 1..] + .iter() + .take_while(|byte| byte.is_ascii_digit()) + .count(); + if !(1..=9).contains(&digits) { + return None; + } + micros = bytes[at + 1..at + 1 + digits.min(6)] + .iter() + .fold(0, |value, digit| value * 10 + i64::from(digit - b'0')) + * 10_i64.pow(6 - digits.min(6) as u32); + at += 1 + digits; + } + } + if bytes.get(at) == Some(&b' ') && at + 1 < bytes.len() { + at += 1; + } + let offset = match bytes.get(at) { + None => 0, + Some(b'Z' | b'z') if at + 1 == bytes.len() => 0, + Some(sign @ (b'+' | b'-')) => { + let hours = number(at + 1, 2)?; + let rest = &bytes[at + 3..]; + let minutes = match rest { + [] => 0, + [b':', ..] if rest.len() == 3 => number(at + 4, 2)?, + _ if rest.len() == 2 => number(at + 3, 2)?, + _ => return None, + }; + if hours > 23 || minutes > 59 { + return None; + } + let seconds = hours * 3600 + minutes * 60; + if *sign == b'-' { -seconds } else { seconds } + } + _ => return None, + }; + let seconds = hour * 3600 + minute * 60 + second - offset; + Some(midnight + Duration::seconds(seconds) + Duration::microseconds(micros)) +} + +/// PHP's `format('Y-m-d\TH:i:sP')` of an occurrence at `offset` seconds. +fn fire_time(at: DateTime, offset: i64) -> String { + let zone = chrono::FixedOffset::east_opt(offset as i32).unwrap_or(chrono::FixedOffset::east_opt(0).expect("UTC")); + at.with_timezone(&zone).format("%Y-%m-%dT%H:%M:%S%:z").to_string() +} + +/// `enumerateOccurrences`: each fire time at or after `from` and before +/// `to`, with its PHP text. +pub(crate) fn occurrences(spec: &Value, from: DateTime, to: DateTime) -> Result, String)>> { + let mut found = Vec::new(); + let mut cursor = from - Duration::seconds(1); + loop { + let Some((next, offset)) = schedules::next_occurrence(spec, cursor)? else { + break; + }; + if next >= to { + break; + } + if found.len() == MAX_OCCURRENCES { + return Err(RuntimeError::Protocol { + status: StatusCode::UNPROCESSABLE_ENTITY, + response: json!({"message":format!( + "The backfill range has more than {MAX_OCCURRENCES} occurrences. Split it into smaller ranges."), + "reason":"backfill_range_too_large","limit":MAX_OCCURRENCES}), + }); + } + found.push((next, fire_time(next, offset))); + cursor = next; + } + Ok(found) +} + +/// The validated range and policy override of a backfill body. +pub(crate) struct Range { + pub(crate) from: DateTime, + pub(crate) to: DateTime, + pub(crate) overlap: Option, +} + +pub(crate) fn range(body: &Value) -> Result { + let body = normalize(body); + validate(&body, RULES)?; + let read = |field: &str| php_date(body[field].as_str().unwrap_or_default()).expect("validated date"); + let (from, to) = (read("start_time"), read("end_time")); + if to <= from { + return Err(RuntimeError::Protocol { + status: StatusCode::UNPROCESSABLE_ENTITY, + response: json!({"message":"end_time must be after start_time.","reason":"invalid_time_range"}), + }); + } + Ok(Range { + from, + to, + overlap: body["overlap_policy"].as_str().map(str::to_owned), + }) +} + +impl Store +where + for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>, + DB::Arguments: IntoArguments, + for<'q> &'q str: Encode<'q, DB> + Type, + for<'q> Option<&'q str>: Encode<'q, DB>, + for<'q> Option: Encode<'q, DB>, + for<'q> Option: Encode<'q, DB>, + for<'q> String: Encode<'q, DB> + Type, + for<'q> i64: Encode<'q, DB> + Type, + for<'r> i64: Decode<'r, DB>, + usize: ColumnIndex, +{ + /// `ScheduleManager::backfill` on a live schedule: each occurrence is + /// triggered on its own, as `triggerForBackfill`, until the run quota is + /// spent. + pub(crate) async fn backfill_schedule(&self, schedule: &str, range: Range, context: Value) -> Result { + let (key, spec, stored) = { + let mut tx = self.begin().await?; + let row = self.schedule_row(&mut tx, schedule, false).await?; + ( + DB::string(&row, "id")?, + DB::optional_document_row(&row, "spec")?.unwrap_or(Value::Null), + DB::string(&row, "overlap_policy")?, + ) + }; + let occurrences = occurrences(&spec, range.from, range.to)?; + let policy = range + .overlap + .or(Some(stored).filter(|policy| schedules::OVERLAP_POLICIES.contains(&policy.as_str()))) + .unwrap_or_else(|| "skip".to_owned()); + // A buffering policy starts every backfilled occurrence. + let policy = if policy.starts_with("buffer_") { "allow_all".to_owned() } else { policy }; + let mut results = Vec::new(); + for (occurrence, text) in occurrences { + let mut result = Map::new(); + result.insert("fire_time".into(), json!(text)); + match self + .trigger_detailed(&key, Some(&policy), Some(&context), Some(occurrence), "backfilled") + .await + { + Ok(super::schedule_execution::Trigger::Triggered { workflow, .. }) => { + result.insert("workflow_id".into(), json!(workflow)); + result.insert("outcome".into(), json!("started")); + } + Ok(_) => { + result.insert("outcome".into(), json!("skipped")); + } + Err(error @ RuntimeError::Database(_)) => return Err(error), + Err(error) => { + let reason = error.to_string(); + self.record_failure(&key, &reason).await?; + result.insert("outcome".into(), json!("failed")); + result.insert("reason".into(), json!(reason)); + } + } + results.push(Value::Object(result)); + let remaining = Self::query("SELECT remaining_actions FROM workflow_schedules WHERE id=$1") + .bind(&key) + .fetch_one(&self.pool) + .await?; + if DB::optional_number(&remaining, "remaining_actions")?.is_some_and(|remaining| remaining <= 0) { + break; + } + } + self.wake.notify_waiters(); + Ok(json!({"schedule_id":schedule,"outcome":"backfill_started","fires_attempted":results.len(), + "results":results})) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(serde::Deserialize)] + struct Case { + value: String, + iso: bool, + valid: bool, + at: Option, + } + + fn micros(time: DateTime) -> String { + format!("{}.{:06}", time.timestamp(), time.timestamp_subsec_micros()) + } + + /// Native reads every ISO-8601 date-time as published PHP does and + /// accepts nothing PHP's `date` rule refuses. + #[test] + fn backfill_times_read_as_published_php_reads_them() { + let corpus = include_str!("../../tests/fixtures/cron/php-2.5.14-backfill-dates.jsonl"); + let mut checked = 0; + for line in corpus.lines() { + let case: Case = serde_json::from_str(line).unwrap(); + let native = php_date(&case.value); + match (&native, case.valid) { + (Some(native), true) => assert_eq!(Some(micros(*native)), case.at, "{}", case.value), + (Some(_), false) => panic!("{} is not a date PHP accepts", case.value), + (None, true) if case.iso => { + // Offsets of a day or more are PHP spellings native refuses. + let tail = case.value.rsplit(['+', '-']).next().unwrap_or_default(); + assert!( + case.value.len() > 19 && tail.get(..2).and_then(|hours| hours.parse::().ok()) >= Some(24), + "{} is an ISO-8601 date PHP accepts", + case.value + ); + } + _ => {} + } + checked += usize::from(native.is_some()); + } + assert!(checked > 400, "only {checked} accepted dates"); + } + + #[test] + fn occurrences_carry_the_zone_offset_php_formats() { + let spec = json!({"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT12H"}],"timezone":"Europe/Budapest"}); + let from = php_date("2026-03-28T00:00:00Z").unwrap(); + let to = php_date("2026-03-30T00:00:00Z").unwrap(); + let texts: Vec = occurrences(&spec, from, to).unwrap().into_iter().map(|(_, text)| text).collect(); + assert_eq!(texts, [ + "2026-03-28T00:00:00+00:00", + "2026-03-28T03:00:00+01:00", + "2026-03-28T12:00:00+00:00", + "2026-03-29T00:00:00+00:00", + "2026-03-29T03:00:00+02:00", + "2026-03-29T12:00:00+00:00", + ]); + let every_second = json!({"intervals":[{"every":"PT1S"}]}); + let wide = occurrences(&every_second, from, from + Duration::seconds(MAX_OCCURRENCES as i64 + 1)); + assert!(matches!(wide, Err(RuntimeError::Protocol { status, .. }) if status == StatusCode::UNPROCESSABLE_ENTITY)); + assert_eq!(occurrences(&every_second, from, from + Duration::seconds(MAX_OCCURRENCES as i64)).unwrap().len(), MAX_OCCURRENCES); + } +} diff --git a/rust/src/runtime/schedule_cron.rs b/rust/src/runtime/schedule_cron.rs index 947e6b768..778c4c2eb 100644 --- a/rust/src/runtime/schedule_cron.rs +++ b/rust/src/runtime/schedule_cron.rs @@ -109,10 +109,17 @@ impl Cron { } /// The first occurrence strictly after `after`'s minute, in `zone`. + #[cfg(test)] pub(crate) fn next_after(&self, after: Timestamp, zone: &str) -> Result { + self.next_after_with_offset(after, zone).map(|(next, _)| next) + } + + /// `next_after` and the UTC offset, in seconds, PHP's result carries. + pub(crate) fn next_after_with_offset(&self, after: Timestamp, zone: &str) -> Result<(Timestamp, i64)> { let zone = PhpZone::parse(zone).ok_or(CronError::UnknownTimezone)?; let found = run_date(&self.parts, after, &zone)?; - Timestamp::from_second(found.seconds).map_err(|_| CronError::Runtime) + let next = Timestamp::from_second(found.seconds).map_err(|_| CronError::Runtime)?; + Ok((next, found.offset())) } } @@ -751,7 +758,7 @@ fn nearest_weekday(year: i16, month: i64, target: i64) -> Option { } /// PHP 8's `is_numeric` for the short ASCII strings cron fields contain. -fn php_is_numeric(value: &str) -> bool { +pub(crate) fn php_is_numeric(value: &str) -> bool { let trimmed = value.trim_start_matches(is_pcre_space).trim_end_matches(is_pcre_space); let digits = trimmed.strip_prefix(['+', '-']).unwrap_or(trimmed); let (mantissa, exponent) = match digits.find(['e', 'E']) { diff --git a/rust/src/runtime/schedule_execution.rs b/rust/src/runtime/schedule_execution.rs index 26c42dcfb..8d80be709 100644 --- a/rust/src/runtime/schedule_execution.rs +++ b/rust/src/runtime/schedule_execution.rs @@ -183,7 +183,7 @@ where } /// `ScheduleManager::triggerDetailed` on the schedule row `key`. - async fn trigger_detailed( + pub(super) async fn trigger_detailed( &self, key: &str, overlap: Option<&str>, @@ -200,7 +200,7 @@ where .await?; let store = self.in_namespace(DB::optional_string(&row, "namespace")?.as_deref().unwrap_or("default")); match store - .decide(&mut tx, &row, overlap, context, occurrence, closed) + .decide(&mut tx, &row, overlap, context, occurrence, closed, outcome == "backfilled") .await? { Decision::Done(result) => { @@ -260,9 +260,11 @@ where context: Option<&Value>, occurrence: Option>, closed: bool, + backfill: bool, ) -> Result { let skip = |reason: &str| Decision::Done(Trigger::Skipped(reason.to_owned())); - if let Some(occurrence) = occurrence { + // triggerForBackfill has no stale check: its occurrences are past. + if let Some(occurrence) = occurrence.filter(|_| !backfill) { let next = DB::optional_instant(row, "next_fire_at")?; if next.is_none_or(|next| occurrence_key(next) != occurrence_key(occurrence)) { // PHP records a stale_occurrence skip here. Native nodes all @@ -454,7 +456,7 @@ where } /// `recordFailure`, committed on its own after a failed evaluation. - async fn record_failure(&self, key: &str, reason: &str) -> Result<()> { + pub(super) async fn record_failure(&self, key: &str, reason: &str) -> Result<()> { let mut tx = self.begin().await?; let row = Self::query("SELECT * FROM workflow_schedules WHERE id=$1") .bind(key) diff --git a/rust/src/runtime/schedule_http.rs b/rust/src/runtime/schedule_http.rs index 3eed4f815..368770f80 100644 --- a/rust/src/runtime/schedule_http.rs +++ b/rust/src/runtime/schedule_http.rs @@ -234,6 +234,14 @@ async fn control( .edit_schedule(&schedule, operation, None, audit) .await .map(Json), + "backfill" => { + let range = super::schedule_backfill::range(&payload)?; + runtime.backfill_schedule(&schedule, range, audit).await.map(Json) + } + "update" => { + let changes = super::schedules::changes(&payload)?; + runtime.update_schedule(&schedule, changes, audit).await.map(Json) + } _ => { validate(&normalized, NOTE)?; let note = normalized["note"].as_str().map(str::to_owned); @@ -266,6 +274,22 @@ pub(super) async fn trigger( ) -> Result> { control(runtime, schedule, "trigger", request).await } +/// `POST /api/schedules/{id}/backfill`. +pub(super) async fn backfill( + Extension(runtime): Extension, + Path(schedule): Path, + request: Request, +) -> Result> { + control(runtime, schedule, "backfill", request).await +} +/// `PUT /api/schedules/{id}`. +pub(super) async fn update( + Extension(runtime): Extension, + Path(schedule): Path, + request: Request, +) -> Result> { + control(runtime, schedule, "update", request).await +} pub(super) async fn remove( Extension(runtime): Extension, Path(schedule): Path, diff --git a/rust/src/runtime/schedule_list.rs b/rust/src/runtime/schedule_list.rs new file mode 100644 index 000000000..ee4f90577 --- /dev/null +++ b/rust/src/runtime/schedule_list.rs @@ -0,0 +1,817 @@ +//! `GET /api/schedules` as published PHP's `ScheduleController::index`: +//! filters, the schedule visibility query, signed continuation tokens and +//! list items, with PHP's refusals. +use super::laravel_rules::{Rule, Rules, errors, normalize}; +use super::schedule_storage::iso8601; +use super::{ + Result, Runtime, RuntimeError, + backend::Backend, + schedules, + store::Store, +}; +use axum::{ + Extension, Json, + extract::RawQuery, + http::StatusCode, +}; +use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; +use chrono::{DateTime, NaiveDateTime, Utc}; +use hmac::{Hmac, KeyInit, Mac}; +use serde_json::{Map, Value, json}; +use sha2::{Digest, Sha256}; +use sqlx::{AssertSqlSafe, ColumnIndex, Decode, Encode, Executor, IntoArguments, Type}; + +const ALLOWED: [&str; 5] = ["status", "workflow_type", "query", "page_size", "next_page_token"]; + +const LIST_RULES: &Rules = &[ + ("status", &[Rule::Sometimes, Rule::Required, Rule::String, Rule::In(&["active", "paused"])]), + ( + "workflow_type", + &[Rule::Sometimes, Rule::Required, Rule::String, Rule::Min(1), Rule::Max(255), Rule::NotBlank], + ), + ("query", &[Rule::Sometimes, Rule::Required, Rule::String, Rule::Min(1), Rule::Max(2048)]), + ("page_size", &[Rule::Sometimes, Rule::Required, Rule::Integer, Rule::Min(1), Rule::Max(200)]), + ("next_page_token", &[Rule::Sometimes, Rule::Required, Rule::String, Rule::Min(1), Rule::Max(8192)]), +]; + +/// A schedule system field a visibility predicate can name. +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub(crate) enum Column { + ScheduleId, + Status, + WorkflowType, + TaskQueue, + Note, +} + +impl Column { + fn named(field: &str) -> Option<(Self, &'static str, &'static str)> { + Some(match field { + "ScheduleId" => (Self::ScheduleId, "schedule_id", "keyword"), + "Status" => (Self::Status, "status", "schedule_status"), + "WorkflowType" => (Self::WorkflowType, "action->workflow_type", "keyword"), + "TaskQueue" => (Self::TaskQueue, "action->task_queue", "keyword"), + "Note" => (Self::Note, "note", "text"), + _ => return None, + }) + } + + /// The SQL expression Laravel compiles for this column. + fn sql(self, backend: &str) -> &'static str { + match (self, backend) { + (Self::ScheduleId, _) => "schedule_id", + (Self::Status, _) => "status", + (Self::Note, _) => "note", + (Self::WorkflowType, "SQLite") => "json_extract(action,'$.\"workflow_type\"')", + (Self::TaskQueue, "SQLite") => "json_extract(action,'$.\"task_queue\"')", + (Self::WorkflowType, "PostgreSQL") => "(action->>'workflow_type')", + (Self::TaskQueue, "PostgreSQL") => "(action->>'task_queue')", + (Self::WorkflowType, _) => "JSON_UNQUOTE(JSON_EXTRACT(action,'$.\"workflow_type\"'))", + (Self::TaskQueue, _) => "JSON_UNQUOTE(JSON_EXTRACT(action,'$.\"task_queue\"'))", + } + } +} + +/// One parsed `Field = literal` predicate. +#[derive(Clone, Debug, PartialEq)] +pub(crate) struct Predicate { + field: String, + column: Option<(Column, &'static str)>, + kind: String, + literal: Value, +} + +/// `ScheduleVisibilityQueryException`. +#[derive(Debug, PartialEq)] +pub(crate) struct QueryError { + pub(crate) message: String, + pub(crate) reason: &'static str, +} + +fn query_error(message: impl Into) -> QueryError { + QueryError { + message: message.into(), + reason: "invalid_schedule_visibility_query", + } +} + +/// `ScheduleVisibilityQuery::parse` against the namespace's registered +/// search attribute types. +pub(crate) fn parse_query( + query: &str, + definitions: &[(String, String)], +) -> std::result::Result, QueryError> { + let query = query.trim_matches([' ', '\t', '\n', '\r', '\0', '\x0b']); + if query.is_empty() { + return Err(query_error("Schedule visibility query must not be empty.")); + } + let parts = split_and(query).ok_or_else(|| { + query_error("Schedule visibility query contains an unterminated string or empty predicate.") + })?; + let mut predicates = Vec::new(); + for part in parts { + let unquoted = without_quoted(&part); + let operator = ["!=", "<>", ">=", "<=", ">", "<"] + .iter() + .any(|operator| unquoted.contains(operator)); + let keyword = unquoted + .split(|character: char| !(character.is_ascii_alphanumeric() || character == '_')) + .any(|word| { + ["OR", "NOT", "IN", "LIKE", "CONTAINS", "STARTS_WITH", "ENDS_WITH"] + .iter() + .any(|keyword| word.eq_ignore_ascii_case(keyword)) + }); + if operator || keyword { + return Err(QueryError { + message: "Schedule visibility supports only equality predicates joined by AND.".into(), + reason: "unsupported_schedule_visibility_predicate", + }); + } + let Some((field, literal)) = equality(&part) else { + return Err(query_error("Schedule visibility predicates must use: Field = literal.")); + }; + let literal = parse_literal(literal.trim_matches(|c: char| c.is_ascii_whitespace()))?; + let (column, kind) = match Column::named(field) { + Some((column, name, kind)) => (Some((column, name)), kind.to_owned()), + None => match definitions.iter().find(|(name, _)| name == field) { + Some((_, kind)) => (None, kind.clone()), + None => { + return Err(QueryError { + message: format!( + "Schedule visibility field [{field}] is not searchable. Use ScheduleId, Status, \ + WorkflowType, TaskQueue, Note, or a registered search attribute." + ), + reason: "unsupported_schedule_visibility_field", + }); + } + }, + }; + let valid = match kind.as_str() { + "keyword" | "string" | "text" | "datetime" | "keyword_list" => literal.is_string(), + "int" => literal.is_i64(), + "double" => literal.is_number(), + "bool" => literal.is_boolean(), + "schedule_status" => matches!(literal.as_str(), Some("active" | "paused")), + _ => false, + }; + if !valid { + let wanted = match kind.as_str() { + "int" => "integer", + "double" => "number", + "bool" => "boolean", + "schedule_status" => "quoted active or paused", + _ => "quoted string", + }; + return Err(query_error(format!( + "Schedule visibility field [{field}] requires a {wanted} literal." + ))); + } + predicates.push(Predicate { + field: field.to_owned(), + column, + kind, + literal, + }); + } + Ok(predicates) +} + +/// `/^([A-Za-z][A-Za-z0-9_]*)\s*=\s*(.+)$/s`. +fn equality(part: &str) -> Option<(&str, &str)> { + let first = part.chars().next()?; + if !first.is_ascii_alphabetic() { + return None; + } + let end = part + .find(|character: char| !(character.is_ascii_alphanumeric() || character == '_')) + .unwrap_or(part.len()); + let (field, rest) = part.split_at(end); + let rest = rest.trim_start_matches(|c: char| c.is_ascii_whitespace() || c == '\x0b'); + let literal = rest.strip_prefix('=')?; + let literal = literal.trim_start_matches(|c: char| c.is_ascii_whitespace() || c == '\x0b'); + (!literal.is_empty()).then_some((field, literal)) +} + +/// `splitAndPredicates`: split on a blank-delimited `AND` outside quotes. +fn split_and(query: &str) -> Option> { + let bytes = query.as_bytes(); + let mut parts = Vec::new(); + let mut current = Vec::new(); + let mut quote = None; + let mut index = 0; + let space = |byte: Option<&u8>| byte.is_none_or(|byte| byte.is_ascii_whitespace() || *byte == 0x0b); + while index < bytes.len() { + let byte = bytes[index]; + if let Some(open) = quote { + current.push(byte); + if byte == b'\\' && index + 1 < bytes.len() { + index += 1; + current.push(bytes[index]); + } else if byte == open { + quote = None; + } + index += 1; + continue; + } + if byte == b'"' || byte == b'\'' { + quote = Some(byte); + current.push(byte); + index += 1; + continue; + } + if bytes.len() >= index + 3 + && bytes[index..index + 3].eq_ignore_ascii_case(b"AND") + && space(index.checked_sub(1).and_then(|before| bytes.get(before)).or(Some(&b' '))) + && space(bytes.get(index + 3)) + { + let part = String::from_utf8_lossy(¤t).trim().to_owned(); + if part.is_empty() { + return None; + } + parts.push(part); + current.clear(); + index += 3; + continue; + } + current.push(byte); + index += 1; + } + let last = String::from_utf8_lossy(¤t).trim().to_owned(); + if quote.is_some() || last.is_empty() { + return None; + } + parts.push(last); + Some(parts) +} + +/// `withoutQuotedLiterals`: quoted text replaced by spaces. +fn without_quoted(value: &str) -> String { + let bytes = value.as_bytes(); + let mut result = String::new(); + let mut quote = None; + let mut index = 0; + while index < bytes.len() { + let byte = bytes[index]; + if let Some(open) = quote { + if byte == b'\\' && index + 1 < bytes.len() { + index += 1; + } else if byte == open { + quote = None; + } + result.push(' '); + } else if byte == b'"' || byte == b'\'' { + quote = Some(byte); + result.push(' '); + } else { + result.push(byte as char); + } + index += 1; + } + result +} + +/// `parseLiteral`. +fn parse_literal(literal: &str) -> std::result::Result { + if literal.is_empty() { + return Err(query_error("Schedule visibility predicate literal must not be empty.")); + } + if literal.starts_with('"') { + return match serde_json::from_str::(literal) { + Ok(Value::String(text)) => Ok(json!(text)), + _ => Err(query_error(format!( + "Schedule visibility literal [{literal}] is not a valid JSON string." + ))), + }; + } + if literal.starts_with('\'') { + if literal.len() < 2 || !literal.ends_with('\'') { + return Err(query_error(format!( + "Schedule visibility literal [{literal}] is not a valid quoted string." + ))); + } + let inner = &literal[1..literal.len() - 1]; + return Ok(json!(inner.replace("\\'", "'").replace("\\\\", "\\"))); + } + if literal.eq_ignore_ascii_case("true") { + return Ok(json!(true)); + } + if literal.eq_ignore_ascii_case("false") { + return Ok(json!(false)); + } + let digits = literal.strip_prefix('-').unwrap_or(literal); + let canonical = |text: &str| { + !text.is_empty() + && text.bytes().all(|byte| byte.is_ascii_digit()) + && (text == "0" || !text.starts_with('0')) + }; + if canonical(digits) { + // PHP's (int) saturates at the integer range. + return Ok(json!(literal.parse::().unwrap_or(if literal.starts_with('-') { i64::MIN } else { i64::MAX }))); + } + if let Some((whole, fraction)) = digits.split_once('.') + && canonical(whole) + && !fraction.is_empty() + && fraction.bytes().all(|byte| byte.is_ascii_digit()) + && let Ok(number) = literal.parse::() + { + return Ok(json!(number)); + } + Err(query_error(format!( + "Schedule visibility literal [{literal}] must be a quoted string, number, or boolean." + ))) +} + +/// PHP's `$request->query()` from a raw query string: the last value of a +/// repeated key wins, and `key[]` / `key[name]` build arrays. +pub(crate) fn query_input(raw: Option<&str>) -> Vec<(String, Value)> { + let mut input: Vec<(String, Value)> = Vec::new(); + for (key, value) in form_urlencoded::parse(raw.unwrap_or_default().as_bytes()) { + let (name, nested) = match key.split_once('[') { + Some((name, rest)) if rest.ends_with(']') && !name.is_empty() => { + (name.to_owned(), Some(rest[..rest.len() - 1].to_owned())) + } + _ => (key.into_owned(), None), + }; + let slot = match input.iter().position(|(existing, _)| *existing == name) { + Some(position) => position, + None => { + input.push((name, Value::Null)); + input.len() - 1 + } + }; + let current = &mut input[slot].1; + match nested { + None => *current = json!(value), + Some(index) => { + if !current.is_array() && !current.is_object() { + *current = json!([]); + } + if index.is_empty() { + match current { + Value::Array(items) => items.push(json!(value)), + Value::Object(fields) => { + let next = fields.len().to_string(); + fields.insert(next, json!(value)); + } + _ => {} + } + } else { + if let Value::Array(items) = current { + *current = Value::Object( + items.drain(..).enumerate().map(|(i, v)| (i.to_string(), v)).collect(), + ); + } + current + .as_object_mut() + .expect("an object") + .insert(index, json!(value)); + } + } + } + } + input +} + +/// `scheduleListError`. +fn list_error( + status: StatusCode, + reason: &str, + field: &str, + message: &str, + errors: Option, + cursor: Option, +) -> RuntimeError { + let errors = errors.unwrap_or_else(|| json!({field:[message]})); + RuntimeError::Protocol { + status, + response: json!({"message":message,"reason":reason,"field":field,"errors":errors, + "validation_errors":errors,"last_safe_cursor":cursor}), + } +} + +/// A decoded continuation token. +struct Token { + namespace: String, + fingerprint: String, + created_at: String, + schedule_id: String, +} + +fn token_key(secret: &str) -> Vec { + Sha256::digest(format!("durable-workflow.schedule-list.page-token|{secret}")).to_vec() +} + +fn signature(encoded: &str, secret: &str) -> String { + let mut mac = Hmac::::new_from_slice(&token_key(secret)).expect("HMAC key"); + mac.update(encoded.as_bytes()); + mac.finalize() + .into_bytes() + .iter() + .map(|byte| format!("{byte:02x}")) + .collect() +} + +fn valid_cursor_time(text: &str) -> bool { + NaiveDateTime::parse_from_str(text, "%Y-%m-%d %H:%M:%S%.6f") + .is_ok_and(|time| time.format("%Y-%m-%d %H:%M:%S%.6f").to_string() == text) +} + +fn hex64(text: &str) -> bool { + text.len() == 64 && text.bytes().all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) +} + +fn encode_token(namespace: &str, fingerprint: &str, created_at: &str, schedule_id: &str, secret: &str) -> String { + let payload = json!({"version":1,"namespace":namespace,"filter_fingerprint":fingerprint, + "cursor":{"created_at":created_at,"schedule_id":schedule_id}}); + let encoded = URL_SAFE_NO_PAD.encode(payload.to_string()); + let signature = signature(&encoded, secret); + format!("{encoded}.{signature}") +} + +fn decode_token(token: &str, secret: &str) -> Option { + let (encoded, given) = token.split_once('.')?; + if encoded.is_empty() || given.contains('.') || !hex64(given) { + return None; + } + if !bool::from(subtle::ConstantTimeEq::ct_eq(signature(encoded, secret).as_bytes(), given.as_bytes())) { + return None; + } + if !encoded.bytes().all(|byte| byte.is_ascii_alphanumeric() || byte == b'_' || byte == b'-') { + return None; + } + let payload: Value = serde_json::from_slice(&URL_SAFE_NO_PAD.decode(encoded).ok()?).ok()?; + let text = |value: &Value| value.as_str().map(str::to_owned); + let cursor = &payload["cursor"]; + let token = Token { + namespace: text(&payload["namespace"]).filter(|value| !value.is_empty())?, + fingerprint: text(&payload["filter_fingerprint"]).filter(|value| hex64(value))?, + created_at: text(&cursor["created_at"]).filter(|value| valid_cursor_time(value))?, + schedule_id: text(&cursor["schedule_id"]).filter(|value| !value.is_empty())?, + }; + (payload["version"] == 1 && payload["version"].is_i64()).then_some(token) +} + +/// `publicScheduleCursor`. +fn public_cursor(token: &Token) -> Value { + let created = NaiveDateTime::parse_from_str(&token.created_at, "%Y-%m-%d %H:%M:%S%.6f") + .map(|time| time.format("%Y-%m-%dT%H:%M:%S%.6fZ").to_string()) + .unwrap_or_else(|_| token.created_at.clone()); + json!({"created_at":created,"schedule_id":token.schedule_id}) +} + +fn cursor_time(time: DateTime) -> String { + time.format("%Y-%m-%d %H:%M:%S%.6f").to_string() +} + +/// PHP's default `json_encode` of a string: `/` and every non-ASCII +/// character escaped. +fn php_string(text: &str) -> String { + let mut encoded = String::from("\""); + for character in text.chars() { + match character { + '"' => encoded.push_str("\\\""), + '\\' => encoded.push_str("\\\\"), + '/' => encoded.push_str("\\/"), + '\u{8}' => encoded.push_str("\\b"), + '\u{c}' => encoded.push_str("\\f"), + '\n' => encoded.push_str("\\n"), + '\r' => encoded.push_str("\\r"), + '\t' => encoded.push_str("\\t"), + character if character.is_ascii() && (character as u32) >= 0x20 => encoded.push(character), + character => { + let mut units = [0; 2]; + for unit in character.encode_utf16(&mut units) { + encoded.push_str(&format!("\\u{unit:04x}")); + } + } + } + } + encoded.push('"'); + encoded +} + +fn php_scalar(value: &Value) -> String { + match value { + Value::String(text) => php_string(text), + other => other.to_string(), + } +} + +/// `scheduleFilterFingerprint`: SHA-256 of PHP's JSON, in PHP's key order. +fn fingerprint(selection: &Selection) -> String { + let optional = |value: &Option| value.as_deref().map_or("null".to_owned(), php_string); + let predicates = selection + .predicates + .iter() + .map(|predicate| { + format!( + "{{\"field\":{},\"column\":{},\"type\":{},\"literal\":{}}}", + php_string(&predicate.field), + predicate.column.map_or("null".to_owned(), |(_, name)| php_string(name)), + php_string(&predicate.kind), + php_scalar(&predicate.literal) + ) + }) + .collect::>() + .join(","); + let json = format!( + "{{\"status\":{},\"workflow_type\":{},\"visibility_predicates\":[{predicates}]}}", + optional(&selection.status), + optional(&selection.workflow_type) + ); + Sha256::digest(json).iter().map(|byte| format!("{byte:02x}")).collect() +} + +/// The filtered set's selection: PHP's `scheduleListQuery`. +pub(crate) struct Selection { + status: Option, + workflow_type: Option, + predicates: Vec, +} + +enum Bind { + Text(String), + Time(DateTime), +} + +impl Store +where + for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>, + DB::Arguments: IntoArguments, + for<'q> &'q str: Encode<'q, DB> + Type, + for<'q> Option<&'q str>: Encode<'q, DB>, + for<'q> Option: Encode<'q, DB>, + for<'q> String: Encode<'q, DB> + Type, + for<'q> i64: Encode<'q, DB> + Type, + for<'r> i64: Decode<'r, DB>, + usize: ColumnIndex, +{ + pub(super) async fn search_attribute_types(&self) -> Result> { + let rows = Self::query("SELECT name,type FROM search_attribute_definitions WHERE namespace=$1 ORDER BY name") + .bind(self.namespace.as_ref()) + .fetch_all(&self.pool) + .await?; + rows.iter() + .map(|row| Ok((DB::string(row, "name")?, DB::string(row, "type")?))) + .collect() + } + + /// The selected live schedules, newest first, after an optional cursor. + async fn select_schedules( + &self, + selection: &Selection, + after: Option<(&str, &str)>, + only: Option<&str>, + limit: i64, + ) -> Result> { + // A native schedule never holds search attribute values. + if selection.predicates.iter().any(|predicate| predicate.column.is_none()) { + return Ok(Vec::new()); + } + let mysql = DB::NAME == "MySQL"; + let mut binds = Vec::new(); + let mut sql = String::from("SELECT * FROM workflow_schedules WHERE namespace="); + let mut placeholder = |sql: &mut String, bind: Bind| { + binds.push(bind); + if mysql { + sql.push('?'); + } else { + sql.push_str(&format!("${}", binds.len())); + } + }; + placeholder(&mut sql, Bind::Text(self.namespace.to_string())); + sql.push_str(" AND status!='deleted'"); + let mut equal = |sql: &mut String, column: Column, value: String| { + sql.push_str(" AND "); + sql.push_str(column.sql(DB::NAME)); + sql.push('='); + placeholder(sql, Bind::Text(value)); + }; + if let Some(status) = &selection.status { + equal(&mut sql, Column::Status, status.clone()); + } + if let Some(workflow_type) = &selection.workflow_type { + equal(&mut sql, Column::WorkflowType, workflow_type.clone()); + } + for predicate in &selection.predicates { + let (column, _) = predicate.column.expect("system field"); + equal(&mut sql, column, predicate.literal.as_str().unwrap_or_default().to_owned()); + } + if let Some(schedule_id) = only { + equal(&mut sql, Column::ScheduleId, schedule_id.to_owned()); + } + if let Some((created, schedule_id)) = after { + let time = NaiveDateTime::parse_from_str(created, "%Y-%m-%d %H:%M:%S%.6f") + .map(|time| time.and_utc()) + .unwrap_or_default(); + sql.push_str(" AND (created_at<"); + placeholder(&mut sql, Bind::Time(time)); + sql.push_str(" OR (created_at="); + placeholder(&mut sql, Bind::Time(time)); + sql.push_str(" AND schedule_id>"); + placeholder(&mut sql, Bind::Text(schedule_id.to_owned())); + sql.push_str("))"); + } + sql.push_str(&format!(" ORDER BY created_at DESC,schedule_id LIMIT {limit}")); + let mut query = sqlx::query::(AssertSqlSafe(sql)); + for bind in binds { + query = match bind { + Bind::Text(text) => query.bind(text), + Bind::Time(time) => query.bind(DB::bind_time(time)), + }; + } + Ok(query.fetch_all(&self.pool).await?) + } + + /// `ScheduleController::formatListItem`. + fn list_item(row: &DB::Row) -> Result { + let status = DB::string(row, "status")?; + let action = DB::optional_document_row(row, "action")?; + let time = |field: &str| -> Result { Ok(json!(DB::optional_instant(row, field)?.map(iso8601))) }; + let mut item = json!({"schedule_id":DB::string(row,"schedule_id")?, + "workflow_type":action.as_ref().map_or(Value::Null, |action| action["workflow_type"].clone()), + "status":status,"paused":status=="paused","next_fire":time("next_fire_at")?,"last_fire":time("last_fired_at")?, + "overlap_policy":DB::string(row,"overlap_policy")?,"note":DB::optional_string(row,"note")?, + "namespace":DB::optional_string(row,"namespace")?,"spec":DB::optional_document_row(row,"spec")?, + "action":action.map(|action| schedules::normalize_action_timeouts(&action)), + "next_fire_at":time("next_fire_at")?,"last_fired_at":time("last_fired_at")?, + "search_attributes":DB::optional_document_row(row,"search_attributes")?, + "created_at":time("created_at")?,"updated_at":time("updated_at")?, + "fires_count":DB::number(row,"fires_count")?}); + let jitter = DB::number(row, "jitter_seconds")?; + if jitter > 0 { + item["jitter_seconds"] = json!(jitter); + } + for field in ["max_runs", "remaining_actions"] { + if let Some(value) = DB::optional_number(row, field)? { + item[field] = json!(value); + } + } + Ok(item) + } + + pub(crate) async fn list_schedules(&self, raw: Option<&str>, secret: &str) -> Result { + let input: Vec<(String, Value)> = query_input(raw) + .into_iter() + .filter(|(key, _)| key != "namespace") + .collect(); + if let Some((field, _)) = input.iter().find(|(key, _)| !ALLOWED.contains(&key.as_str())) { + let message = format!("Schedule list filter [{field}] is not supported."); + return Err(list_error(StatusCode::UNPROCESSABLE_ENTITY, "unsupported_schedule_list_filter", + field, &message, None, None)); + } + let filters = normalize(&Value::Object(input.into_iter().collect::>())); + let failed = errors(&filters, LIST_RULES); + if let Some((field, messages)) = failed.first() { + let all: Map = failed + .iter() + .map(|(field, messages)| (field.clone(), json!(messages))) + .collect(); + return Err(list_error(StatusCode::UNPROCESSABLE_ENTITY, "validation_failed", field, + &messages[0], Some(Value::Object(all)), None)); + } + let token = match filters["next_page_token"].as_str() { + Some(text) => Some(decode_token(text, secret).ok_or_else(|| { + list_error(StatusCode::BAD_REQUEST, "malformed_schedule_page_token", "next_page_token", + "Schedule continuation token is malformed or has an invalid signature.", None, None) + })?), + None => None, + }; + let cursor = token.as_ref().map(public_cursor); + if let Some(token) = &token + && token.namespace != *self.namespace + { + return Err(list_error(StatusCode::FORBIDDEN, "schedule_page_token_namespace_mismatch", "next_page_token", + "Schedule continuation token belongs to a different namespace.", None, cursor)); + } + let predicates = match filters["query"].as_str() { + Some(query) => parse_query(query, &self.search_attribute_types().await?).map_err(|error| { + list_error(StatusCode::UNPROCESSABLE_ENTITY, error.reason, "query", &error.message, None, cursor.clone()) + })?, + None => Vec::new(), + }; + let selection = Selection { + status: filters["status"].as_str().map(str::to_owned), + workflow_type: filters["workflow_type"].as_str().map(str::to_owned), + predicates, + }; + let fingerprint = fingerprint(&selection); + if let Some(token) = &token { + if token.fingerprint != fingerprint { + return Err(list_error(StatusCode::CONFLICT, "schedule_page_token_filter_mismatch", "next_page_token", + "Schedule continuation token must be reused with the same status, workflow type, and visibility query.", + None, cursor)); + } + let current = self + .select_schedules(&selection, None, Some(&token.schedule_id), 1) + .await?; + let present = match current.first() { + Some(row) => DB::optional_instant(row, "created_at")?.map(cursor_time).as_deref() + == Some(token.created_at.as_str()), + None => false, + }; + if !present { + return Err(list_error(StatusCode::CONFLICT, "stale_schedule_page_token", "next_page_token", + "Schedule continuation token cursor is no longer present in the unchanged filtered set. Restart pagination without a token.", + None, cursor)); + } + } + let page_size = filters["page_size"] + .as_i64() + .or_else(|| filters["page_size"].as_str().and_then(|text| text.parse().ok())) + .unwrap_or(50); + let rows = self + .select_schedules( + &selection, + token.as_ref().map(|token| (token.created_at.as_str(), token.schedule_id.as_str())), + None, + page_size + 1, + ) + .await?; + let more = rows.len() as i64 > page_size; + let page = &rows[..rows.len().min(page_size as usize)]; + let mut schedules = Vec::new(); + for row in page { + schedules.push(Self::list_item(row)?); + } + let next = match page.last().filter(|_| more) { + Some(last) => Some(encode_token( + &self.namespace, + &fingerprint, + &DB::optional_instant(last, "created_at")?.map(cursor_time).unwrap_or_default(), + &DB::string(last, "schedule_id")?, + secret, + )), + None => None, + }; + Ok(json!({"schedules":schedules,"schedule_count":page.len(),"next_page_token":next})) + } +} + +/// PHP signs continuation tokens with its application key, which the image +/// entrypoint takes from `DW_SERVER_KEY`, then `APP_KEY`. Native reads the +/// same two. Where PHP would generate a container-local key, native uses its +/// auth token, so tokens stay valid across restarts and nodes. +fn token_secret(runtime: &Runtime) -> String { + ["DW_SERVER_KEY", "APP_KEY"] + .iter() + .find_map(|name| std::env::var(name).ok().filter(|key| !key.is_empty())) + .unwrap_or_else(|| runtime.token.to_string()) +} + +/// `GET /api/schedules`. +pub(super) async fn list( + Extension(runtime): Extension, + RawQuery(raw): RawQuery, +) -> Result> { + let secret = token_secret(&runtime); + runtime.list_schedules(raw.as_deref(), &secret).await.map(Json) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn reason(query: &str) -> (&'static str, String) { + match parse_query(query, &[("Team".into(), "keyword".into()), ("Tier".into(), "int".into())]) { + Err(error) => (error.reason, error.message), + Ok(predicates) => panic!("{query} parsed as {predicates:?}"), + } + } + + #[test] + fn visibility_queries_parse_and_refuse_as_php_does() { + let parsed = parse_query("ScheduleId = 'a\\'b' AND Status = \"paused\" and Tier = -5 AND Team = 'x AND y'", + &[("Team".into(), "keyword".into()), ("Tier".into(), "int".into())]).unwrap(); + assert_eq!(parsed.iter().map(|p| p.literal.clone()).collect::>(), + vec![json!("a'b"), json!("paused"), json!(-5), json!("x AND y")]); + assert_eq!(reason("Status != 'active'").0, "unsupported_schedule_visibility_predicate"); + assert_eq!(reason("Status = 'a' OR Note = 'b'").0, "unsupported_schedule_visibility_predicate"); + assert_eq!(reason("Status IN ('active')").0, "unsupported_schedule_visibility_predicate"); + assert_eq!(reason("Owner = 'x'").0, "unsupported_schedule_visibility_field"); + assert_eq!(reason("Status = 'deleted'").1, "Schedule visibility field [Status] requires a quoted active or paused literal."); + assert_eq!(reason("Tier = 1.5").1, "Schedule visibility field [Tier] requires a integer literal."); + assert_eq!(reason("Note = 01").1, "Schedule visibility literal [01] must be a quoted string, number, or boolean."); + assert_eq!(reason("Note = 'open").1, "Schedule visibility query contains an unterminated string or empty predicate."); + assert_eq!(reason("AND Note = 'x'").1, "Schedule visibility query contains an unterminated string or empty predicate."); + assert_eq!(reason("Note 'x'").1, "Schedule visibility predicates must use: Field = literal."); + assert_eq!(reason(" ").1, "Schedule visibility query must not be empty."); + } + + #[test] + fn continuation_tokens_round_trip_and_refuse_tampering() { + let token = encode_token("default", &"a".repeat(64), "2026-10-21 05:00:00.123456", "nightly", "secret"); + let decoded = decode_token(&token, "secret").unwrap(); + assert_eq!((decoded.created_at.as_str(), decoded.schedule_id.as_str()), ("2026-10-21 05:00:00.123456", "nightly")); + assert!(decode_token(&token, "other").is_none()); + assert!(decode_token(&token.replacen('e', "f", 1), "secret").is_none()); + assert!(decode_token("not-a-token", "secret").is_none()); + assert_eq!(public_cursor(&decoded)["created_at"], "2026-10-21T05:00:00.123456Z"); + } + + #[test] + fn query_strings_read_as_php_reads_them() { + assert_eq!(query_input(Some("status=a&status=b&x[]=1&x[]=2&y[k]=v")), vec![ + ("status".into(), json!("b")), ("x".into(), json!(["1", "2"])), ("y".into(), json!({"k":"v"}))]); + } +} diff --git a/rust/src/runtime/schedule_spec.rs b/rust/src/runtime/schedule_spec.rs index b43efbdfa..b61fc61b0 100644 --- a/rust/src/runtime/schedule_spec.rs +++ b/rust/src/runtime/schedule_spec.rs @@ -18,13 +18,19 @@ fn members(value: &Value) -> Vec<&Value> { /// The next fire time without jitter, `None` when no rule yields one, or the /// exception PHP throws evaluating a cron expression. pub(crate) fn next_fire(spec: &Value, after: Timestamp) -> Result, CronError> { + Ok(next_occurrence(spec, after)?.map(|(next, _)| next)) +} + +/// `next_fire` and the UTC offset of PHP's result: the schedule zone's for +/// a cron occurrence, zero for an interval. The first rule wins a tie. +pub(crate) fn next_occurrence(spec: &Value, after: Timestamp) -> Result, CronError> { let zone = spec .get("timezone") .and_then(Value::as_str) .unwrap_or("UTC"); - let mut earliest: Option = None; - let mut consider = |next: Timestamp| { - if earliest.is_none_or(|current| next < current) { + let mut earliest: Option<(Timestamp, i64)> = None; + let mut consider = |next: (Timestamp, i64)| { + if earliest.is_none_or(|current| next.0 < current.0) { earliest = Some(next); } }; @@ -32,11 +38,11 @@ pub(crate) fn next_fire(spec: &Value, after: Timestamp) -> Result Err(error.as_str().unwrap()), - None => Ok(case["next"].as_str().map(str::to_owned)), + None => Ok(case["next"] + .as_str() + .map(|next| format!("{next} {}", case["offset"].as_str().unwrap()))), }; if actual != expected { mismatches.push(format!("{line} -> {actual:?}")); diff --git a/rust/src/runtime/schedule_storage.rs b/rust/src/runtime/schedule_storage.rs index db0561ba5..7b625102c 100644 --- a/rust/src/runtime/schedule_storage.rs +++ b/rust/src/runtime/schedule_storage.rs @@ -110,6 +110,99 @@ where Ok(json!({"schedule_id":schedule_id,"outcome":"created"})) } + /// `ScheduleManager::update` on a live schedule. + pub(super) async fn update_schedule( + &self, + schedule_id: &str, + changes: schedules::Changes, + context: Value, + ) -> Result { + let mut tx = self.begin().await?; + let row = self.schedule_row(&mut tx, schedule_id, false).await?; + let key = DB::string(&row, "id")?; + let mut spec = DB::optional_document_row(&row, "spec")?.unwrap_or_else(|| json!({})); + if let Some(changed) = changes.spec { + // PHP leaves this LogicException unhandled (500). + if let Some(problem) = schedules::spec_problem(&changed) { + return Err(schedules::invalid_spec(problem, schedule_id)); + } + spec = changed; + } + let mut action = DB::optional_document_row(&row, "action")?.unwrap_or_else(|| json!({})); + if let Some(changed) = changes.action { + // array_merge: the given fields replace the stored ones. + if let (Some(stored), Some(given)) = (action.as_object_mut(), changed.as_object()) { + for (field, value) in given { + stored.insert(field.clone(), value.clone()); + } + } else { + action = changed; + } + action = schedules::normalize_action_timeouts(&action); + } + let mut changed_fields = vec!["spec", "action"]; + let mut policy = DB::string(&row, "overlap_policy")?; + if let Some(changed) = changes.overlap_policy { + changed_fields.push("overlap_policy"); + policy = changed; + } + let mut jitter = DB::number(&row, "jitter_seconds")?; + if let Some(changed) = changes.jitter_seconds { + changed_fields.push("jitter_seconds"); + jitter = changed; + } + let mut note = DB::optional_string(&row, "note")?; + if let Some(changed) = changes.note { + changed_fields.push("note"); + note = Some(changed); + } + let mut memo = DB::optional_document_row(&row, "memo")?; + if let Some(changed) = changes.memo { + changed_fields.push("memo"); + memo = changed; + } + if changes.clears_search_attributes { + changed_fields.push("search_attributes"); + } + let mut max_runs = DB::optional_number(&row, "max_runs")?; + let mut remaining = DB::optional_number(&row, "remaining_actions")?; + if let Some(changed) = changes.max_runs { + changed_fields.extend(["max_runs", "remaining_actions"]); + let fires = DB::number(&row, "fires_count")?; + remaining = Some(if remaining.is_none() || changed > fires { + changed - fires + } else { + remaining.unwrap_or_default() + }); + max_runs = Some(changed); + } + let changed_at = now(); + let next = schedules::next_fire(&spec, jitter, changed_at)?; + Self::query("UPDATE workflow_schedules SET spec=$1,action=$2,overlap_policy=$3,jitter_seconds=$4,note=$5,memo=$6,max_runs=$7,remaining_actions=$8,updated_at=$9 WHERE id=$10") + .bind(DB::document(&spec)).bind(DB::document(&action)).bind(policy.as_str()).bind(jitter) + .bind(note.as_deref()).bind(memo.as_ref().map(DB::document)).bind(max_runs).bind(remaining) + .bind(DB::bind_time(changed_at)).bind(&key).execute(&mut *tx).await?; + match next { + Some(next) => Self::query("UPDATE workflow_schedules SET next_fire_at=$1 WHERE id=$2") + .bind(DB::bind_time(next)).bind(&key).execute(&mut *tx).await?, + None => Self::query("UPDATE workflow_schedules SET next_fire_at=NULL WHERE id=$1") + .bind(&key).execute(&mut *tx).await?, + }; + Self::append_schedule( + &mut tx, + &key, + "ScheduleUpdated", + json!({"changed_fields":changed_fields,"spec":spec,"action":action, + "overlap_policy":policy,"next_fire_at":next.map(iso8601)}), + Some(&context), + None, + None, + ) + .await?; + tx.commit().await?; + Ok(json!({"schedule_id":schedule_id,"outcome":"updated"})) + } + /// `ScheduleManager::pause`: an active or paused schedule becomes paused /// now, keeping its note unless one is given. pub(super) async fn pause_in( diff --git a/rust/src/runtime/schedules.rs b/rust/src/runtime/schedules.rs index 2f44a37fc..ba863753b 100644 --- a/rust/src/runtime/schedules.rs +++ b/rust/src/runtime/schedules.rs @@ -45,6 +45,84 @@ const STORE_RULES: &Rules = &[ ("note", &[Rule::Nullable, Rule::String, Rule::Max(1000)]), ]; +/// `ScheduleController::updateRules`, in order. +const UPDATE_RULES: &Rules = &[ + ("spec", &[Rule::Nullable, Rule::Array]), + ("spec.cron_expressions", &[Rule::Nullable, Rule::Array]), + ("spec.cron_expressions.*", &[Rule::String]), + ("spec.intervals", &[Rule::Nullable, Rule::Array]), + ( + "spec.intervals.*.every", + &[Rule::RequiredWith("spec.intervals"), Rule::String, Rule::Max(64)], + ), + ("spec.intervals.*.offset", &[Rule::Nullable, Rule::String, Rule::Max(64)]), + ("spec.timezone", &[Rule::Nullable, Rule::String, Rule::Max(64)]), + ("action", &[Rule::Nullable, Rule::Array]), + ("action.workflow_type", &[Rule::Nullable, Rule::String]), + ("action.task_queue", &[Rule::Nullable, Rule::String]), + ("action.input", &[Rule::Nullable, Rule::Array]), + ("action.execution_timeout_seconds", &[Rule::Nullable, Rule::Integer, Rule::Min(1)]), + ("action.run_timeout_seconds", &[Rule::Nullable, Rule::Integer, Rule::Min(1)]), + ("action.workflow_execution_timeout", &[Rule::Nullable, Rule::Integer, Rule::Min(1)]), + ("action.workflow_run_timeout", &[Rule::Nullable, Rule::Integer, Rule::Min(1)]), + ("overlap_policy", &[Rule::Nullable, Rule::String, Rule::In(OVERLAP_POLICIES)]), + ("jitter_seconds", &[Rule::Nullable, Rule::Integer, Rule::Min(0), Rule::Max(3600)]), + ("max_runs", &[Rule::Nullable, Rule::Integer, Rule::Min(1)]), + ("memo", &[Rule::Nullable, Rule::Array]), + ("search_attributes", &[Rule::Nullable, Rule::Array]), + ("note", &[Rule::Nullable, Rule::String, Rule::Max(1000)]), +]; + +/// A validated schedule update: each field PHP's `ScheduleManager::update` +/// changes, `None` where it keeps the stored value. +pub(crate) struct Changes { + pub(crate) spec: Option, + /// The fields to merge over the stored action. + pub(crate) action: Option, + pub(crate) overlap_policy: Option, + pub(crate) jitter_seconds: Option, + pub(crate) note: Option, + /// `Some(None)` clears the memo. + pub(crate) memo: Option>, + /// The body named `search_attributes` (empty: native stores none). + pub(crate) clears_search_attributes: bool, + pub(crate) max_runs: Option, +} + +/// Validates an update body as PHP's `update` does, after the schedule is +/// found. +pub(crate) fn changes(body: &Value) -> Result { + let body = normalize(body); + validate(&body, UPDATE_RULES)?; + let validated = validated(&body, UPDATE_RULES); + memo_size(&validated["memo"])?; + if !empty(&validated["search_attributes"]) { + return Err(refuse( + StatusCode::UNPROCESSABLE_ENTITY, + "schedule_search_attributes_unavailable", + )); + } + let action = Some(validated["action"].clone()).filter(|action| !action.is_null()); + if let Some(input) = action.as_ref().and_then(|action| action.get("input")) + && !input.is_null() + { + super::envelope(action.as_ref().expect("action"), "input")?; + } + let fields = validated.as_object().expect("validated object"); + Ok(Changes { + spec: Some(validated["spec"].clone()).filter(|spec| !spec.is_null()), + action, + overlap_policy: validated["overlap_policy"].as_str().map(str::to_owned), + jitter_seconds: integer(&validated["jitter_seconds"]), + note: validated["note"].as_str().map(str::to_owned), + memo: fields + .contains_key("memo") + .then(|| Some(validated["memo"].clone()).filter(|memo| !empty(memo))), + clears_search_attributes: fields.contains_key("search_attributes"), + max_runs: integer(&validated["max_runs"]), + }) +} + /// A validated schedule creation. pub(crate) struct Definition { pub(crate) schedule_id: Option, @@ -244,6 +322,21 @@ pub(crate) fn next_fire(spec: &Value, jitter: i64, after: DateTime) -> Resu })) } +/// `computeNextFireAt` without jitter, with the UTC offset PHP's result +/// carries; failures as for `next_fire`. +pub(crate) fn next_occurrence(spec: &Value, after: DateTime) -> Result, i64)>> { + let at = jiff::Timestamp::new(after.timestamp(), after.timestamp_subsec_nanos() as i32) + .map_err(|_| refuse(StatusCode::UNPROCESSABLE_ENTITY, "invalid_schedule_spec"))?; + let next = schedule_spec::next_occurrence(spec, at).map_err(|error| RuntimeError::Protocol { + status: StatusCode::UNPROCESSABLE_ENTITY, + response: json!({"message":format!("Schedule spec could not be evaluated ({}).", error.php_class()), + "reason":"invalid_schedule_spec"}), + })?; + Ok(next.and_then(|(next, offset)| { + DateTime::from_timestamp(next.as_second(), next.subsec_nanosecond() as u32).map(|next| (next, offset)) + })) +} + /// A uniform integer in `0..=limit`, like PHP's `random_int(0, $limit)`. fn random_up_to(limit: i64) -> i64 { let mut bytes = [0u8; 8]; diff --git a/rust/tests/execution/schedules.rs b/rust/tests/execution/schedules.rs index ba58a3733..c7bc50662 100644 --- a/rust/tests/execution/schedules.rs +++ b/rust/tests/execution/schedules.rs @@ -397,3 +397,138 @@ async fn schedules_are_namespace_scoped_and_fire_into_their_own_namespace() { runtime.close().await; database.remove().await; } + +fn ids(page: &Value) -> Vec<&str> { + page["schedules"] + .as_array() + .unwrap() + .iter() + .map(|item| item["schedule_id"].as_str().unwrap()) + .collect() +} + +async fn list(app: &Router, query: &str) -> (StatusCode, Value) { + request(app, "GET", &format!("/api/schedules?{query}"), Value::Null).await +} + +fn encoded(text: &str) -> String { + form_urlencoded::byte_serialize(text.as_bytes()).collect() +} + +#[tokio::test] +async fn schedules_list_update_and_backfill_as_published_php() { + use super::namespaces::{create as create_namespace, scoped}; + let database = TestDatabase::new().await; + let runtime = database.open().await.unwrap(); + let app = router(runtime.clone()); + for (schedule, workflow_type, queue, extra) in [ + ("alpha", "echo", "q-a", json!({"note":"first"})), + ("beta", "other", "q-b", json!({"paused":true,"spec":{"cron_expressions":["0 3 * * *"],"timezone":"Europe/Budapest"}})), + ("gamma", "echo", "q-b", json!({"note":"x AND y"})), + ("delta", "echo", "q-d", json!({})), + ] { + let mut body = json!({"schedule_id":schedule,"spec":{"intervals":[{"every":"P1D"}]}, + "action":{"workflow_type":workflow_type,"task_queue":queue,"input":action()["input"]}}); + for (field, value) in extra.as_object().unwrap() { + body[field] = value.clone(); + } + let created = request(&app, "POST", "/api/schedules", body).await; + assert_eq!(created.0, StatusCode::CREATED, "{}", created.1); + } + + // Newest first, with PHP's filters and visibility predicates. + let all = list(&app, "").await; + assert_eq!((all.0, ids(&all.1)), (StatusCode::OK, vec!["delta", "gamma", "beta", "alpha"])); + assert_eq!((all.1["schedule_count"].clone(), all.1["next_page_token"].clone()), (json!(4), Value::Null)); + let beta = &all.1["schedules"][2]; + assert_eq!((beta["paused"].clone(), beta["workflow_type"].clone()), (json!(true), json!("other"))); + assert_eq!(ids(&list(&app, "status=paused").await.1), ["beta"]); + assert_eq!(ids(&list(&app, "workflow_type=echo").await.1), ["delta", "gamma", "alpha"]); + for (query, expected) in [ + ("WorkflowType = \"echo\" AND TaskQueue = 'q-b'", vec!["gamma"]), + ("Note = 'x AND y'", vec!["gamma"]), + ("ScheduleId = 'alpha' and Status = \"active\"", vec!["alpha"]), + ("Status = 'active'", vec!["delta", "gamma", "alpha"]), + ] { + let page = list(&app, &format!("query={}", encoded(query))).await; + assert_eq!((page.0, ids(&page.1)), (StatusCode::OK, expected), "{query}: {}", page.1); + } + let refused = list(&app, &format!("query={}", encoded("Status != 'active'"))).await; + assert_eq!((refused.0, refused.1["reason"].clone()), (StatusCode::UNPROCESSABLE_ENTITY, json!("unsupported_schedule_visibility_predicate"))); + let registered = request(&app, "POST", "/api/search-attributes", json!({"name":"Team","type":"keyword"})).await; + assert!(registered.0.is_success(), "{}", registered.1); + assert!(ids(&list(&app, &format!("query={}", encoded("Team = 'x'"))).await.1).is_empty()); + let typed = list(&app, &format!("query={}", encoded("Team = 5"))).await; + assert_eq!(typed.1["message"], "Schedule visibility field [Team] requires a quoted string literal."); + let invalid = list(&app, "page_size=0&bogus=1").await; + assert_eq!((invalid.0, invalid.1["reason"].clone()), (StatusCode::UNPROCESSABLE_ENTITY, json!("unsupported_schedule_list_filter"))); + let invalid = list(&app, "page_size=x").await; + assert_eq!(invalid.1["errors"], json!({"page_size":["The page size field must be an integer."]})); + + // Signed continuation tokens bound to the filters and namespace. + let first = list(&app, "page_size=2").await; + assert_eq!(ids(&first.1), ["delta", "gamma"]); + let token = encoded(first.1["next_page_token"].as_str().unwrap()); + let second = list(&app, &format!("page_size=2&next_page_token={token}")).await; + assert_eq!((ids(&second.1), second.1["next_page_token"].clone()), (vec!["beta", "alpha"], Value::Null)); + let mismatch = list(&app, &format!("page_size=2&status=active&next_page_token={token}")).await; + assert_eq!((mismatch.0, mismatch.1["reason"].clone()), (StatusCode::CONFLICT, json!("schedule_page_token_filter_mismatch"))); + assert_eq!(mismatch.1["last_safe_cursor"]["schedule_id"], "gamma"); + let tampered = list(&app, &format!("next_page_token={}", encoded(&format!("{}0", &first.1["next_page_token"].as_str().unwrap()[..20])))).await; + assert_eq!((tampered.0, tampered.1["reason"].clone()), (StatusCode::BAD_REQUEST, json!("malformed_schedule_page_token"))); + create_namespace(&app, "other").await; + let foreign = scoped(&app, "other", "GET", &format!("/api/schedules?page_size=2&next_page_token={token}"), Value::Null).await; + assert_eq!((foreign.0, foreign.1["reason"].clone()), (StatusCode::FORBIDDEN, json!("schedule_page_token_namespace_mismatch"))); + let newest = list(&app, "page_size=1").await; + let stale = encoded(newest.1["next_page_token"].as_str().unwrap()); + assert_eq!(request(&app, "DELETE", "/api/schedules/delta", Value::Null).await.0, StatusCode::OK); + let gone = list(&app, &format!("page_size=1&next_page_token={stale}")).await; + assert_eq!((gone.0, gone.1["reason"].clone()), (StatusCode::CONFLICT, json!("stale_schedule_page_token"))); + + // Updates merge the action and record PHP's changed fields. + let updated = request(&app, "PUT", "/api/schedules/alpha", + json!({"spec":{"cron_expressions":["0 4 * * *"],"timezone":"America/New_York"}, + "action":{"task_queue":"q-z","workflow_execution_timeout":60},"memo":{"k":"v"},"max_runs":5})).await; + assert_eq!(updated, (StatusCode::OK, json!({"schedule_id":"alpha","outcome":"updated"}))); + let alpha = request(&app, "GET", "/api/schedules/alpha", Value::Null).await.1; + assert_eq!((alpha["action"]["workflow_type"].clone(), alpha["action"]["task_queue"].clone()), (json!("echo"), json!("q-z"))); + assert_eq!(alpha["action"]["execution_timeout_seconds"], 60); + assert_eq!((alpha["max_runs"].clone(), alpha["remaining_actions"].clone()), (json!(5), json!(5))); + assert!(alpha["next_fire_at"].as_str().unwrap().contains("T08:00:00+00:00") || alpha["next_fire_at"].as_str().unwrap().contains("T09:00:00+00:00")); + let events = audit(&app, "alpha").await; + assert_eq!(events.last().unwrap()["payload"]["changed_fields"], json!(["spec","action","memo","max_runs","remaining_actions"])); + assert_eq!(ids(&list(&app, &format!("query={}", encoded("TaskQueue = 'q-z'"))).await.1), ["alpha"]); + let invalid = request(&app, "PUT", "/api/schedules/alpha", json!({"overlap_policy":"bad","jitter_seconds":4000})).await; + assert_eq!(invalid.0, StatusCode::UNPROCESSABLE_ENTITY); + assert_eq!(request(&app, "PUT", "/api/schedules/missing", json!({})).await.0, StatusCode::NOT_FOUND); + + // Backfill fires each past occurrence once, in PHP's formats. + let created = request(&app, "POST", "/api/schedules", json!({"schedule_id":"bf", + "spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1D","offset":"PT6H"}],"timezone":"Europe/Budapest"}, + "action":action(),"overlap_policy":"allow_all"})).await; + assert_eq!(created.0, StatusCode::CREATED, "{}", created.1); + let range = json!({"start_time":"2026-03-27T00:00:00Z","end_time":"2026-03-30 06:00:00+02:00"}); + let backfill = request(&app, "POST", "/api/schedules/bf/backfill", range.clone()).await; + assert_eq!(backfill.0, StatusCode::OK, "{}", backfill.1); + let times: Vec<&str> = backfill.1["results"].as_array().unwrap().iter().map(|result| { + assert_eq!(result["outcome"], "started"); + result["fire_time"].as_str().unwrap() + }).collect(); + assert_eq!(times, ["2026-03-27T03:00:00+01:00", "2026-03-27T06:00:00+00:00", "2026-03-28T03:00:00+01:00", + "2026-03-28T06:00:00+00:00", "2026-03-29T03:00:00+02:00", "2026-03-29T06:00:00+00:00", "2026-03-30T03:00:00+02:00"]); + let again = request(&app, "POST", "/api/schedules/bf/backfill", range).await; + assert!(again.1["results"].as_array().unwrap().iter().all(|result| result == &json!({"fire_time":result["fire_time"],"outcome":"skipped"}))); + let refused = request(&app, "POST", "/api/schedules/bf/backfill", json!({"start_time":"2026-04-01 +1 day","end_time":"2026-03-01"})).await; + assert_eq!(refused.1["errors"], json!({"start_time":["The start time field must be a valid date."]})); + let reversed = request(&app, "POST", "/api/schedules/bf/backfill", json!({"start_time":"2026-03-02","end_time":"2026-03-01"})).await; + assert_eq!(reversed, (StatusCode::UNPROCESSABLE_ENTITY, json!({"message":"end_time must be after start_time.","reason":"invalid_time_range"}))); + let created = request(&app, "POST", "/api/schedules", json!({"schedule_id":"bf-quota", + "spec":{"intervals":[{"every":"P1D"}]},"action":action(),"overlap_policy":"buffer_one","max_runs":2})).await; + assert_eq!(created.0, StatusCode::CREATED, "{}", created.1); + let quota = request(&app, "POST", "/api/schedules/bf-quota/backfill", + json!({"start_time":"2026-01-01T00:00:00Z","end_time":"2026-01-06T00:00:00Z"})).await; + assert_eq!(quota.1["fires_attempted"], 2, "{}", quota.1); + assert_eq!(request(&app, "GET", "/api/schedules/bf-quota", Value::Null).await.0, StatusCode::NOT_FOUND); + runtime.close().await; + database.remove().await; +} diff --git a/rust/tests/fixtures/cron/php-2.5.14-backfill-dates.jsonl b/rust/tests/fixtures/cron/php-2.5.14-backfill-dates.jsonl new file mode 100644 index 000000000..9763634c3 --- /dev/null +++ b/rust/tests/fixtures/cron/php-2.5.14-backfill-dates.jsonl @@ -0,0 +1,700 @@ +{"value":"now","iso":false,"valid":false} +{"value":"yesterday","iso":false,"valid":false} +{"value":"tomorrow 05:00","iso":false,"valid":false} +{"value":"next monday","iso":false,"valid":false} +{"value":"+1 day","iso":false,"valid":false} +{"value":"2026-04-01 +1 day","iso":false,"valid":true,"at":"1775088000.000000"} +{"value":"@1700000000","iso":false,"valid":true,"at":"1700000000.000000"} +{"value":"@1700000000.5","iso":false,"valid":true,"at":"1700000000.500000"} +{"value":"1700000000","iso":false,"valid":false} +{"value":"20260401","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"20260401T050000Z","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-4-1","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"2026-04-1T5:00","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026/04/01","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"04/01/2026","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"01.04.2026","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"1 April 2026","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"April 1, 2026","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"Wed, 01 Apr 2026 05:00:00 GMT","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01T05:00:00 UTC","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01T05:00:00 Europe/Budapest","iso":false,"valid":true,"at":"1775012400.000000"} +{"value":"2026-04-01T05:00:00+05:30:00","iso":false,"valid":true,"at":"1774999800.000000"} +{"value":"2026-04-01T05:00:00.000000Z","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01T05","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01T","iso":false,"valid":true,"at":"1775026800.000000"} +{"value":"2026-W14-3","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"2026-091","iso":false,"valid":false} +{"value":"-2026-04-01","iso":false,"valid":false} +{"value":"12026-04-01","iso":false,"valid":true,"at":"1143892920.000000"} +{"value":"0000-00-00","iso":false,"valid":false} +{"value":"0001-01-01","iso":false,"valid":true,"at":"-62135596800.000000"} +{"value":"9999-12-31T23:59:59Z","iso":false,"valid":true,"at":"253402300799.000000"} +{"value":"garbage","iso":false,"valid":false} +{"value":"T05:00:00","iso":false,"valid":false} +{"value":"05:00","iso":false,"valid":false} +{"value":"2026-04-01T05:00:00ZZ","iso":false,"valid":false} +{"value":"2026-04-01T05:00:00+2","iso":false,"valid":true,"at":"1775012400.000000"} +{"value":"2026-04-01T05:00:00-0","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01 05:00:00","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01T05:00:00.Z","iso":false,"valid":true,"at":"1775019600.000000"} +{"value":"2026-04-01T05:00:00,5Z","iso":false,"valid":false} +{"value":"2026-02-29","iso":false,"valid":false} +{"value":"2028-02-29T00:00:00Z","iso":false,"valid":true,"at":"1835395200.000000"} +{"value":"2100-02-29","iso":false,"valid":false} +{"value":"2000-02-29","iso":false,"valid":true,"at":"951782400.000000"} +{"value":"2026-04-01T05:00:00 +02:00","iso":false,"valid":true,"at":"1775012400.000000"} +{"value":"2026-04-01T05:00:00+02:00 ","iso":false,"valid":true,"at":"1775012400.000000"} +{"value":" 2026-04-01","iso":false,"valid":true,"at":"1775001600.000000"} +{"value":"2026-04-01T05:00:00GMT+2","iso":false,"valid":true,"at":"1775012400.000000"} +{"value":"2075-04-00","iso":true,"valid":false} +{"value":"2083-11-22T13:54:29.2-1259","iso":true,"valid":true,"at":"3594164009.200000"} +{"value":"2032-03-17T13:56:16-07","iso":true,"valid":true,"at":"1963169776.000000"} +{"value":"2001-11-09t00:37:25.976908-25","iso":true,"valid":true,"at":"1005356245.976908"} +{"value":"2067-12-17T08:48","iso":true,"valid":true,"at":"3091337280.000000"} +{"value":"1999-01-28T16:25:50z","iso":true,"valid":true,"at":"917540750.000000"} +{"value":"2032-05-11T12:17:00.5993","iso":true,"valid":true,"at":"1967890620.599300"} +{"value":"2081-08-13t04:60:44Z","iso":true,"valid":false} +{"value":"2022-08-18 18:25:35.469","iso":true,"valid":true,"at":"1660847135.469000"} +{"value":"2009-12-26T04:60:51.70291Z","iso":true,"valid":false} +{"value":"2095-11-13 23:53:44.690601031-05","iso":true,"valid":true,"at":"3972084824.690601"} +{"value":"2012-07-31T22:12:56","iso":true,"valid":true,"at":"1343772776.000000"} +{"value":"2095-08-28","iso":true,"valid":true,"at":"3965328000.000000"} +{"value":"1999-04-10T23:00:28-0200","iso":true,"valid":true,"at":"923792428.000000"} +{"value":"2018-12-28","iso":true,"valid":true,"at":"1545955200.000000"} +{"value":"1999-06-22","iso":true,"valid":true,"at":"930009600.000000"} +{"value":"1971-10-32T21:40","iso":true,"valid":false} +{"value":"2083-02-27t02:02:54.43315-00:30","iso":true,"valid":true,"at":"3570921174.433150"} +{"value":"2048-04-30","iso":true,"valid":true,"at":"2471817600.000000"} +{"value":"2000-10-09t20:59-0859","iso":true,"valid":true,"at":"971157480.000000"} +{"value":"2082-05-03T19:37:07+10","iso":true,"valid":true,"at":"3545026627.000000"} +{"value":"2400-01-14T00:60:57Z","iso":true,"valid":false} +{"value":"2400-01-32T10:45:37Z","iso":true,"valid":false} +{"value":"1992-12-24t09:06:00.80121321","iso":true,"valid":true,"at":"725187960.801213"} +{"value":"2077-06-25T21:07:60","iso":true,"valid":true,"at":"3391880880.000000"} +{"value":"2024-10-28T25:34:57 +23:00","iso":true,"valid":false} +{"value":"2058-11-21T19:60:00Z","iso":true,"valid":false} +{"value":"2005-04-20T11:07","iso":true,"valid":true,"at":"1113995220.000000"} +{"value":"2023-07-00 02:00:00","iso":true,"valid":false} +{"value":"2079-01-28T04:42:55","iso":true,"valid":true,"at":"3442106575.000000"} +{"value":"2098-13-28T10:40:27.198882","iso":true,"valid":false} +{"value":"2100-03-13","iso":true,"valid":true,"at":"4108579200.000000"} +{"value":"2069-05-12T11:30:41 -15","iso":true,"valid":true,"at":"3135637841.000000"} +{"value":"2040-04-14T08:07:35Z","iso":true,"valid":true,"at":"2218003655.000000"} +{"value":"2075-02-25","iso":true,"valid":true,"at":"3318278400.000000"} +{"value":"2096-09-22T24:45:52.868801075","iso":true,"valid":true,"at":"3999199552.868801"} +{"value":"2000-07-20T23:34-07:45","iso":true,"valid":true,"at":"964163940.000000"} +{"value":"2000-11-19T11:36:59Z","iso":true,"valid":true,"at":"974633819.000000"} +{"value":"2100-11-31","iso":true,"valid":false} +{"value":"1987-06-14T05:25:37.56303","iso":true,"valid":true,"at":"550646737.563030"} +{"value":"1986-04-28t16:06z","iso":true,"valid":true,"at":"515088360.000000"} +{"value":"1999-11-26T07:59:17z","iso":true,"valid":true,"at":"943603157.000000"} +{"value":"1995-09-01t13:16","iso":true,"valid":true,"at":"809961360.000000"} +{"value":"2024-12-21T03:20:33","iso":true,"valid":true,"at":"1734751233.000000"} +{"value":"2013-04-01T02:33:44","iso":true,"valid":true,"at":"1364783624.000000"} +{"value":"2070-11-24T03:18Z","iso":true,"valid":true,"at":"3184024680.000000"} +{"value":"2000-02-05","iso":true,"valid":true,"at":"949708800.000000"} +{"value":"2015-01-04 19:30:54+06","iso":true,"valid":true,"at":"1420378254.000000"} +{"value":"2034-05-30t01:53:45-0130","iso":true,"valid":true,"at":"2032572225.000000"} +{"value":"1977-12-13t21:41:57+02:30","iso":true,"valid":true,"at":"250888317.000000"} +{"value":"2020-04-21T02:01:47","iso":true,"valid":true,"at":"1587434507.000000"} +{"value":"1987-06-10T08:14:37.785767227Z","iso":true,"valid":true,"at":"550311277.785767"} +{"value":"2045-06-31t02:09:46-08","iso":true,"valid":false} +{"value":"2015-05-28 19:03:44z","iso":true,"valid":true,"at":"1432839824.000000"} +{"value":"2099-02-09T00:41:25.73023Z","iso":true,"valid":true,"at":"4074280885.730230"} +{"value":"2400-11-29t11:11:32+11","iso":true,"valid":true,"at":"13598237492.000000"} +{"value":"2100-10-05","iso":true,"valid":true,"at":"4126377600.000000"} +{"value":"2000-04-09t17:35:18-00:00","iso":true,"valid":true,"at":"955301718.000000"} +{"value":"2055-01-19 13:60:60+1200","iso":true,"valid":false} +{"value":"2022-05-25T10:17:48+08","iso":true,"valid":true,"at":"1653445068.000000"} +{"value":"1985-05-19T11:49:46Z","iso":true,"valid":true,"at":"485351386.000000"} +{"value":"2022-11-19T13:54","iso":true,"valid":true,"at":"1668866040.000000"} +{"value":"2048-10-01 25:15:31.8948022 +0745","iso":true,"valid":false} +{"value":"2051-11-27T06:29:00Z","iso":true,"valid":true,"at":"2584679340.000000"} +{"value":"2000-08-29T00:19:41Z","iso":true,"valid":true,"at":"967508381.000000"} +{"value":"2000-05-05T04:51:16.3432 -1000","iso":true,"valid":true,"at":"957538276.343200"} +{"value":"2061-10-22t13:21:07+00","iso":true,"valid":true,"at":"2897212867.000000"} +{"value":"1976-07-01T09:32:25-03:45","iso":true,"valid":true,"at":"205075045.000000"} +{"value":"2030-08-20t00:44:31+0230","iso":true,"valid":true,"at":"1913408071.000000"} +{"value":"2055-05-25t06:58:20.525623+02:00","iso":true,"valid":true,"at":"2694833900.525623"} +{"value":"2024-09-15t08:15:37Z","iso":true,"valid":true,"at":"1726388137.000000"} +{"value":"2099-07-30t10:35","iso":true,"valid":true,"at":"4089090900.000000"} +{"value":"2089-03-01","iso":true,"valid":true,"at":"3760473600.000000"} +{"value":"2043-11-18t00:14 +1130","iso":true,"valid":true,"at":"2331377040.000000"} +{"value":"2077-07-05t13:59","iso":true,"valid":true,"at":"3392719140.000000"} +{"value":"2044-08-04 06:60:17.7206194","iso":true,"valid":false} +{"value":"2000-09-22T03:36:45.8-1200","iso":true,"valid":true,"at":"969637005.800000"} +{"value":"1970-05-24 00:41:19Z","iso":true,"valid":true,"at":"12357679.000000"} +{"value":"2099-11-20t10:22:38","iso":true,"valid":true,"at":"4098853358.000000"} +{"value":"1979-03-20T20:33:01+02:30","iso":true,"valid":true,"at":"290800981.000000"} +{"value":"1996-08-05T11:16:43.1484 +0000","iso":true,"valid":true,"at":"839243803.148400"} +{"value":"1976-11-25t14:46:59","iso":true,"valid":true,"at":"217781219.000000"} +{"value":"1984-06-16","iso":true,"valid":true,"at":"456192000.000000"} +{"value":"2035-05-19T11:36:14+0545","iso":true,"valid":true,"at":"2063166674.000000"} +{"value":"1985-01-07T11:24:19","iso":true,"valid":true,"at":"473945059.000000"} +{"value":"2073-06-08T22:10:45Z","iso":true,"valid":true,"at":"3264185445.000000"} +{"value":"1993-09-32T05:03:60.7051929Z","iso":true,"valid":false} +{"value":"1999-08-21T15:18:49 +09:45","iso":true,"valid":true,"at":"935213629.000000"} +{"value":"2073-07-17 20:42:15-06","iso":true,"valid":true,"at":"3267571335.000000"} +{"value":"2026-11-03 00:10:52.889283143 -14","iso":true,"valid":true,"at":"1793715052.889283"} +{"value":"2063-04-27T08:35:40","iso":true,"valid":true,"at":"2944888540.000000"} +{"value":"1971-07-15","iso":true,"valid":true,"at":"48384000.000000"} +{"value":"2094-08-16T08:45:26","iso":true,"valid":true,"at":"3932786726.000000"} +{"value":"1997-07-31T16:09:22-03","iso":true,"valid":true,"at":"870376162.000000"} +{"value":"2021-04-12 18:02:37","iso":true,"valid":true,"at":"1618250557.000000"} +{"value":"2000-01-03T18:14:57.1-0045","iso":true,"valid":true,"at":"946925997.100000"} +{"value":"2030-12-28 21:50:03.5511990+11:30","iso":true,"valid":true,"at":"1924683603.551199"} +{"value":"2002-03-04T17:59:15.74784z","iso":true,"valid":true,"at":"1015264755.747840"} +{"value":"2001-12-32 17:44:55.7z","iso":true,"valid":false} +{"value":"2031-10-14t00:00:20-01","iso":true,"valid":true,"at":"1949706020.000000"} +{"value":"2021-05-04 15:17:41+07:00","iso":true,"valid":true,"at":"1620116261.000000"} +{"value":"2090-07-04T04:20:34+00:00","iso":true,"valid":true,"at":"3802825234.000000"} +{"value":"2029-09-25","iso":true,"valid":true,"at":"1884988800.000000"} +{"value":"2067-03-07T21:59:11+00:45","iso":true,"valid":true,"at":"3066758051.000000"} +{"value":"1979-06-24 14:48:41","iso":true,"valid":true,"at":"299083721.000000"} +{"value":"2090-11-25T09:21Z","iso":true,"valid":true,"at":"3815284860.000000"} +{"value":"2005-05-24 00:40","iso":true,"valid":true,"at":"1116895200.000000"} +{"value":"1992-04-11T03:27:08-0000","iso":true,"valid":true,"at":"702962828.000000"} +{"value":"1970-04-18","iso":true,"valid":true,"at":"9244800.000000"} +{"value":"2000-12-28T22:27:58 +0600","iso":true,"valid":true,"at":"978020878.000000"} +{"value":"2059-04-03T04:42:58 +10:45","iso":true,"valid":true,"at":"2816531878.000000"} +{"value":"2086-09-14 05:59","iso":true,"valid":true,"at":"3682821540.000000"} +{"value":"1973-07-08T12:07:23z","iso":true,"valid":true,"at":"110981243.000000"} +{"value":"1977-10-16T16:56:59Z","iso":true,"valid":true,"at":"245869019.000000"} +{"value":"2066-04-04 06:18","iso":true,"valid":true,"at":"3037587480.000000"} +{"value":"1995-09-20T00:00:07.67972","iso":true,"valid":true,"at":"811555207.679720"} +{"value":"2006-04-03T00:43:50","iso":true,"valid":true,"at":"1144025030.000000"} +{"value":"1972-09-12T08:11-09:00","iso":true,"valid":true,"at":"85165860.000000"} +{"value":"1971-03-18T01:09:05-1200","iso":true,"valid":true,"at":"38149745.000000"} +{"value":"2046-11-15T18:28:06","iso":true,"valid":true,"at":"2425919286.000000"} +{"value":"2099-02-09T01:03:57Z","iso":true,"valid":true,"at":"4074282237.000000"} +{"value":"2015-10-04t12:04:51+03:45","iso":true,"valid":true,"at":"1443946791.000000"} +{"value":"1997-08-27T20:00:53-04","iso":true,"valid":true,"at":"872726453.000000"} +{"value":"1980-12-00","iso":true,"valid":false} +{"value":"2061-03-22t00:59:09.8053Z","iso":true,"valid":true,"at":"2878678749.805300"} +{"value":"2027-01-22t06:07:39.5681Z","iso":true,"valid":true,"at":"1800598059.568100"} +{"value":"2400-09-31","iso":true,"valid":false} +{"value":"2011-10-13T16:37:28","iso":true,"valid":true,"at":"1318523848.000000"} +{"value":"2020-03-27","iso":true,"valid":true,"at":"1585267200.000000"} +{"value":"2041-01-21t15:45:05.76","iso":true,"valid":true,"at":"2242395905.760000"} +{"value":"2010-03-02t16:07","iso":true,"valid":true,"at":"1267546020.000000"} +{"value":"2063-09-15t07:43:34.9+14","iso":true,"valid":true,"at":"2957017414.900000"} +{"value":"2049-08-06T03:42 -05:30","iso":true,"valid":true,"at":"2511853920.000000"} +{"value":"2000-01-27T23:55:09Z","iso":true,"valid":true,"at":"949017309.000000"} +{"value":"2024-02-04t06:38Z","iso":true,"valid":true,"at":"1707028680.000000"} +{"value":"2097-06-09t18:05:29+0700","iso":true,"valid":true,"at":"4021614329.000000"} +{"value":"2028-12-20 09:29z","iso":true,"valid":true,"at":"1860917340.000000"} +{"value":"1975-01-32T19:35:08","iso":true,"valid":false} +{"value":"2021-02-16T09:59:15.6Z","iso":true,"valid":true,"at":"1613469555.600000"} +{"value":"2088-08-07T12:48:28+11","iso":true,"valid":true,"at":"3742681708.000000"} +{"value":"2059-04-28","iso":true,"valid":true,"at":"2818713600.000000"} +{"value":"2005-07-05T00:00:59Z","iso":true,"valid":true,"at":"1120521659.000000"} +{"value":"2024-04-00T17:38:36.1300Z","iso":true,"valid":false} +{"value":"2004-05-17T16:57:17-11","iso":true,"valid":true,"at":"1084852637.000000"} +{"value":"2400-04-27","iso":true,"valid":true,"at":"13579574400.000000"} +{"value":"1990-11-05T22:48:61Z","iso":true,"valid":false} +{"value":"2075-04-17T00:23:00","iso":true,"valid":true,"at":"3322686180.000000"} +{"value":"2400-01-25T18:43:42.997+0130","iso":true,"valid":true,"at":"13571601222.997000"} +{"value":"2012-09-07T25:52:52Z","iso":true,"valid":false} +{"value":"2032-12-26 12:57:25+02:59","iso":true,"valid":true,"at":"1987667905.000000"} +{"value":"2014-09-12T03:60:48.702448Z","iso":true,"valid":false} +{"value":"1970-11-12T24:09:50.575906","iso":true,"valid":true,"at":"27302990.575906"} +{"value":"2000-04-25T06:30:33-07","iso":true,"valid":true,"at":"956669433.000000"} +{"value":"2082-04-22","iso":true,"valid":true,"at":"3544041600.000000"} +{"value":"2017-05-29","iso":true,"valid":true,"at":"1496016000.000000"} +{"value":"2080-01-31 17:60:42.25786123 -24:00","iso":true,"valid":false} +{"value":"2072-06-04t00:41:59+1059","iso":true,"valid":true,"at":"3232186979.000000"} +{"value":"1986-06-32t01:41:37.6963825+10","iso":true,"valid":false} +{"value":"2039-03-00T20:10:40 -05:00","iso":true,"valid":false} +{"value":"2400-10-01T23:27:00+04:30","iso":true,"valid":true,"at":"13593207420.000000"} +{"value":"2023-06-28T15:38","iso":true,"valid":true,"at":"1687966680.000000"} +{"value":"2093-12-20 07:48:28 +1100","iso":true,"valid":true,"at":"3912094108.000000"} +{"value":"2008-06-07t18:39:11+23","iso":true,"valid":true,"at":"1212781151.000000"} +{"value":"2027-04-10T19:41:61","iso":true,"valid":false} +{"value":"1980-06-21t22:59:01","iso":true,"valid":true,"at":"330476341.000000"} +{"value":"2400-08-11T09:49:42Z","iso":true,"valid":true,"at":"13588768182.000000"} +{"value":"1984-01-03T11:32","iso":true,"valid":true,"at":"441977520.000000"} +{"value":"1984-02-02T19:59:24","iso":true,"valid":true,"at":"444599964.000000"} +{"value":"2018-10-10T12:51:27.1690674","iso":true,"valid":true,"at":"1539175887.169067"} +{"value":"2094-04-20","iso":true,"valid":true,"at":"3922560000.000000"} +{"value":"2063-08-26","iso":true,"valid":true,"at":"2955312000.000000"} +{"value":"2044-05-30","iso":true,"valid":true,"at":"2348179200.000000"} +{"value":"2041-05-02T17:11:10z","iso":true,"valid":true,"at":"2251127470.000000"} +{"value":"2016-08-14T00:46:04+0530","iso":true,"valid":true,"at":"1471115764.000000"} +{"value":"1993-07-05","iso":true,"valid":true,"at":"741830400.000000"} +{"value":"2092-08-11T19:05:02.857122290 +05","iso":true,"valid":true,"at":"3869301902.857122"} +{"value":"2400-07-26t19:13:60.29590032","iso":true,"valid":true,"at":"13587419640.295900"} +{"value":"2050-02-24","iso":true,"valid":true,"at":"2529273600.000000"} +{"value":"2015-03-30T21:47:48.175935976","iso":true,"valid":true,"at":"1427752068.175935"} +{"value":"2100-01-25t13:31:15.2642270+09","iso":true,"valid":true,"at":"4104534675.264227"} +{"value":"2070-05-16T16:29:48.4361395z","iso":true,"valid":true,"at":"3167483388.436139"} +{"value":"2081-02-24T01:45-02:30","iso":true,"valid":true,"at":"3507596100.000000"} +{"value":"1985-05-21T12:21","iso":true,"valid":true,"at":"485526060.000000"} +{"value":"2088-10-11 13:13:49.69+04","iso":true,"valid":true,"at":"3748324429.690000"} +{"value":"1983-04-08 23:27:40","iso":true,"valid":true,"at":"418692460.000000"} +{"value":"2027-03-17t09:26:46.758782121-01:00","iso":true,"valid":true,"at":"1805279206.758782"} +{"value":"1995-03-00T17:14:11Z","iso":true,"valid":false} +{"value":"2072-12-02T15:43:11z","iso":true,"valid":true,"at":"3247918991.000000"} +{"value":"2074-03-23 20:36:51","iso":true,"valid":true,"at":"3289063011.000000"} +{"value":"2020-08-00 21:60:01z","iso":true,"valid":false} +{"value":"2089-06-23T25:33:20z","iso":true,"valid":false} +{"value":"2008-07-29T04:60z","iso":true,"valid":false} +{"value":"2046-08-07T15:36","iso":true,"valid":true,"at":"2417268960.000000"} +{"value":"2400-06-24","iso":true,"valid":true,"at":"13584585600.000000"} +{"value":"2055-04-18T03:05:09z","iso":true,"valid":true,"at":"2691630309.000000"} +{"value":"1994-08-01T18:43:00z","iso":true,"valid":true,"at":"775766580.000000"} +{"value":"2024-01-17t09:21:38Z","iso":true,"valid":true,"at":"1705483298.000000"} +{"value":"2085-10-30T05:04:33.419604213 -04","iso":true,"valid":true,"at":"3655271073.419604"} +{"value":"2014-09-27T07:33:00.3799+09","iso":true,"valid":true,"at":"1411770780.379900"} +{"value":"1994-04-25T00:31Z","iso":true,"valid":true,"at":"767233860.000000"} +{"value":"2027-04-25T02:24:44-04","iso":true,"valid":true,"at":"1808634284.000000"} +{"value":"2072-06-27T01:51:21+0159","iso":true,"valid":true,"at":"3234210741.000000"} +{"value":"2076-02-14t08:34:30Z","iso":true,"valid":true,"at":"3348894870.000000"} +{"value":"2011-10-25T17:52:58z","iso":true,"valid":true,"at":"1319565178.000000"} +{"value":"2100-04-13T24:13:48.6207404Z","iso":true,"valid":true,"at":"4111344828.620740"} +{"value":"2095-03-04 01:43","iso":true,"valid":true,"at":"3950041380.000000"} +{"value":"2039-05-01","iso":true,"valid":true,"at":"2187820800.000000"} +{"value":"2000-07-23","iso":true,"valid":true,"at":"964310400.000000"} +{"value":"2004-01-28t11:13Z","iso":true,"valid":true,"at":"1075288380.000000"} +{"value":"1999-10-27T18:31:16.71985195-0500","iso":true,"valid":true,"at":"941067076.719851"} +{"value":"2079-08-18T10:11:38.9172190","iso":true,"valid":true,"at":"3459579098.917219"} +{"value":"2035-07-09t07:17:36","iso":true,"valid":true,"at":"2067578256.000000"} +{"value":"2071-06-23","iso":true,"valid":true,"at":"3202243200.000000"} +{"value":"2000-10-21 03:50z","iso":true,"valid":true,"at":"972100200.000000"} +{"value":"2088-05-00T02:56:20-07:00","iso":true,"valid":false} +{"value":"2075-11-24 12:25","iso":true,"valid":true,"at":"3341823900.000000"} +{"value":"2059-01-12T24:59-05","iso":true,"valid":true,"at":"2809663140.000000"} +{"value":"2087-06-19t04:60","iso":true,"valid":false} +{"value":"2010-00-13t13:29:54-05","iso":true,"valid":false} +{"value":"2100-08-25 14:42:28z","iso":true,"valid":true,"at":"4122888148.000000"} +{"value":"2080-01-21 01:24+03","iso":true,"valid":true,"at":"3473015040.000000"} +{"value":"2076-12-03 15:07:00z","iso":true,"valid":true,"at":"3374233620.000000"} +{"value":"1996-06-14T13:49","iso":true,"valid":true,"at":"834760140.000000"} +{"value":"2033-10-12 04:60:10","iso":true,"valid":false} +{"value":"2086-03-31t08:00-1000","iso":true,"valid":true,"at":"3668436000.000000"} +{"value":"2097-07-08 05:41:54.2866Z","iso":true,"valid":true,"at":"4024100514.286600"} +{"value":"2000-05-05T07:56:25 -03","iso":true,"valid":true,"at":"957524185.000000"} +{"value":"1974-07-26","iso":true,"valid":true,"at":"144028800.000000"} +{"value":"2011-01-03 00:00:48","iso":true,"valid":true,"at":"1294012848.000000"} +{"value":"1999-03-25T08:58","iso":true,"valid":true,"at":"922352280.000000"} +{"value":"2050-01-12t23:37:39 +0600","iso":true,"valid":true,"at":"2525621859.000000"} +{"value":"2009-13-07T01:20:05.982405","iso":true,"valid":false} +{"value":"2008-03-05T05:10:12","iso":true,"valid":true,"at":"1204693812.000000"} +{"value":"2063-01-00t24:19:07","iso":true,"valid":false} +{"value":"2078-10-16T14:32:57.9629610","iso":true,"valid":true,"at":"3433156377.962961"} +{"value":"2400-01-30","iso":true,"valid":true,"at":"13571971200.000000"} +{"value":"2045-09-31T10:05:52Z","iso":true,"valid":false} +{"value":"2073-11-07t04:42 -03:45","iso":true,"valid":true,"at":"3277268820.000000"} +{"value":"2100-09-04 10:00:46.56847 +11:30","iso":true,"valid":true,"at":"4123693846.568470"} +{"value":"2000-02-29t22:08:02.219z","iso":true,"valid":true,"at":"951862082.219000"} +{"value":"2000-10-28T20:22 -09:00","iso":true,"valid":true,"at":"972796920.000000"} +{"value":"2085-12-28T00:39:17.7074z","iso":true,"valid":true,"at":"3660338357.707400"} +{"value":"2051-12-20","iso":true,"valid":true,"at":"2586643200.000000"} +{"value":"2015-04-29T21:58:13.543453","iso":true,"valid":true,"at":"1430344693.543453"} +{"value":"2019-01-03T18:45:42.163410867Z","iso":true,"valid":true,"at":"1546541142.163410"} +{"value":"2069-11-25T09:40:38z","iso":true,"valid":true,"at":"3152598038.000000"} +{"value":"1972-02-07","iso":true,"valid":true,"at":"66268800.000000"} +{"value":"2068-05-06T20:03:52-0960","iso":true,"valid":false} +{"value":"2026-10-15","iso":true,"valid":true,"at":"1792022400.000000"} +{"value":"2019-05-16 23:19+07:45","iso":true,"valid":true,"at":"1558020840.000000"} +{"value":"1990-12-03T15:02+10:45","iso":true,"valid":true,"at":"660197820.000000"} +{"value":"2012-01-23T10:24:45-2430","iso":true,"valid":true,"at":"1327402485.000000"} +{"value":"1970-05-23T24:38:40","iso":true,"valid":true,"at":"12357520.000000"} +{"value":"2050-02-00T12:60:18 -09:00","iso":true,"valid":false} +{"value":"2067-08-15T04:52-04","iso":true,"valid":true,"at":"3080623920.000000"} +{"value":"2078-07-32T07:09:00","iso":true,"valid":false} +{"value":"2100-04-26","iso":true,"valid":true,"at":"4112380800.000000"} +{"value":"1998-10-14T15:50:59.282407826","iso":true,"valid":true,"at":"908380259.282407"} +{"value":"2064-08-22T13:46:18.82496+09","iso":true,"valid":true,"at":"2986605978.824960"} +{"value":"1970-09-31T23:00","iso":true,"valid":false} +{"value":"2043-07-28T02:47:54Z","iso":true,"valid":true,"at":"2321664474.000000"} +{"value":"2036-05-21T22:09:46-1130","iso":true,"valid":true,"at":"2095061986.000000"} +{"value":"2083-04-28t22:00:54","iso":true,"valid":true,"at":"3576175254.000000"} +{"value":"2100-04-12T14:42:53.8184092","iso":true,"valid":true,"at":"4111224173.818409"} +{"value":"2031-04-24","iso":true,"valid":true,"at":"1934755200.000000"} +{"value":"2049-12-10 21:52","iso":true,"valid":true,"at":"2522785920.000000"} +{"value":"1970-11-18T02:20:38.4417","iso":true,"valid":true,"at":"27742838.441700"} +{"value":"2037-12-17 04:05:29z","iso":true,"valid":true,"at":"2144635529.000000"} +{"value":"2005-10-29t06:21:08z","iso":true,"valid":true,"at":"1130566868.000000"} +{"value":"2400-01-00t00:37:00.3+01:30","iso":true,"valid":false} +{"value":"2011-08-30T23:24:20+14:00","iso":true,"valid":true,"at":"1314696260.000000"} +{"value":"2000-08-04t25:35Z","iso":true,"valid":false} +{"value":"1970-05-27T23:46:21.37z","iso":true,"valid":true,"at":"12699981.370000"} +{"value":"2050-09-00 23:08:06+09:45","iso":true,"valid":false} +{"value":"2054-02-19 18:00:16Z","iso":true,"valid":true,"at":"2655136816.000000"} +{"value":"2000-02-09 23:42 -00:45","iso":true,"valid":true,"at":"950142420.000000"} +{"value":"2002-12-18 20:38+23","iso":true,"valid":true,"at":"1040161080.000000"} +{"value":"1970-05-29T12:41:40+02","iso":true,"valid":true,"at":"12825700.000000"} +{"value":"2087-08-12 20:49 -1100","iso":true,"valid":true,"at":"3711599340.000000"} +{"value":"2078-05-28 15:12:19","iso":true,"valid":true,"at":"3420976339.000000"} +{"value":"2050-05-20t13:07:25","iso":true,"valid":true,"at":"2536664845.000000"} +{"value":"2000-11-28","iso":true,"valid":true,"at":"975369600.000000"} +{"value":"1970-03-01T02:58:07Z","iso":true,"valid":true,"at":"5108287.000000"} +{"value":"2030-07-20T07:38:41.2181","iso":true,"valid":true,"at":"1910763521.218100"} +{"value":"2014-06-32","iso":true,"valid":false} +{"value":"2002-10-12t18:30:27Z","iso":true,"valid":true,"at":"1034447427.000000"} +{"value":"1982-12-25T08:31:50-05","iso":true,"valid":true,"at":"409671110.000000"} +{"value":"2012-10-26","iso":true,"valid":true,"at":"1351209600.000000"} +{"value":"1988-09-08","iso":true,"valid":true,"at":"589680000.000000"} +{"value":"1977-01-31","iso":true,"valid":true,"at":"223516800.000000"} +{"value":"2014-12-28T11:52:30","iso":true,"valid":true,"at":"1419767550.000000"} +{"value":"2017-03-15","iso":true,"valid":true,"at":"1489536000.000000"} +{"value":"2024-04-29","iso":true,"valid":true,"at":"1714348800.000000"} +{"value":"2039-04-00 08:18:15Z","iso":true,"valid":false} +{"value":"2002-09-01T14:55:50 +25","iso":true,"valid":true,"at":"1030802150.000000"} +{"value":"2092-07-17 19:45:50+00:00","iso":true,"valid":true,"at":"3867162350.000000"} +{"value":"2060-04-18T19:59 +15:45","iso":true,"valid":true,"at":"2849487240.000000"} +{"value":"2030-06-00T07:47:40.37232 +11:45","iso":true,"valid":false} +{"value":"2064-11-14 22:09:31 +10:30","iso":true,"valid":true,"at":"2993888371.000000"} +{"value":"1972-11-28","iso":true,"valid":true,"at":"91756800.000000"} +{"value":"2002-12-24T09:21:51-05:45","iso":true,"valid":true,"at":"1040742411.000000"} +{"value":"2010-04-19T17:59:22.721300539","iso":true,"valid":true,"at":"1271699962.721300"} +{"value":"2072-08-25 13:46:33-15:30","iso":true,"valid":true,"at":"3239414193.000000"} +{"value":"2038-07-11T06:36-07:45","iso":true,"valid":true,"at":"2162470860.000000"} +{"value":"1984-08-26T08:10:24.905235Z","iso":true,"valid":true,"at":"462355824.905235"} +{"value":"2095-09-06T21:49-0800","iso":true,"valid":true,"at":"3966212940.000000"} +{"value":"2010-01-28T05:09:10","iso":true,"valid":true,"at":"1264655350.000000"} +{"value":"2099-01-06T18:52","iso":true,"valid":true,"at":"4071408720.000000"} +{"value":"2012-04-10T03:28-10","iso":true,"valid":true,"at":"1334064480.000000"} +{"value":"2024-06-21T01:09+01:00","iso":true,"valid":true,"at":"1718928540.000000"} +{"value":"2042-06-08T18:21z","iso":true,"valid":true,"at":"2285864460.000000"} +{"value":"2068-07-06T07:45:41.4Z","iso":true,"valid":true,"at":"3108786341.400000"} +{"value":"2024-03-07 11:05:32 -08:00","iso":true,"valid":true,"at":"1709838332.000000"} +{"value":"1990-02-14","iso":true,"valid":true,"at":"634953600.000000"} +{"value":"1983-03-15T16:59","iso":true,"valid":true,"at":"416595540.000000"} +{"value":"2075-11-15T08:59:23-0300","iso":true,"valid":true,"at":"3341044763.000000"} +{"value":"1986-06-25T10:01:17-0745","iso":true,"valid":true,"at":"520105577.000000"} +{"value":"1980-13-27 13:08:37.6532-0230","iso":true,"valid":false} +{"value":"2055-08-09T13:29:57.108372+0900","iso":true,"valid":true,"at":"2701398597.108372"} +{"value":"2082-02-28t04:47:47.2-02:45","iso":true,"valid":true,"at":"3539489567.200000"} +{"value":"2023-04-05 19:08z","iso":true,"valid":true,"at":"1680721680.000000"} +{"value":"1983-07-28 05:35Z","iso":true,"valid":true,"at":"428218500.000000"} +{"value":"2065-10-27","iso":true,"valid":true,"at":"3023827200.000000"} +{"value":"1978-03-00 13:48:16.8-08:00","iso":true,"valid":false} +{"value":"2400-08-01T16:22:26.997937 -00","iso":true,"valid":true,"at":"13587927746.997937"} +{"value":"2098-12-00T20:48:29.50752-0500","iso":true,"valid":false} +{"value":"2024-06-26T25:27:15-06","iso":true,"valid":false} +{"value":"2017-02-29T20:46:17","iso":true,"valid":false} +{"value":"2028-07-14T00:46:45.2972350Z","iso":true,"valid":true,"at":"1847148405.297235"} +{"value":"2023-06-05 07:59:56Z","iso":true,"valid":true,"at":"1685951996.000000"} +{"value":"2024-04-28","iso":true,"valid":true,"at":"1714262400.000000"} +{"value":"1999-05-08","iso":true,"valid":true,"at":"926121600.000000"} +{"value":"2015-05-14T22:15:08.56578476Z","iso":true,"valid":true,"at":"1431641708.565784"} +{"value":"2018-11-22T13:46:29z","iso":true,"valid":true,"at":"1542894389.000000"} +{"value":"2051-05-07t19:57:15Z","iso":true,"valid":true,"at":"2567102235.000000"} +{"value":"2045-01-29T15:10:49.8222169-08","iso":true,"valid":true,"at":"2369344249.822216"} +{"value":"2034-02-31T02:40:28z","iso":true,"valid":false} +{"value":"2020-07-06T21:56:25.58927258Z","iso":true,"valid":true,"at":"1594072585.589272"} +{"value":"1999-01-05T03:37:07z","iso":true,"valid":true,"at":"915507427.000000"} +{"value":"2100-08-16T18:00:37","iso":true,"valid":true,"at":"4122122437.000000"} +{"value":"1977-05-11","iso":true,"valid":true,"at":"232156800.000000"} +{"value":"2099-08-05T10:08:05Z","iso":true,"valid":true,"at":"4089607685.000000"} +{"value":"2060-10-22","iso":true,"valid":true,"at":"2865628800.000000"} +{"value":"2070-02-30 16:00:46 +0430","iso":true,"valid":false} +{"value":"2094-12-24T19:44:16.830141 +05","iso":true,"valid":true,"at":"3944040256.830141"} +{"value":"2039-06-21 12:40:34.175748209Z","iso":true,"valid":true,"at":"2192272834.175748"} +{"value":"2034-12-14T23:60:08.1","iso":true,"valid":false} +{"value":"2008-10-15","iso":true,"valid":true,"at":"1224028800.000000"} +{"value":"2086-00-18t03:45:16.882159653","iso":true,"valid":false} +{"value":"2041-08-20t20:27:00.1035 -10:00","iso":true,"valid":true,"at":"2260679220.103500"} +{"value":"2064-04-16T21:59:59-0800","iso":true,"valid":true,"at":"2975637599.000000"} +{"value":"2011-09-22t00:28:22-04:00","iso":true,"valid":true,"at":"1316665702.000000"} +{"value":"2400-12-31T00:56:11","iso":true,"valid":true,"at":"13601004971.000000"} +{"value":"2058-07-28","iso":true,"valid":true,"at":"2795040000.000000"} +{"value":"1995-02-18T20:45:53Z","iso":true,"valid":true,"at":"793140353.000000"} +{"value":"2066-06-12","iso":true,"valid":true,"at":"3043526400.000000"} +{"value":"2017-07-26","iso":true,"valid":true,"at":"1501027200.000000"} +{"value":"2100-03-18T06:29:52Z","iso":true,"valid":true,"at":"4109034592.000000"} +{"value":"2100-05-09 06:59z","iso":true,"valid":true,"at":"4113529140.000000"} +{"value":"1999-06-08T02:60:60+00","iso":true,"valid":false} +{"value":"2037-10-25T23:30:02.26432","iso":true,"valid":true,"at":"2140126202.264320"} +{"value":"1973-03-23","iso":true,"valid":true,"at":"101692800.000000"} +{"value":"2079-07-17","iso":true,"valid":true,"at":"3456777600.000000"} +{"value":"2036-03-22T10:53:37-04:45","iso":true,"valid":true,"at":"2089813117.000000"} +{"value":"2078-07-26T11:04:18.459253Z","iso":true,"valid":true,"at":"3426059058.459253"} +{"value":"1974-04-17T05:52-0230","iso":true,"valid":true,"at":"135418920.000000"} +{"value":"2400-07-25 23:07:38","iso":true,"valid":true,"at":"13587347258.000000"} +{"value":"1970-01-19","iso":true,"valid":true,"at":"1555200.000000"} +{"value":"1999-06-27 11:25:56","iso":true,"valid":true,"at":"930482756.000000"} +{"value":"1988-10-30T20:10:61z","iso":true,"valid":false} +{"value":"1985-09-11 20:48:55z","iso":true,"valid":true,"at":"495319735.000000"} +{"value":"2052-05-08T14:01:33","iso":true,"valid":true,"at":"2598789693.000000"} +{"value":"2061-06-28 15:33","iso":true,"valid":true,"at":"2887198380.000000"} +{"value":"1976-01-14T12:28:23.753 -0400","iso":true,"valid":true,"at":"190484903.753000"} +{"value":"2099-04-14 22:19:00Z","iso":true,"valid":true,"at":"4079888340.000000"} +{"value":"1999-09-00t00:04:59-1400","iso":true,"valid":false} +{"value":"2029-10-22T00:51:51.89959-11","iso":true,"valid":true,"at":"1887364311.899590"} +{"value":"2099-11-18 12:12:21-00","iso":true,"valid":true,"at":"4098687141.000000"} +{"value":"2093-05-29t13:44","iso":true,"valid":true,"at":"3894443040.000000"} +{"value":"1981-05-09T14:07:52z","iso":true,"valid":true,"at":"358265272.000000"} +{"value":"2099-12-26T21:38:02Z","iso":true,"valid":true,"at":"4102004282.000000"} +{"value":"2021-09-06T04:56:32-0745","iso":true,"valid":true,"at":"1630932092.000000"} +{"value":"2003-01-32 00:49+11","iso":true,"valid":false} +{"value":"2061-10-07T05:25Z","iso":true,"valid":true,"at":"2895888300.000000"} +{"value":"2064-01-32T02:06:47.16544090z","iso":true,"valid":false} +{"value":"2065-04-08t01:38-05:30","iso":true,"valid":true,"at":"3006400080.000000"} +{"value":"2050-07-31 09:49","iso":true,"valid":true,"at":"2542873740.000000"} +{"value":"2002-02-31T16:33:00z","iso":true,"valid":false} +{"value":"1994-04-19T14:31 -00:00","iso":true,"valid":true,"at":"766765860.000000"} +{"value":"2100-05-19t21:08-11","iso":true,"valid":true,"at":"4114483680.000000"} +{"value":"2012-04-16T00:49:31","iso":true,"valid":true,"at":"1334537371.000000"} +{"value":"2057-08-20T09:13:12Z","iso":true,"valid":true,"at":"2765524392.000000"} +{"value":"2047-07-05T00:41:29.904z","iso":true,"valid":true,"at":"2445900089.904000"} +{"value":"1981-04-28T22:40:27Z","iso":true,"valid":true,"at":"357345627.000000"} +{"value":"1971-09-02","iso":true,"valid":true,"at":"52617600.000000"} +{"value":"1987-11-23","iso":true,"valid":true,"at":"564624000.000000"} +{"value":"2080-02-26T20:59:07-25","iso":true,"valid":true,"at":"3476296747.000000"} +{"value":"2050-01-03T10:07","iso":true,"valid":true,"at":"2524817220.000000"} +{"value":"2069-08-32T17:18:55+00:45","iso":true,"valid":false} +{"value":"2040-02-11 16:02:51 -08","iso":true,"valid":true,"at":"2212617771.000000"} +{"value":"2050-05-32t00:53:55.25602 +0030","iso":true,"valid":false} +{"value":"1992-12-17T23:22:59.629161","iso":true,"valid":true,"at":"724634579.629161"} +{"value":"2062-10-23","iso":true,"valid":true,"at":"2928787200.000000"} +{"value":"2100-11-13T13:22:49-06","iso":true,"valid":true,"at":"4129816969.000000"} +{"value":"2066-01-15","iso":true,"valid":true,"at":"3030739200.000000"} +{"value":"2063-04-14T08:50:54+05","iso":true,"valid":true,"at":"2943748254.000000"} +{"value":"2100-01-27T06:03:33.372 +0130","iso":true,"valid":true,"at":"4104707613.372000"} +{"value":"2052-07-03T19:26:40+0245","iso":true,"valid":true,"at":"2603637700.000000"} +{"value":"2062-05-05T14:46:33z","iso":true,"valid":true,"at":"2914065993.000000"} +{"value":"2039-12-09T00:19:18-1200","iso":true,"valid":true,"at":"2207045958.000000"} +{"value":"2000-07-11","iso":true,"valid":true,"at":"963273600.000000"} +{"value":"2100-06-16 20:21:28-07:30","iso":true,"valid":true,"at":"4116887488.000000"} +{"value":"1995-12-31T07:37Z","iso":true,"valid":true,"at":"820395420.000000"} +{"value":"1981-11-07 08:14:46z","iso":true,"valid":true,"at":"373968886.000000"} +{"value":"2092-11-10 20:33:00 +1000","iso":true,"valid":true,"at":"3877151580.000000"} +{"value":"2024-07-21 07:59:42 +12","iso":true,"valid":true,"at":"1721505582.000000"} +{"value":"2078-08-10T02:60:06.220203","iso":true,"valid":false} +{"value":"2004-02-22","iso":true,"valid":true,"at":"1077408000.000000"} +{"value":"2098-05-20","iso":true,"valid":true,"at":"4051382400.000000"} +{"value":"2051-12-18T03:57","iso":true,"valid":true,"at":"2586484620.000000"} +{"value":"2091-09-19T13:55:29.83856231Z","iso":true,"valid":true,"at":"3841048529.838562"} +{"value":"1997-12-19 00:32:48+0045","iso":true,"valid":true,"at":"882488868.000000"} +{"value":"2091-11-25t03:15:49","iso":true,"valid":true,"at":"3846798949.000000"} +{"value":"2033-12-17 06:16:08.357753907Z","iso":true,"valid":true,"at":"2018412968.357753"} +{"value":"1977-04-16T08:34:37.6926 -0500","iso":true,"valid":true,"at":"230045677.692600"} +{"value":"2094-03-16","iso":true,"valid":true,"at":"3919536000.000000"} +{"value":"2045-05-07","iso":true,"valid":true,"at":"2377728000.000000"} +{"value":"2024-04-02t16:50:59.1+0500","iso":true,"valid":true,"at":"1712058659.100000"} +{"value":"1993-05-06T22:45:02+04:00","iso":true,"valid":true,"at":"736713902.000000"} +{"value":"2000-03-15t23:04:15.41Z","iso":true,"valid":true,"at":"953161455.410000"} +{"value":"2040-09-00 09:42:57.281365 -0300","iso":true,"valid":false} +{"value":"1992-03-19T19:21:08","iso":true,"valid":true,"at":"701032868.000000"} +{"value":"1992-11-32T20:50+1100","iso":true,"valid":false} +{"value":"2015-12-14t00:00:22","iso":true,"valid":true,"at":"1450051222.000000"} +{"value":"2072-10-06 21:07","iso":true,"valid":true,"at":"3243013620.000000"} +{"value":"1973-01-27","iso":true,"valid":true,"at":"96940800.000000"} +{"value":"1985-13-05T01:56:12 +07:45","iso":true,"valid":false} +{"value":"2018-11-21","iso":true,"valid":true,"at":"1542758400.000000"} +{"value":"2011-06-20 02:60:07","iso":true,"valid":false} +{"value":"2039-02-15 19:40:53z","iso":true,"valid":true,"at":"2181411653.000000"} +{"value":"2024-12-12 18:19:12","iso":true,"valid":true,"at":"1734027552.000000"} +{"value":"2031-11-14 08:19:26.8Z","iso":true,"valid":true,"at":"1952410766.800000"} +{"value":"1985-10-27T22:00:17.4951034","iso":true,"valid":true,"at":"499298417.495103"} +{"value":"2038-04-12T22:18:00","iso":true,"valid":true,"at":"2154723480.000000"} +{"value":"2027-06-18T00:13:44.3256","iso":true,"valid":true,"at":"1813277624.325600"} +{"value":"2025-05-15T22:15:37Z","iso":true,"valid":true,"at":"1747347337.000000"} +{"value":"1988-08-10T09:35+12:00","iso":true,"valid":true,"at":"587165700.000000"} +{"value":"2098-02-28 16:25:13.9939759z","iso":true,"valid":true,"at":"4044443113.993975"} +{"value":"2067-07-11","iso":true,"valid":true,"at":"3077568000.000000"} +{"value":"1994-06-27t04:23:60 -0345","iso":true,"valid":true,"at":"772704540.000000"} +{"value":"1999-04-14t15:59:44 -0200","iso":true,"valid":true,"at":"924112784.000000"} +{"value":"2037-06-30T08:60:28.4143865","iso":true,"valid":false} +{"value":"2090-03-12T23:25:01-00","iso":true,"valid":true,"at":"3793044301.000000"} +{"value":"1997-11-03T00:53:29.222917+12:00","iso":true,"valid":true,"at":"878475209.222917"} +{"value":"2029-02-26T11:14:22 +07:60","iso":true,"valid":false} +{"value":"2006-12-22","iso":true,"valid":true,"at":"1166745600.000000"} +{"value":"1971-03-02t23:58:55.291562z","iso":true,"valid":true,"at":"36806335.291562"} +{"value":"2023-07-20T22:40:14.6+04","iso":true,"valid":true,"at":"1689878414.600000"} +{"value":"2100-02-04 10:03:28.4+0400","iso":true,"valid":true,"at":"4105404208.400000"} +{"value":"2018-10-21T15:45 +10","iso":true,"valid":true,"at":"1540100700.000000"} +{"value":"2002-08-27t04:20:00 +08","iso":true,"valid":true,"at":"1030393200.000000"} +{"value":"2034-01-04","iso":true,"valid":true,"at":"2019945600.000000"} +{"value":"1999-06-13","iso":true,"valid":true,"at":"929232000.000000"} +{"value":"2073-11-24T14:30:13Z","iso":true,"valid":true,"at":"3278759413.000000"} +{"value":"2025-09-21T19:57:21z","iso":true,"valid":true,"at":"1758484641.000000"} +{"value":"2091-05-08T09:14:57","iso":true,"valid":true,"at":"3829454097.000000"} +{"value":"2014-06-22T18:00:49","iso":true,"valid":true,"at":"1403460049.000000"} +{"value":"1989-12-12","iso":true,"valid":true,"at":"629424000.000000"} +{"value":"2074-04-00T16:04+01","iso":true,"valid":false} +{"value":"1983-09-13T03:45:38z","iso":true,"valid":true,"at":"432272738.000000"} +{"value":"2004-12-14T11:52:21.86","iso":true,"valid":true,"at":"1103025141.860000"} +{"value":"2100-08-04T18:37:00-0900","iso":true,"valid":true,"at":"4121120220.000000"} +{"value":"1976-04-09T00:28:07.767146901Z","iso":true,"valid":true,"at":"197857687.767146"} +{"value":"2064-03-13","iso":true,"valid":true,"at":"2972592000.000000"} +{"value":"2009-03-00 23:00:50.48941296","iso":true,"valid":false} +{"value":"2004-11-10T00:18:00Z","iso":true,"valid":true,"at":"1100045880.000000"} +{"value":"2040-10-28t10:54-10:00","iso":true,"valid":true,"at":"2235070440.000000"} +{"value":"2093-06-04 10:17-03","iso":true,"valid":true,"at":"3894959820.000000"} +{"value":"2066-10-18T00:27:59-0530","iso":true,"valid":true,"at":"3054607079.000000"} +{"value":"1999-08-29t24:27:22Z","iso":true,"valid":true,"at":"935972842.000000"} +{"value":"2092-06-14T09:42:21.64418945","iso":true,"valid":true,"at":"3864274941.644189"} +{"value":"1980-05-16T03:04Z","iso":true,"valid":true,"at":"327294240.000000"} +{"value":"1970-10-03 11:31:20-07:30","iso":true,"valid":true,"at":"23828480.000000"} +{"value":"2083-12-28T20:33:08z","iso":true,"valid":true,"at":"3597251588.000000"} +{"value":"2001-08-16","iso":true,"valid":true,"at":"997920000.000000"} +{"value":"2100-04-20T11:21","iso":true,"valid":true,"at":"4111903260.000000"} +{"value":"1998-01-13 09:59:59.2271041-12","iso":true,"valid":true,"at":"884728799.227104"} +{"value":"2001-08-31T17:35:19z","iso":true,"valid":true,"at":"999279319.000000"} +{"value":"2010-04-15t06:49","iso":true,"valid":true,"at":"1271314140.000000"} +{"value":"2000-02-27T07:17:30-24:30","iso":true,"valid":true,"at":"951724050.000000"} +{"value":"2059-03-09 06:03-00","iso":true,"valid":true,"at":"2814415380.000000"} +{"value":"2080-04-28","iso":true,"valid":true,"at":"3481488000.000000"} +{"value":"2019-03-23 12:14:32.6379+03:00","iso":true,"valid":true,"at":"1553332472.637900"} +{"value":"2073-08-31T04:60:24Z","iso":true,"valid":false} +{"value":"2400-02-19T24:15:24+00","iso":true,"valid":true,"at":"13573786524.000000"} +{"value":"2000-02-28T16:03:07Z","iso":true,"valid":true,"at":"951753787.000000"} +{"value":"2065-01-02t19:51:55+12","iso":true,"valid":true,"at":"2998108315.000000"} +{"value":"2100-04-07T08:26:21 +01:45","iso":true,"valid":true,"at":"4110763281.000000"} +{"value":"2000-09-31","iso":true,"valid":false} +{"value":"2058-11-26T07:38:20+06","iso":true,"valid":true,"at":"2805500300.000000"} +{"value":"2054-12-18 23:30:00","iso":true,"valid":true,"at":"2681249400.000000"} +{"value":"2074-08-08t19:00:23.46","iso":true,"valid":true,"at":"3300980423.460000"} +{"value":"1979-04-22t23:34:52.8","iso":true,"valid":true,"at":"293672092.800000"} +{"value":"2085-02-30T21:21:48-04","iso":true,"valid":false} +{"value":"2017-10-27T07:07:13+00","iso":true,"valid":true,"at":"1509088033.000000"} +{"value":"2098-06-10","iso":true,"valid":true,"at":"4053196800.000000"} +{"value":"1993-09-16T10:53:45Z","iso":true,"valid":true,"at":"748176825.000000"} +{"value":"2008-06-25 03:50:14Z","iso":true,"valid":true,"at":"1214365814.000000"} +{"value":"2400-12-17T05:46 +0045","iso":true,"valid":true,"at":"13599810060.000000"} +{"value":"1983-01-27T22:25:56z","iso":true,"valid":true,"at":"412554356.000000"} +{"value":"1989-06-10","iso":true,"valid":true,"at":"613440000.000000"} +{"value":"2051-07-09T08:50:59Z","iso":true,"valid":true,"at":"2572505459.000000"} +{"value":"2100-01-03T03:19:03","iso":true,"valid":true,"at":"4102629543.000000"} +{"value":"2050-02-21 13:11","iso":true,"valid":true,"at":"2529061860.000000"} +{"value":"2037-03-25T25:26:31.39Z","iso":true,"valid":false} +{"value":"2056-01-31T19:28:30-04","iso":true,"valid":true,"at":"2716586910.000000"} +{"value":"1987-12-09 16:17z","iso":true,"valid":true,"at":"566065020.000000"} +{"value":"1996-02-01T03:00:36.7638683","iso":true,"valid":true,"at":"823143636.763868"} +{"value":"2052-12-10t06:22:18+10","iso":true,"valid":true,"at":"2617388538.000000"} +{"value":"2100-08-00T08:56:18","iso":true,"valid":false} +{"value":"1992-00-11T02:02:52Z","iso":true,"valid":false} +{"value":"2086-09-12 22:25:20","iso":true,"valid":true,"at":"3682707920.000000"} +{"value":"2043-01-20 02:44+07","iso":true,"valid":true,"at":"2305309440.000000"} +{"value":"2061-13-27 04:00:25Z","iso":true,"valid":false} +{"value":"2010-01-20","iso":true,"valid":true,"at":"1263945600.000000"} +{"value":"2400-07-26 20:47:24.638570","iso":true,"valid":true,"at":"13587425244.638570"} +{"value":"1989-05-30T14:45","iso":true,"valid":true,"at":"612542700.000000"} +{"value":"2012-11-23t15:29:05Z","iso":true,"valid":true,"at":"1353684545.000000"} +{"value":"1971-03-02","iso":true,"valid":true,"at":"36720000.000000"} +{"value":"2098-01-17 18:14:44.300628","iso":true,"valid":true,"at":"4040820884.300628"} +{"value":"2093-06-28T10:00:41Z","iso":true,"valid":true,"at":"3897021641.000000"} +{"value":"1995-12-04T08:08z","iso":true,"valid":true,"at":"818064480.000000"} +{"value":"2023-01-02T07:33:38-06:30","iso":true,"valid":true,"at":"1672668218.000000"} +{"value":"2084-06-08","iso":true,"valid":true,"at":"3611260800.000000"} +{"value":"1992-07-13 25:39:36.535 -1200","iso":true,"valid":false} +{"value":"1985-04-30t10:51:08","iso":true,"valid":true,"at":"483706268.000000"} +{"value":"1975-06-21t23:21:55","iso":true,"valid":true,"at":"172624915.000000"} +{"value":"2090-02-00t07:12:36Z","iso":true,"valid":false} +{"value":"2046-11-28","iso":true,"valid":true,"at":"2426976000.000000"} +{"value":"2030-12-20t12:15:48.10310703+0845","iso":true,"valid":true,"at":"1923967848.103107"} +{"value":"1970-11-00 10:01:22.24682","iso":true,"valid":false} +{"value":"2062-01-23T09:11:14","iso":true,"valid":true,"at":"2905233074.000000"} +{"value":"2069-12-29T11:18:36Z","iso":true,"valid":true,"at":"3155541516.000000"} +{"value":"2100-05-11T02:55:61.14642230 -1000","iso":true,"valid":false} +{"value":"2017-05-06 10:09:39Z","iso":true,"valid":true,"at":"1494065379.000000"} +{"value":"2031-06-26t02:38:30.52148","iso":true,"valid":true,"at":"1940207910.521480"} +{"value":"2048-12-31 05:09:29.983-0000","iso":true,"valid":true,"at":"2493004169.983000"} +{"value":"1994-12-22 00:01:33.126558+0200","iso":true,"valid":true,"at":"788047293.126558"} +{"value":"1975-10-16T17:60:02+06","iso":true,"valid":false} +{"value":"2075-08-17T08:59:37+01","iso":true,"valid":true,"at":"3333254377.000000"} +{"value":"1978-05-27 15:00:01","iso":true,"valid":true,"at":"265129201.000000"} +{"value":"2024-06-26","iso":true,"valid":true,"at":"1719360000.000000"} +{"value":"1975-10-00T06:37:45","iso":true,"valid":false} +{"value":"2082-01-15T00:17Z","iso":true,"valid":true,"at":"3535661820.000000"} +{"value":"1970-12-20T18:32:07.4 +03:30","iso":true,"valid":true,"at":"30553327.400000"} +{"value":"1981-03-05t14:03:17-0630","iso":true,"valid":true,"at":"352672397.000000"} +{"value":"2076-03-07 13:21:03+04:00","iso":true,"valid":true,"at":"3350798463.000000"} +{"value":"2400-03-11t00:46:60","iso":true,"valid":true,"at":"13575516420.000000"} +{"value":"2087-01-30T21:04Z","iso":true,"valid":true,"at":"3694799040.000000"} +{"value":"1995-12-26","iso":true,"valid":true,"at":"819936000.000000"} +{"value":"2100-05-21t04:38:23.418755","iso":true,"valid":true,"at":"4114557503.418755"} +{"value":"2000-04-06T17:16:20+02:45","iso":true,"valid":true,"at":"955031480.000000"} +{"value":"1994-12-28 17:25:16","iso":true,"valid":true,"at":"788635516.000000"} +{"value":"1974-11-23","iso":true,"valid":true,"at":"154396800.000000"} +{"value":"1970-12-26 20:39Z","iso":true,"valid":true,"at":"31091940.000000"} +{"value":"2400-04-16T14:40:43+06","iso":true,"valid":true,"at":"13578655243.000000"} +{"value":"2098-10-20T02:27:02Z","iso":true,"valid":true,"at":"4064610422.000000"} +{"value":"2024-07-29 01:44:20","iso":true,"valid":true,"at":"1722217460.000000"} +{"value":"2057-01-12T24:03","iso":true,"valid":true,"at":"2746569780.000000"} +{"value":"2002-02-21T14:02 -01","iso":true,"valid":true,"at":"1014303720.000000"} +{"value":"2006-03-29","iso":true,"valid":true,"at":"1143590400.000000"} +{"value":"2075-04-04t06:16:50+0560","iso":true,"valid":false} +{"value":"2015-00-16T23:02:30.6734z","iso":true,"valid":false} +{"value":"1999-09-31 00:60:57 +0630","iso":true,"valid":false} +{"value":"1970-12-06t10:50 -1245","iso":true,"valid":true,"at":"29374500.000000"} +{"value":"2075-06-32T12:46+04","iso":true,"valid":false} +{"value":"1972-09-23T22:00:54-11","iso":true,"valid":true,"at":"86173254.000000"} +{"value":"2063-08-12T23:60:04-00:30","iso":true,"valid":false} +{"value":"2026-04-31T11:37:46z","iso":true,"valid":false} +{"value":"2100-08-17T03:42:50+05","iso":true,"valid":true,"at":"4122139370.000000"} +{"value":"2024-02-06T11:51:22+0800","iso":true,"valid":true,"at":"1707191482.000000"} +{"value":"1983-05-28 08:39:28.178995060","iso":true,"valid":true,"at":"422959168.178995"} +{"value":"2064-10-32T07:43+05:00","iso":true,"valid":false} +{"value":"2047-02-17T15:50:48Z","iso":true,"valid":true,"at":"2434031448.000000"} +{"value":"2028-10-24T14:42:00.5415106","iso":true,"valid":true,"at":"1856011320.541510"} +{"value":"2044-01-10t05:59z","iso":true,"valid":true,"at":"2336018340.000000"} +{"value":"2100-09-30T23:19:52.8408","iso":true,"valid":true,"at":"4126029592.840800"} +{"value":"1999-09-02T14:50:41","iso":true,"valid":true,"at":"936283841.000000"} +{"value":"1984-01-09 18:54:30Z","iso":true,"valid":true,"at":"442522470.000000"} +{"value":"2027-11-09 06:08 -05","iso":true,"valid":true,"at":"1825758480.000000"} +{"value":"2011-12-25T00:59:06.726416-05","iso":true,"valid":true,"at":"1324792746.726416"} +{"value":"2064-11-04t12:37:31.31+07","iso":true,"valid":true,"at":"2993002651.310000"} +{"value":"2023-03-21T07:15:44z","iso":true,"valid":true,"at":"1679382944.000000"} +{"value":"2009-11-03T11:40:39","iso":true,"valid":true,"at":"1257248439.000000"} +{"value":"1994-11-14T02:60:53+12:00","iso":true,"valid":false} +{"value":"1970-08-15 05:58:55","iso":true,"valid":true,"at":"19547935.000000"} +{"value":"2083-01-15T05:23:55Z","iso":true,"valid":true,"at":"3567216235.000000"} +{"value":"2048-03-05 04:33:04.810Z","iso":true,"valid":true,"at":"2466995584.810000"} +{"value":"2049-09-16T23:33:53Z","iso":true,"valid":true,"at":"2515448033.000000"} +{"value":"2064-03-09t05:49:57 -04:00","iso":true,"valid":true,"at":"2972281797.000000"} +{"value":"1970-05-24t18:43:13+0930","iso":true,"valid":true,"at":"12388393.000000"} +{"value":"2010-01-22t01:44:23-0730","iso":true,"valid":true,"at":"1264151663.000000"} +{"value":"1973-02-20t24:41:52.4718+0000","iso":true,"valid":true,"at":"99103312.471800"} +{"value":"2092-05-11 22:12:45.5251z","iso":true,"valid":true,"at":"3861382365.525100"} +{"value":"2034-02-10T23:10-23:00","iso":true,"valid":true,"at":"2023308600.000000"} +{"value":"1999-05-02","iso":true,"valid":true,"at":"925603200.000000"} +{"value":"1986-11-28T02:46Z","iso":true,"valid":true,"at":"533529960.000000"} +{"value":"2045-07-02T22:07:14.64145147","iso":true,"valid":true,"at":"2382646034.641451"} +{"value":"1980-07-21T25:29:61+00","iso":true,"valid":false} +{"value":"1992-07-32t00:58:27-08","iso":true,"valid":false} +{"value":"2093-06-12 10:60Z","iso":true,"valid":false} +{"value":"1995-01-28T12:32:47Z","iso":true,"valid":true,"at":"791296367.000000"} +{"value":"2075-09-25T15:37:44.9336","iso":true,"valid":true,"at":"3336651464.933600"} +{"value":"2061-12-32T24:50:61","iso":true,"valid":false} +{"value":"1983-01-28","iso":true,"valid":true,"at":"412560000.000000"} +{"value":"2080-11-27T21:56:28","iso":true,"valid":true,"at":"3499970188.000000"} +{"value":"2021-07-22","iso":true,"valid":true,"at":"1626912000.000000"} +{"value":"2043-04-31","iso":true,"valid":false} +{"value":"1999-08-18T20:36:25.20613 +06:00","iso":true,"valid":true,"at":"934986985.206130"} +{"value":"2000-11-06T00:18:57z","iso":true,"valid":true,"at":"973469937.000000"} +{"value":"1999-06-17t23:45:57.8683-04:00","iso":true,"valid":true,"at":"929677557.868300"} +{"value":"2024-09-29T15:45:49","iso":true,"valid":true,"at":"1727624749.000000"} +{"value":"2056-06-29T12:50:38","iso":true,"valid":true,"at":"2729508638.000000"} +{"value":"2075-02-26T18:59:06 +03","iso":true,"valid":true,"at":"3318422346.000000"} +{"value":"2089-06-18T16:60:07","iso":true,"valid":false} +{"value":"2077-11-26","iso":true,"valid":true,"at":"3405110400.000000"} +{"value":"2025-03-28t07:14:31","iso":true,"valid":true,"at":"1743146071.000000"} +{"value":"2400-12-29t23:37:45.845783","iso":true,"valid":true,"at":"13600913865.845783"} +{"value":"2099-09-14","iso":true,"valid":true,"at":"4093027200.000000"} +{"value":"2065-06-30 06:54:55.334501140z","iso":true,"valid":true,"at":"3013570495.334501"} +{"value":"2060-03-07T18:43:14+04:30","iso":true,"valid":true,"at":"2845894394.000000"} +{"value":"2029-12-15 12:00Z","iso":true,"valid":true,"at":"1892030400.000000"} +{"value":"2026-11-25T18:41:12z","iso":true,"valid":true,"at":"1795632072.000000"} +{"value":"2006-02-15T20:19:45.795629747","iso":true,"valid":true,"at":"1140034785.795629"} +{"value":"2051-11-29T13:22:38.30858015","iso":true,"valid":true,"at":"2584876958.308580"} +{"value":"2053-10-15T01:03:55","iso":true,"valid":true,"at":"2644103035.000000"} +{"value":"2058-12-09","iso":true,"valid":true,"at":"2806617600.000000"} +{"value":"2073-06-28t15:35:41-02","iso":true,"valid":true,"at":"3265896941.000000"} +{"value":"2078-12-27t19:18:15-11","iso":true,"valid":true,"at":"3439433895.000000"} +{"value":"2023-10-28T11:43:52Z","iso":true,"valid":true,"at":"1698493432.000000"} +{"value":"2024-05-04T19:33:60.796285","iso":true,"valid":true,"at":"1714851240.796285"} +{"value":"2091-06-29T20:12:40-04","iso":true,"valid":true,"at":"3834000760.000000"} +{"value":"2084-02-04T23:00","iso":true,"valid":true,"at":"3600543600.000000"} +{"value":"1981-12-17t21:11:48+00","iso":true,"valid":true,"at":"377471508.000000"} +{"value":"1994-07-25","iso":true,"valid":true,"at":"775094400.000000"} +{"value":"2009-12-27 07:47:58+0145","iso":true,"valid":true,"at":"1261893778.000000"} +{"value":"2024-03-09","iso":true,"valid":true,"at":"1709942400.000000"} +{"value":"1999-01-19T13:16-06","iso":true,"valid":true,"at":"916773360.000000"} +{"value":"2088-06-07T13:22:34 -03:30","iso":true,"valid":true,"at":"3737465554.000000"} +{"value":"2100-09-31t16:47:60.8220790 -01","iso":true,"valid":false} +{"value":"2048-04-28 04:60:50.5362 -0300","iso":true,"valid":false} diff --git a/rust/tests/fixtures/cron/php-2.5.14-next-fire.jsonl b/rust/tests/fixtures/cron/php-2.5.14-next-fire.jsonl index 39f0c22a6..efa9e4743 100644 --- a/rust/tests/fixtures/cron/php-2.5.14-next-fire.jsonl +++ b/rust/tests/fixtures/cron/php-2.5.14-next-fire.jsonl @@ -1,600 +1,600 @@ {"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Mars/Base"},"after":"2026-02-09T09:29:21.684233Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P0D"},{"every":"P0Y2MT30H78M"}],"timezone":"America/New_York"},"after":"2028-02-07T21:46:03.192404Z","next":"2028-03-29T13:06:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 3 * * *"],"timezone":"EST"},"after":"2027-12-20T21:26:46.708009Z","next":"2027-12-20T22:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"intervals":[{"every":"P10M2W18D"}]},"after":"2028-08-23T21:03:01.395881Z","next":"2028-08-23T22:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P0D"},{"every":"P0Y2MT30H78M"}],"timezone":"America/New_York"},"after":"2028-02-07T21:46:03.192404Z","next":"2028-03-29T13:06:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","0 3 * * *"],"timezone":"EST"},"after":"2027-12-20T21:26:46.708009Z","next":"2027-12-20T22:00:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"intervals":[{"every":"P10M2W18D"}]},"after":"2028-08-23T21:03:01.395881Z","next":"2028-08-23T22:00:00.000000Z","offset":"+00:00"} {"spec":{"intervals":[{"every":"P0W"}],"timezone":""},"after":"2028-02-19T09:21:48.608503Z","next":null} -{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"timezone":"Europe/Budapest"},"after":"2028-03-16T09:24:31.179399Z","next":"2028-03-16T10:00:00.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"timezone":"Europe/Budapest"},"after":"2028-03-16T09:24:31.179399Z","next":"2028-03-16T10:00:00.000000Z","offset":"+01:00"} {"spec":{"timezone":""},"after":"2027-12-15T02:33:48.376137Z","next":null} -{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"],"intervals":[{"every":"P0Y39DT82M"},{"every":"P3WT760S"}],"timezone":"+05:30"},"after":"2027-03-17T15:25:19.081189Z","next":"2027-03-17T21:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P6M7DT44H"},{"every":"P14D"}],"timezone":"Australia/Lord_Howe"},"after":"2027-03-17T10:24:27.201519Z","next":"2027-03-25T00:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"],"intervals":[{"every":"P0Y39DT82M"},{"every":"P3WT760S"}],"timezone":"+05:30"},"after":"2027-03-17T15:25:19.081189Z","next":"2027-03-17T21:30:00.000000Z","offset":"+05:30"} +{"spec":{"intervals":[{"every":"P6M7DT44H"},{"every":"P14D"}],"timezone":"Australia/Lord_Howe"},"after":"2027-03-17T10:24:27.201519Z","next":"2027-03-25T00:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["5 4 L * ?"],"timezone":""},"after":"2028-08-03T14:15:14.715307Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P1W23DT971S"},{"every":"PT10H"}]},"after":"2025-10-07T05:41:13.166011Z","next":"2025-10-07T08:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P1W23DT971S"},{"every":"PT10H"}]},"after":"2025-10-07T05:41:13.166011Z","next":"2025-10-07T08:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","bad cron"]},"after":"2028-04-10T03:51:37.879190Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"PT16H7164S","offset":"PT45H13M"}],"timezone":"+05:30"},"after":"2028-06-03T12:05:40.359424Z","next":"2028-06-03T18:34:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *","0 0 1 * *"],"intervals":[{"every":"P3WT0H3755S","offset":"P1YT28H1386S"}],"timezone":"UTC"},"after":"2027-05-11T22:31:42.785856Z","next":"2027-05-29T17:32:11.000000Z"} +{"spec":{"intervals":[{"every":"PT16H7164S","offset":"PT45H13M"}],"timezone":"+05:30"},"after":"2028-06-03T12:05:40.359424Z","next":"2028-06-03T18:34:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *","0 0 1 * *"],"intervals":[{"every":"P3WT0H3755S","offset":"P1YT28H1386S"}],"timezone":"UTC"},"after":"2027-05-11T22:31:42.785856Z","next":"2027-05-29T17:32:11.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 3 * * *"],"timezone":"Mars/Base"},"after":"2028-12-26T08:39:30.997893Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"PT6304S"},{"every":"P0W28DT15H","offset":"P2D1W"}],"timezone":"UTC"},"after":"2028-12-11T03:32:27.175651Z","next":"2028-12-11T04:21:20.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","0 0 1 * *"],"intervals":[{"every":"PT30M1129S","offset":"PT19H"},{"every":"PT83M169S","offset":"P9MT40M2161S"}],"timezone":"UTC"},"after":"2028-08-20T12:23:20.576017Z","next":"2028-08-20T12:30:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Australia/Lord_Howe"},"after":"2027-06-23T01:12:38.155251Z","next":"2028-02-29T01:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT1121S"}],"timezone":"America/New_York"},"after":"2025-05-24T05:09:59.133868Z","next":"2025-05-24T05:17:39.000000Z"} -{"spec":{"intervals":[{"every":"PT2366S"},{"every":"P31DT6580S"}],"timezone":"Asia/Kolkata"},"after":"2026-10-01T16:20:50.446536Z","next":"2026-10-01T16:38:40.000000Z"} +{"spec":{"intervals":[{"every":"PT6304S"},{"every":"P0W28DT15H","offset":"P2D1W"}],"timezone":"UTC"},"after":"2028-12-11T03:32:27.175651Z","next":"2028-12-11T04:21:20.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","0 0 1 * *"],"intervals":[{"every":"PT30M1129S","offset":"PT19H"},{"every":"PT83M169S","offset":"P9MT40M2161S"}],"timezone":"UTC"},"after":"2028-08-20T12:23:20.576017Z","next":"2028-08-20T12:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Australia/Lord_Howe"},"after":"2027-06-23T01:12:38.155251Z","next":"2028-02-29T01:00:00.000000Z","offset":"+11:00"} +{"spec":{"intervals":[{"every":"PT1121S"}],"timezone":"America/New_York"},"after":"2025-05-24T05:09:59.133868Z","next":"2025-05-24T05:17:39.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT2366S"},{"every":"P31DT6580S"}],"timezone":"Asia/Kolkata"},"after":"2026-10-01T16:20:50.446536Z","next":"2026-10-01T16:38:40.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron",""],"timezone":"America/New_York"},"after":"2027-06-22T12:18:37.280503Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P8M1WT50H50M"}],"timezone":"Australia/Lord_Howe"},"after":"2026-04-24T07:51:17.148229Z","next":"2026-08-11T19:10:00.000000Z"} -{"spec":{"intervals":[{"every":"P7M","offset":"P2Y9DT41H"}],"timezone":"Mars/Base"},"after":"2025-11-18T20:32:25.471373Z","next":"2026-01-27T17:00:00.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P8M1WT50H50M"}],"timezone":"Australia/Lord_Howe"},"after":"2026-04-24T07:51:17.148229Z","next":"2026-08-11T19:10:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P7M","offset":"P2Y9DT41H"}],"timezone":"Mars/Base"},"after":"2025-11-18T20:32:25.471373Z","next":"2026-01-27T17:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","0 12 29 2 *"],"timezone":"+05:30"},"after":"2025-11-26T19:57:59.982784Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 9 * * 1-5"]},"after":"2026-10-18T02:53:41.643187Z","next":"2026-10-19T09:00:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5"]},"after":"2026-10-18T02:53:41.643187Z","next":"2026-10-19T09:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P5MT41M"},{"every":"P3WT1M359S"}],"timezone":"Mars/Base"},"after":"2026-12-22T10:12:08.919035Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["0 12 29 2 *","0 0 1 * *"],"intervals":[{"every":"P0YT39H1494S"}],"timezone":"Mars/Base"},"after":"2026-10-01T00:49:10.193998Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"P2Y4D"},{"every":"P2DT1921S"}],"timezone":"Australia/Lord_Howe"},"after":"2026-04-19T09:01:55.922271Z","next":"2026-04-21T02:17:29.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","30 2 * * SUN"],"intervals":[{"every":"P15DT48M"}],"timezone":"Australia/Lord_Howe"},"after":"2027-07-03T02:05:52.166470Z","next":"2027-07-03T02:15:00.000000Z"} -{"spec":{"intervals":[{"every":"P0YT24H7132S"},{"every":"P0D"}],"timezone":"Asia/Kolkata"},"after":"2027-12-18T02:17:58.192301Z","next":"2027-12-18T06:36:32.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"P2Y4D"},{"every":"P2DT1921S"}],"timezone":"Australia/Lord_Howe"},"after":"2026-04-19T09:01:55.922271Z","next":"2026-04-21T02:17:29.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","30 2 * * SUN"],"intervals":[{"every":"P15DT48M"}],"timezone":"Australia/Lord_Howe"},"after":"2027-07-03T02:05:52.166470Z","next":"2027-07-03T02:15:00.000000Z","offset":"+10:30"} +{"spec":{"intervals":[{"every":"P0YT24H7132S"},{"every":"P0D"}],"timezone":"Asia/Kolkata"},"after":"2027-12-18T02:17:58.192301Z","next":"2027-12-18T06:36:32.000000Z","offset":"+00:00"} {"spec":{"timezone":"EST"},"after":"2028-03-18T15:40:10.783988Z","next":null} {"spec":{"cron_expressions":["30 2 * * SUN","bad cron"],"intervals":[{"every":"PT303S"},{"every":"PT53M637S","offset":"P3W"}],"timezone":""},"after":"2026-12-23T13:29:09.082410Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P33D"}]},"after":"2027-07-26T07:12:48.904833Z","next":"2027-08-24T00:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P33D"}]},"after":"2027-07-26T07:12:48.904833Z","next":"2027-08-24T00:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["*/15 * * * *","bad cron"],"intervals":[{"every":"PT14H"}],"timezone":"America/New_York"},"after":"2025-02-18T14:29:12.170410Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P0WT24H"}],"timezone":"Europe/Budapest"},"after":"2028-01-20T19:03:56.187132Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"PT0S"},{"every":"P8M1W","offset":"PT10H"}],"timezone":"Asia/Kolkata"},"after":"2028-07-17T18:25:06.530828Z","next":"2028-11-01T10:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT5803S"}]},"after":"2027-05-13T01:37:32.581499Z","next":"2027-05-13T02:43:34.000000Z"} +{"spec":{"intervals":[{"every":"PT0S"},{"every":"P8M1W","offset":"PT10H"}],"timezone":"Asia/Kolkata"},"after":"2028-07-17T18:25:06.530828Z","next":"2028-11-01T10:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT5803S"}]},"after":"2027-05-13T01:37:32.581499Z","next":"2027-05-13T02:43:34.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["5 4 L * ?","bad cron"],"intervals":[{"every":"P2Y"},{"every":"P0WT45M"}],"timezone":"America/New_York"},"after":"2028-02-20T07:25:36.838272Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT2002S"}],"timezone":"EST"},"after":"2025-03-29T13:26:40.292059Z","next":"2025-03-29T13:30:00.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT2002S"}],"timezone":"EST"},"after":"2025-03-29T13:26:40.292059Z","next":"2025-03-29T13:30:00.000000Z","offset":"-05:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P1D ","offset":"PT2H"},{"every":"PT1327S","offset":"P2Y14M"}],"timezone":"Europe/Budapest"},"after":"2027-02-02T00:49:07.776196Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 3 * * *"],"intervals":[{"every":"P1WT5473S"}],"timezone":"America/New_York"},"after":"2026-07-20T04:33:34.275358Z","next":"2026-07-20T07:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"timezone":"UTC"},"after":"2025-09-02T14:36:10.957055Z","next":"2025-09-03T03:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P2WT12M6553S"},{"every":"PT6M","offset":""}],"timezone":"Australia/Lord_Howe"},"after":"2028-02-23T17:47:09.731427Z","next":"2028-02-23T17:48:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 3 * * *"],"intervals":[{"every":"P1WT5473S"}],"timezone":"America/New_York"},"after":"2026-07-20T04:33:34.275358Z","next":"2026-07-20T07:00:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"timezone":"UTC"},"after":"2025-09-02T14:36:10.957055Z","next":"2025-09-03T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2WT12M6553S"},{"every":"PT6M","offset":""}],"timezone":"Australia/Lord_Howe"},"after":"2028-02-23T17:47:09.731427Z","next":"2028-02-23T17:48:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 9 * * 1-5","0 3 * * *"],"intervals":[{"every":"P2Y"}],"timezone":""},"after":"2028-06-22T12:16:29.346585Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"Europe/Budapest"},"after":"2026-09-19T13:27:57.572792Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5","*/15 * * * *"],"intervals":[{"every":"P24DT50H89M6622S","offset":"P0Y7MT47H"}],"timezone":"+05:30"},"after":"2027-01-14T18:32:42.092624Z","next":"2027-01-14T18:45:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5","*/15 * * * *"],"intervals":[{"every":"P24DT50H89M6622S","offset":"P0Y7MT47H"}],"timezone":"+05:30"},"after":"2027-01-14T18:32:42.092624Z","next":"2027-01-14T18:45:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P1Y35D"}],"timezone":"Europe/Budapest"},"after":"2026-08-07T22:55:31.459048Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"PT3447S","offset":"P1WT14H"},{"every":"P0WT15H","offset":"P0Y10M9DT90M"}],"timezone":"Mars/Base"},"after":"2025-04-07T02:32:26.217195Z","next":"2025-04-07T03:22:12.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT639S","offset":"PT1970S"}]},"after":"2025-06-08T15:15:16.360987Z","next":"2025-06-08T15:21:44.000000Z"} +{"spec":{"intervals":[{"every":"PT3447S","offset":"P1WT14H"},{"every":"P0WT15H","offset":"P0Y10M9DT90M"}],"timezone":"Mars/Base"},"after":"2025-04-07T02:32:26.217195Z","next":"2025-04-07T03:22:12.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT639S","offset":"PT1970S"}]},"after":"2025-06-08T15:15:16.360987Z","next":"2025-06-08T15:21:44.000000Z","offset":"+00:00"} {"spec":{"timezone":"America/New_York"},"after":"2027-08-20T20:24:40.689560Z","next":null} -{"spec":{"cron_expressions":["","0 0 1 * *"],"timezone":"EST"},"after":"2025-03-24T19:19:49.674151Z","next":"2025-04-01T05:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P1MT47H29M","offset":"P0MT6771S"},{"every":"PT1319S"}],"timezone":"Australia/Lord_Howe"},"after":"2028-10-19T05:48:21.714653Z","next":"2028-10-19T06:01:36.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT71M"},{"every":"P6MT43H84M4807S"}],"timezone":"Asia/Kolkata"},"after":"2026-12-29T22:43:53.203631Z","next":"2026-12-29T22:53:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 3 * * *"],"intervals":[{"every":"P2WT5852S"}]},"after":"2026-08-31T08:28:55.219966Z","next":"2026-08-31T09:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"intervals":[{"every":"P1YT74M208S"},{"every":"PT17H","offset":"P1W2D"}],"timezone":"+05:30"},"after":"2028-05-02T05:00:31.168474Z","next":"2028-05-02T11:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P1M1W0DT5875S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-06-04T07:37:18.370045Z","next":"2025-07-07T04:40:25.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","0 3 * * *"],"intervals":[{"every":"P1W16DT28H","offset":"P1MT15H72M"},{"every":"P36D"}]},"after":"2025-04-15T15:29:32.536226Z","next":"2025-04-15T15:30:00.000000Z"} -{"spec":{"intervals":[{"every":"PT40H"},{"every":"P17DT32H52M"}]},"after":"2027-03-02T19:10:56.326103Z","next":"2027-03-03T00:00:00.000000Z"} +{"spec":{"cron_expressions":["","0 0 1 * *"],"timezone":"EST"},"after":"2025-03-24T19:19:49.674151Z","next":"2025-04-01T05:00:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"P1MT47H29M","offset":"P0MT6771S"},{"every":"PT1319S"}],"timezone":"Australia/Lord_Howe"},"after":"2028-10-19T05:48:21.714653Z","next":"2028-10-19T06:01:36.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT71M"},{"every":"P6MT43H84M4807S"}],"timezone":"Asia/Kolkata"},"after":"2026-12-29T22:43:53.203631Z","next":"2026-12-29T22:53:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 3 * * *"],"intervals":[{"every":"P2WT5852S"}]},"after":"2026-08-31T08:28:55.219966Z","next":"2026-08-31T09:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"intervals":[{"every":"P1YT74M208S"},{"every":"PT17H","offset":"P1W2D"}],"timezone":"+05:30"},"after":"2028-05-02T05:00:31.168474Z","next":"2028-05-02T11:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P1M1W0DT5875S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-06-04T07:37:18.370045Z","next":"2025-07-07T04:40:25.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","0 3 * * *"],"intervals":[{"every":"P1W16DT28H","offset":"P1MT15H72M"},{"every":"P36D"}]},"after":"2025-04-15T15:29:32.536226Z","next":"2025-04-15T15:30:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT40H"},{"every":"P17DT32H52M"}]},"after":"2027-03-02T19:10:56.326103Z","next":"2027-03-03T00:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P7M0W16DT76M7185S","offset":"P1Y0W20DT1M"},{"every":"P2D1W"}],"timezone":"UTC"},"after":"2026-07-23T10:05:53.139117Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT21H56M4886S"}],"timezone":"+05:30"},"after":"2027-01-11T09:33:13.258129Z","next":"2027-01-11T12:29:04.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P10000000000000000000D"}]},"after":"2026-09-09T23:04:56.976613Z","next":"2028-02-29T12:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P2Y39DT13H"}],"timezone":"EST"},"after":"2028-09-18T12:28:37.154784Z","next":"2028-12-29T04:00:00.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P1YT43H","offset":"PT30H"},{"every":"P2Y1W26DT52M"}],"timezone":"Europe/Budapest"},"after":"2025-04-22T19:13:38.965049Z","next":"2026-03-29T14:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P7M1W2DT31H"},{"every":"P10000000000000000000D"}],"timezone":"UTC"},"after":"2028-08-02T02:33:47.952177Z","next":"2028-08-02T09:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","30 2 * * SUN"],"intervals":[{"every":"PT290S"},{"every":"P3M"}],"timezone":"Asia/Kolkata"},"after":"2025-09-17T23:04:00.338112Z","next":"2025-09-17T23:08:40.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"PT1H"},{"every":"PT49H"}],"timezone":"Europe/Budapest"},"after":"2028-06-03T07:44:27.309552Z","next":"2028-06-03T08:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P5MT18H","offset":"P2D1W"},{"every":"P8MT41H27M"}],"timezone":"UTC"},"after":"2026-01-13T14:18:49.661599Z","next":"2026-02-18T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"timezone":"Europe/Budapest"},"after":"2027-05-11T19:42:53.913592Z","next":"2027-05-12T01:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT21H56M4886S"}],"timezone":"+05:30"},"after":"2027-01-11T09:33:13.258129Z","next":"2027-01-11T12:29:04.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P10000000000000000000D"}]},"after":"2026-09-09T23:04:56.976613Z","next":"2028-02-29T12:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2Y39DT13H"}],"timezone":"EST"},"after":"2028-09-18T12:28:37.154784Z","next":"2028-12-29T04:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P1YT43H","offset":"PT30H"},{"every":"P2Y1W26DT52M"}],"timezone":"Europe/Budapest"},"after":"2025-04-22T19:13:38.965049Z","next":"2026-03-29T14:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P7M1W2DT31H"},{"every":"P10000000000000000000D"}],"timezone":"UTC"},"after":"2028-08-02T02:33:47.952177Z","next":"2028-08-02T09:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","30 2 * * SUN"],"intervals":[{"every":"PT290S"},{"every":"P3M"}],"timezone":"Asia/Kolkata"},"after":"2025-09-17T23:04:00.338112Z","next":"2025-09-17T23:08:40.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"PT1H"},{"every":"PT49H"}],"timezone":"Europe/Budapest"},"after":"2028-06-03T07:44:27.309552Z","next":"2028-06-03T08:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P5MT18H","offset":"P2D1W"},{"every":"P8MT41H27M"}],"timezone":"UTC"},"after":"2026-01-13T14:18:49.661599Z","next":"2026-02-18T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"timezone":"Europe/Budapest"},"after":"2027-05-11T19:42:53.913592Z","next":"2027-05-12T01:00:00.000000Z","offset":"+02:00"} {"spec":[],"after":"2027-02-16T12:56:37.387766Z","next":null} -{"spec":{"intervals":[{"every":"PT47H4M6730S","offset":"P2Y11MT9H"}],"timezone":"+05:30"},"after":"2026-01-21T09:23:20.792750Z","next":"2026-01-22T18:39:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","*/15 * * * *"],"timezone":"UTC"},"after":"2028-05-14T07:53:50.895097Z","next":"2028-05-14T08:00:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P14MT2335S"}],"timezone":"Australia/Lord_Howe"},"after":"2026-01-30T11:41:13.604252Z","next":"2026-01-30T17:05:00.000000Z"} -{"spec":{"intervals":[{"every":"P1YT76M","offset":"PT79M"},{"every":"P3W"}],"timezone":"+05:30"},"after":"2028-09-25T05:36:42.848528Z","next":"2028-10-05T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":"Asia/Kolkata"},"after":"2027-02-24T21:06:47.956260Z","next":"2027-02-25T03:30:00.000000Z"} +{"spec":{"intervals":[{"every":"PT47H4M6730S","offset":"P2Y11MT9H"}],"timezone":"+05:30"},"after":"2026-01-21T09:23:20.792750Z","next":"2026-01-22T18:39:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","*/15 * * * *"],"timezone":"UTC"},"after":"2028-05-14T07:53:50.895097Z","next":"2028-05-14T08:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P14MT2335S"}],"timezone":"Australia/Lord_Howe"},"after":"2026-01-30T11:41:13.604252Z","next":"2026-01-30T17:05:00.000000Z","offset":"+11:00"} +{"spec":{"intervals":[{"every":"P1YT76M","offset":"PT79M"},{"every":"P3W"}],"timezone":"+05:30"},"after":"2028-09-25T05:36:42.848528Z","next":"2028-10-05T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":"Asia/Kolkata"},"after":"2027-02-24T21:06:47.956260Z","next":"2027-02-25T03:30:00.000000Z","offset":"+05:30"} {"spec":[],"after":"2028-04-14T03:36:28.375994Z","next":null} -{"spec":{"cron_expressions":["0 3 * * *","0 9 * * 1-5"],"intervals":[{"every":"PT6H","offset":"P6DT84M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-05-12T11:30:44.395347Z","next":"2028-05-12T13:24:00.000000Z"} -{"spec":{"intervals":[{"every":"P24D"},{"every":"P2WT4279S"}],"timezone":"UTC"},"after":"2027-12-30T23:05:47.325379Z","next":"2028-01-03T16:25:32.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P1YT43M"},{"every":"P29D"}]},"after":"2026-02-08T08:54:23.812658Z","next":"2026-02-08T09:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *","0 9 * * 1-5"],"intervals":[{"every":"PT6H","offset":"P6DT84M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-05-12T11:30:44.395347Z","next":"2028-05-12T13:24:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P24D"},{"every":"P2WT4279S"}],"timezone":"UTC"},"after":"2027-12-30T23:05:47.325379Z","next":"2028-01-03T16:25:32.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P1YT43M"},{"every":"P29D"}]},"after":"2026-02-08T08:54:23.812658Z","next":"2026-02-08T09:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT3583S"}],"timezone":""},"after":"2025-01-22T23:26:16.675758Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"Europe/Budapest"},"after":"2026-05-30T23:23:52.266131Z","next":null} -{"spec":{"cron_expressions":["*/15 * * * *"],"timezone":"EST"},"after":"2028-02-14T23:50:14.470614Z","next":"2028-02-15T00:00:00.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"],"timezone":"EST"},"after":"2028-02-14T23:50:14.470614Z","next":"2028-02-15T00:00:00.000000Z","offset":"-05:00"} {"spec":{"cron_expressions":["*/15 * * * *",""],"intervals":[{"every":"P0YT1H","offset":"P0WT8H"}],"timezone":""},"after":"2027-06-07T19:53:22.969234Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"Asia/Kolkata"},"after":"2028-05-29T03:34:56.514041Z","next":"2028-06-03T21:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"]},"after":"2027-08-15T11:40:57.096896Z","next":"2027-08-16T03:00:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"Asia/Kolkata"},"after":"2028-05-29T03:34:56.514041Z","next":"2028-06-03T21:00:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"]},"after":"2027-08-15T11:40:57.096896Z","next":"2027-08-16T03:00:00.000000Z","offset":"+00:00"} {"spec":{"timezone":""},"after":"2028-12-17T02:50:39.664623Z","next":null} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P0M0W"}],"timezone":"Australia/Lord_Howe"},"after":"2028-05-15T17:00:17.591055Z","next":"2028-05-15T17:30:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"+05:30"},"after":"2026-10-02T12:30:13.817300Z","next":"2026-10-30T22:35:00.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P0M0W"}],"timezone":"Australia/Lord_Howe"},"after":"2028-05-15T17:00:17.591055Z","next":"2028-05-15T17:30:00.000000Z","offset":"+10:30"} +{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"+05:30"},"after":"2026-10-02T12:30:13.817300Z","next":"2026-10-30T22:35:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":[""],"timezone":"Australia/Lord_Howe"},"after":"2025-10-11T11:52:59.497618Z","next":null} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P3DT72M4810S","offset":"PT26H"}]},"after":"2026-11-06T16:56:55.714163Z","next":"2026-11-08T02:30:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1W0DT2478S","offset":"PT1H1D"}],"timezone":"Australia/Lord_Howe"},"after":"2025-08-26T04:20:23.672791Z","next":"2025-08-26T16:30:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?","5 4 L * ?"],"timezone":"America/New_York"},"after":"2028-09-26T17:09:54.285672Z","next":"2028-09-30T08:05:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"PT41H"},{"every":"P2YT768S","offset":"PT74M"}]},"after":"2027-08-10T09:35:48.829688Z","next":"2027-08-11T13:00:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2026-12-18T02:37:10.737793Z","next":"2027-01-01T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT2280S"}],"timezone":"Asia/Kolkata"},"after":"2027-04-10T18:08:32.387529Z","next":"2027-04-10T18:18:00.000000Z"} -{"spec":{"intervals":[{"every":"P2YT3H1M6031S"},{"every":"PT4H5264S"}],"timezone":"Europe/Budapest"},"after":"2027-11-27T21:21:56.470736Z","next":"2027-11-27T22:50:56.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"PT24H73M"}],"timezone":"Asia/Kolkata"},"after":"2028-06-29T21:20:34.587113Z","next":"2028-06-29T22:35:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?","5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2026-11-09T12:55:56.491228Z","next":"2026-11-29T17:05:00.000000Z"} -{"spec":{"cron_expressions":["","5 4 L * ?"]},"after":"2027-03-30T00:24:20.232551Z","next":"2027-03-31T04:05:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P3DT72M4810S","offset":"PT26H"}]},"after":"2026-11-06T16:56:55.714163Z","next":"2026-11-08T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1W0DT2478S","offset":"PT1H1D"}],"timezone":"Australia/Lord_Howe"},"after":"2025-08-26T04:20:23.672791Z","next":"2025-08-26T16:30:00.000000Z","offset":"+10:30"} +{"spec":{"cron_expressions":["5 4 L * ?","5 4 L * ?"],"timezone":"America/New_York"},"after":"2028-09-26T17:09:54.285672Z","next":"2028-09-30T08:05:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"PT41H"},{"every":"P2YT768S","offset":"PT74M"}]},"after":"2027-08-10T09:35:48.829688Z","next":"2027-08-11T13:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2026-12-18T02:37:10.737793Z","next":"2027-01-01T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT2280S"}],"timezone":"Asia/Kolkata"},"after":"2027-04-10T18:08:32.387529Z","next":"2027-04-10T18:18:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2YT3H1M6031S"},{"every":"PT4H5264S"}],"timezone":"Europe/Budapest"},"after":"2027-11-27T21:21:56.470736Z","next":"2027-11-27T22:50:56.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"PT24H73M"}],"timezone":"Asia/Kolkata"},"after":"2028-06-29T21:20:34.587113Z","next":"2028-06-29T22:35:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["5 4 L * ?","5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2026-11-09T12:55:56.491228Z","next":"2026-11-29T17:05:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["","5 4 L * ?"]},"after":"2027-03-30T00:24:20.232551Z","next":"2027-03-31T04:05:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"UTC"},"after":"2028-04-08T18:25:16.244290Z","next":null} -{"spec":{"intervals":[{"every":"P0000-00-00T00:00:01"}],"timezone":""},"after":"2025-10-16T15:22:04.351586Z","next":"2025-10-16T15:22:05.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P24DT13H","offset":"PT73M"},{"every":"PT0001H","offset":"PT179S"}]},"after":"2027-12-21T07:35:16.004358Z","next":"2027-12-21T08:00:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P2Y2W"}]},"after":"2026-10-23T14:21:07.012334Z","next":"2026-10-31T04:05:00.000000Z"} -{"spec":{"intervals":[{"every":"PT2H334S"}],"timezone":"+05:30"},"after":"2027-06-07T14:07:16.241567Z","next":"2027-06-07T14:37:20.000000Z"} +{"spec":{"intervals":[{"every":"P0000-00-00T00:00:01"}],"timezone":""},"after":"2025-10-16T15:22:04.351586Z","next":"2025-10-16T15:22:05.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P24DT13H","offset":"PT73M"},{"every":"PT0001H","offset":"PT179S"}]},"after":"2027-12-21T07:35:16.004358Z","next":"2027-12-21T08:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P2Y2W"}]},"after":"2026-10-23T14:21:07.012334Z","next":"2026-10-31T04:05:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT2H334S"}],"timezone":"+05:30"},"after":"2027-06-07T14:07:16.241567Z","next":"2027-06-07T14:37:20.000000Z","offset":"+00:00"} {"spec":{"timezone":"UTC"},"after":"2025-12-18T08:15:38.145916Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5","30 2 * * SUN"],"intervals":[{"every":"P1W19D"},{"every":"P1Y2WT27H4475S"}],"timezone":"+05:30"},"after":"2026-05-31T12:48:26.420842Z","next":"2026-06-01T03:30:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5","30 2 * * SUN"],"intervals":[{"every":"P1W19D"},{"every":"P1Y2WT27H4475S"}],"timezone":"+05:30"},"after":"2026-05-31T12:48:26.420842Z","next":"2026-06-01T03:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["*/15 * * * *","bad cron"],"intervals":[{"every":"P1Y14DT16H","offset":"P7DT18H33M1276S"}],"timezone":"+05:30"},"after":"2025-07-29T21:21:24.540313Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"PT3498S"},{"every":"P1YT32M"}],"timezone":"+05:30"},"after":"2025-03-13T22:30:44.038395Z","next":"2025-03-13T22:47:36.000000Z"} +{"spec":{"intervals":[{"every":"PT3498S"},{"every":"P1YT32M"}],"timezone":"+05:30"},"after":"2025-03-13T22:30:44.038395Z","next":"2025-03-13T22:47:36.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"PT0001H"},{"every":"PT2039S"}],"timezone":"America/New_York"},"after":"2026-01-07T13:11:28.272076Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 3 * * *"]},"after":"2025-05-31T22:03:34.191444Z","next":"2025-06-01T03:00:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","0 0 1 * *"],"intervals":[{"every":"P1Y3M"},{"every":"PT3415S"}],"timezone":"UTC"},"after":"2027-09-05T14:55:07.050258Z","next":"2027-09-05T15:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT0S"},{"every":"P3M"}],"timezone":"+05:30"},"after":"2028-10-09T18:24:27.498224Z","next":"2028-11-22T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P2Y4DT773S"}],"timezone":"+05:30"},"after":"2028-01-24T08:19:31.383572Z","next":"2028-04-12T06:13:37.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"America/New_York"},"after":"2025-10-01T11:56:40.740893Z","next":"2025-10-05T06:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P2WT41H","offset":"P2Y21DT3094S"},{"every":"PT10H"}],"timezone":"Europe/Budapest"},"after":"2027-05-23T03:04:39.679839Z","next":"2027-05-23T06:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *"]},"after":"2025-05-31T22:03:34.191444Z","next":"2025-06-01T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","0 0 1 * *"],"intervals":[{"every":"P1Y3M"},{"every":"PT3415S"}],"timezone":"UTC"},"after":"2027-09-05T14:55:07.050258Z","next":"2027-09-05T15:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT0S"},{"every":"P3M"}],"timezone":"+05:30"},"after":"2028-10-09T18:24:27.498224Z","next":"2028-11-22T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2Y4DT773S"}],"timezone":"+05:30"},"after":"2028-01-24T08:19:31.383572Z","next":"2028-04-12T06:13:37.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"America/New_York"},"after":"2025-10-01T11:56:40.740893Z","next":"2025-10-05T06:30:00.000000Z","offset":"-04:00"} +{"spec":{"intervals":[{"every":"P2WT41H","offset":"P2Y21DT3094S"},{"every":"PT10H"}],"timezone":"Europe/Budapest"},"after":"2027-05-23T03:04:39.679839Z","next":"2027-05-23T06:00:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"America/New_York"},"after":"2027-10-17T15:41:49.694977Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2028-07-30T19:04:59.738919Z","next":"2028-07-31T18:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P1YT40H78M514S"},{"every":"P2M2W36D","offset":"PT27H"}],"timezone":"America/New_York"},"after":"2026-11-08T11:01:41.556930Z","next":"2026-12-04T03:00:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2028-07-30T19:04:59.738919Z","next":"2028-07-31T18:30:00.000000Z","offset":"+05:30"} +{"spec":{"intervals":[{"every":"P1YT40H78M514S"},{"every":"P2M2W36D","offset":"PT27H"}],"timezone":"America/New_York"},"after":"2026-11-08T11:01:41.556930Z","next":"2026-12-04T03:00:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"EST"},"after":"2025-06-03T22:27:12.880236Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"intervals":[{"every":"PT88M"}]},"after":"2025-08-30T11:13:44.507694Z","next":"2025-08-30T12:08:00.000000Z"} -{"spec":{"intervals":[{"every":"P1Y25DT62M2348S"}],"timezone":"Mars/Base"},"after":"2025-04-09T12:19:42.487503Z","next":"2025-07-14T15:38:56.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"intervals":[{"every":"PT88M"}]},"after":"2025-08-30T11:13:44.507694Z","next":"2025-08-30T12:08:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P1Y25DT62M2348S"}],"timezone":"Mars/Base"},"after":"2025-04-09T12:19:42.487503Z","next":"2025-07-14T15:38:56.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","bad cron"],"intervals":[{"every":"P1D ","offset":"P2M3W"}]},"after":"2027-01-02T13:47:16.080317Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly"],"timezone":"UTC"},"after":"2025-03-16T19:30:27.356624Z","next":"2025-03-16T20:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P14M2WT0M","offset":"P2WT12H"}]},"after":"2028-05-23T09:23:53.091973Z","next":"2028-05-28T02:30:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT598S"},{"every":"PT1831S"}],"timezone":"Europe/Budapest"},"after":"2027-09-21T19:11:22.110112Z","next":"2027-09-21T19:14:06.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P0YT15H43M170S"},{"every":"P0Y4M3W11DT16M"}],"timezone":"Europe/Budapest"},"after":"2027-07-20T06:58:47.675672Z","next":"2027-07-20T19:58:20.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"UTC"},"after":"2025-03-16T19:30:27.356624Z","next":"2025-03-16T20:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P14M2WT0M","offset":"P2WT12H"}]},"after":"2028-05-23T09:23:53.091973Z","next":"2028-05-28T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT598S"},{"every":"PT1831S"}],"timezone":"Europe/Budapest"},"after":"2027-09-21T19:11:22.110112Z","next":"2027-09-21T19:14:06.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P0YT15H43M170S"},{"every":"P0Y4M3W11DT16M"}],"timezone":"Europe/Budapest"},"after":"2027-07-20T06:58:47.675672Z","next":"2027-07-20T19:58:20.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","5 4 L * ?"]},"after":"2025-07-10T23:30:27.226467Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"timezone":"EST"},"after":"2028-11-09T10:57:35.176656Z","next":"2028-11-12T07:30:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"timezone":"EST"},"after":"2028-11-09T10:57:35.176656Z","next":"2028-11-12T07:30:00.000000Z","offset":"-05:00"} {"spec":{"cron_expressions":["5 4 L * ?","0 12 29 2 *"],"intervals":[{"every":"P6M"}],"timezone":"Mars/Base"},"after":"2025-03-27T03:09:00.188831Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P2YT7H68M695S"},{"every":"P35DT14H9M3784S"}],"timezone":"+05:30"},"after":"2027-06-24T21:01:28.960090Z","next":"2027-07-24T16:39:20.000000Z"} -{"spec":{"cron_expressions":["@hourly","30 2 * * SUN"],"intervals":[{"every":"PT103S"},{"every":"P9M38DT5311S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-05-28T15:37:44.387552Z","next":"2025-05-28T15:38:53.000000Z"} +{"spec":{"intervals":[{"every":"P2YT7H68M695S"},{"every":"P35DT14H9M3784S"}],"timezone":"+05:30"},"after":"2027-06-24T21:01:28.960090Z","next":"2027-07-24T16:39:20.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","30 2 * * SUN"],"intervals":[{"every":"PT103S"},{"every":"P9M38DT5311S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-05-28T15:37:44.387552Z","next":"2025-05-28T15:38:53.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","0 3 * * *"]},"after":"2026-03-17T14:15:19.440496Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 3 * * *"]},"after":"2026-04-12T21:59:46.884289Z","next":"2026-04-13T03:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *"]},"after":"2026-04-12T21:59:46.884289Z","next":"2026-04-13T03:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 12 29 2 *","bad cron"],"intervals":[{"every":"PT11M3588S"},{"every":"P20DT4H","offset":"PT4H3382S"}],"timezone":"Mars/Base"},"after":"2026-11-13T21:04:35.653360Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["*/15 * * * *"]},"after":"2026-01-04T17:21:32.077077Z","next":"2026-01-04T17:30:00.000000Z"} -{"spec":{"cron_expressions":["",""],"intervals":[{"every":"P2YT27M"},{"every":"PT1794S"}],"timezone":"America/New_York"},"after":"2027-08-29T17:43:41.476597Z","next":"2027-08-29T18:05:06.000000Z"} -{"spec":{"intervals":[{"every":"P2WT6397S"},{"every":"P2WT3548S"}]},"after":"2028-05-24T02:57:10.948932Z","next":"2028-05-24T09:03:32.000000Z"} -{"spec":{"intervals":[{"every":"PT38M"},{"every":"P1YT17H","offset":"P13MT77M6384S"}],"timezone":"UTC"},"after":"2026-06-13T19:14:32.588261Z","next":"2026-06-13T19:46:00.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"]},"after":"2026-01-04T17:21:32.077077Z","next":"2026-01-04T17:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["",""],"intervals":[{"every":"P2YT27M"},{"every":"PT1794S"}],"timezone":"America/New_York"},"after":"2027-08-29T17:43:41.476597Z","next":"2027-08-29T18:05:06.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2WT6397S"},{"every":"P2WT3548S"}]},"after":"2028-05-24T02:57:10.948932Z","next":"2028-05-24T09:03:32.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT38M"},{"every":"P1YT17H","offset":"P13MT77M6384S"}],"timezone":"UTC"},"after":"2026-06-13T19:14:32.588261Z","next":"2026-06-13T19:46:00.000000Z","offset":"+00:00"} {"spec":[],"after":"2028-09-22T15:14:26.289793Z","next":null} {"spec":{"cron_expressions":["bad cron","0 9 * * 1-5"],"timezone":"Australia/Lord_Howe"},"after":"2027-08-31T06:25:26.494049Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P1WT43H75M"}],"timezone":"EST"},"after":"2026-11-07T07:23:59.467085Z","next":"2026-11-08T03:00:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"UTC"},"after":"2026-03-16T23:16:31.228343Z","next":"2026-04-01T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT49H"},{"every":"P1M3WT3H"}],"timezone":""},"after":"2026-07-02T18:03:55.386196Z","next":"2026-07-03T04:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P1WT43H75M"}],"timezone":"EST"},"after":"2026-11-07T07:23:59.467085Z","next":"2026-11-08T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"UTC"},"after":"2026-03-16T23:16:31.228343Z","next":"2026-04-01T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT49H"},{"every":"P1M3WT3H"}],"timezone":""},"after":"2026-07-02T18:03:55.386196Z","next":"2026-07-03T04:00:00.000000Z","offset":"+00:00"} {"spec":[],"after":"2027-07-27T11:41:54.241202Z","next":null} {"spec":{"cron_expressions":[""],"timezone":"UTC"},"after":"2026-05-02T09:32:22.118361Z","next":null} {"spec":{"timezone":"UTC"},"after":"2028-07-09T22:40:59.549216Z","next":null} -{"spec":{"intervals":[{"every":"P0Y2MT2H35M","offset":"P0M1W"},{"every":"P0WT7H88M","offset":"PT1112S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-11-22T04:50:05.367146Z","next":"2025-11-22T04:54:32.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2028-12-22T04:58:51.739494Z","next":"2029-01-01T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT2364S","offset":"P2WT90M5716S"}],"timezone":"UTC"},"after":"2026-12-11T01:19:52.293340Z","next":"2026-12-11T01:35:40.000000Z"} +{"spec":{"intervals":[{"every":"P0Y2MT2H35M","offset":"P0M1W"},{"every":"P0WT7H88M","offset":"PT1112S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-11-22T04:50:05.367146Z","next":"2025-11-22T04:54:32.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2028-12-22T04:58:51.739494Z","next":"2029-01-01T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT2364S","offset":"P2WT90M5716S"}],"timezone":"UTC"},"after":"2026-12-11T01:19:52.293340Z","next":"2026-12-11T01:35:40.000000Z","offset":"+00:00"} {"spec":{"timezone":"Mars/Base"},"after":"2027-09-19T22:12:45.136293Z","next":null} {"spec":{"timezone":"America/New_York"},"after":"2026-09-18T06:39:18.367556Z","next":null} -{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"PT18H"},{"every":"PT1161S"}]},"after":"2026-12-27T07:44:22.248728Z","next":"2026-12-27T07:47:33.000000Z"} -{"spec":{"intervals":[{"every":"PT47M","offset":"PT282S"},{"every":"P2YT71M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-08-20T21:00:07.662430Z","next":"2028-08-20T21:23:42.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"PT18H"},{"every":"PT1161S"}]},"after":"2026-12-27T07:44:22.248728Z","next":"2026-12-27T07:47:33.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT47M","offset":"PT282S"},{"every":"P2YT71M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-08-20T21:00:07.662430Z","next":"2028-08-20T21:23:42.000000Z","offset":"+00:00"} {"spec":[],"after":"2025-04-07T06:51:13.358558Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *","0 9 * * 1-5"],"intervals":[{"every":"PT2820S"},{"every":"P0Y39DT61M3433S"}],"timezone":"America/New_York"},"after":"2028-12-25T20:54:46.442088Z","next":"2028-12-25T21:16:00.000000Z"} -{"spec":{"intervals":[{"every":"PT78M"}],"timezone":"UTC"},"after":"2025-03-07T09:55:20.908120Z","next":"2025-03-07T10:36:00.000000Z"} -{"spec":{"intervals":[{"every":"PT22M379S","offset":"P10MT3H"}],"timezone":"EST"},"after":"2026-10-27T12:14:05.048299Z","next":"2026-10-27T12:41:14.000000Z"} -{"spec":{"intervals":[{"every":"PT4H"}],"timezone":"Mars/Base"},"after":"2028-08-13T08:51:24.952073Z","next":"2028-08-13T12:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P1Y","offset":"P1Y10MT29H61M"},{"every":"P1Y13MT20S"}],"timezone":"+05:30"},"after":"2025-04-22T03:07:48.115154Z","next":"2025-10-15T06:01:00.000000Z"} -{"spec":{"cron_expressions":["","30 2 * * SUN"],"intervals":[{"every":"P1YT31M"}]},"after":"2026-01-14T07:37:34.963712Z","next":"2026-01-18T02:30:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *","0 9 * * 1-5"],"intervals":[{"every":"PT2820S"},{"every":"P0Y39DT61M3433S"}],"timezone":"America/New_York"},"after":"2028-12-25T20:54:46.442088Z","next":"2028-12-25T21:16:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT78M"}],"timezone":"UTC"},"after":"2025-03-07T09:55:20.908120Z","next":"2025-03-07T10:36:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT22M379S","offset":"P10MT3H"}],"timezone":"EST"},"after":"2026-10-27T12:14:05.048299Z","next":"2026-10-27T12:41:14.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT4H"}],"timezone":"Mars/Base"},"after":"2028-08-13T08:51:24.952073Z","next":"2028-08-13T12:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P1Y","offset":"P1Y10MT29H61M"},{"every":"P1Y13MT20S"}],"timezone":"+05:30"},"after":"2025-04-22T03:07:48.115154Z","next":"2025-10-15T06:01:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","30 2 * * SUN"],"intervals":[{"every":"P1YT31M"}]},"after":"2026-01-14T07:37:34.963712Z","next":"2026-01-18T02:30:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["*/15 * * * *","0 3 * * *"],"timezone":""},"after":"2026-08-19T05:26:50.430612Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"EST"},"after":"2028-04-17T06:51:07.261214Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5","5 4 L * ?"],"intervals":[{"every":"P1Y3M"}],"timezone":"America/New_York"},"after":"2028-09-14T11:33:25.873440Z","next":"2028-09-14T13:00:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P2Y","offset":"P0000-00-00T00:00:01"}]},"after":"2026-04-21T19:35:44.643125Z","next":"2026-05-01T00:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","30 2 * * SUN"],"intervals":[{"every":"P1Y3WT5820S"}],"timezone":"UTC"},"after":"2026-05-23T16:41:46.283178Z","next":"2026-05-24T02:30:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","@hourly"],"timezone":"EST"},"after":"2027-01-25T16:01:54.455971Z","next":"2027-01-25T17:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P10MT28H3388S","offset":"PT5978S"}]},"after":"2026-09-04T21:06:44.688771Z","next":"2026-11-26T06:35:50.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","30 2 * * SUN"],"intervals":[{"every":"p1d"}],"timezone":"Australia/Lord_Howe"},"after":"2027-02-13T07:05:04.672930Z","next":"2027-02-13T07:15:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P1YT49H6279S"},{"every":"PT1855S"}],"timezone":"UTC"},"after":"2027-06-05T08:26:41.707111Z","next":"2027-06-05T08:30:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5","5 4 L * ?"],"intervals":[{"every":"P1Y3M"}],"timezone":"America/New_York"},"after":"2028-09-14T11:33:25.873440Z","next":"2028-09-14T13:00:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P2Y","offset":"P0000-00-00T00:00:01"}]},"after":"2026-04-21T19:35:44.643125Z","next":"2026-05-01T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","30 2 * * SUN"],"intervals":[{"every":"P1Y3WT5820S"}],"timezone":"UTC"},"after":"2026-05-23T16:41:46.283178Z","next":"2026-05-24T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","@hourly"],"timezone":"EST"},"after":"2027-01-25T16:01:54.455971Z","next":"2027-01-25T17:00:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"P10MT28H3388S","offset":"PT5978S"}]},"after":"2026-09-04T21:06:44.688771Z","next":"2026-11-26T06:35:50.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","30 2 * * SUN"],"intervals":[{"every":"p1d"}],"timezone":"Australia/Lord_Howe"},"after":"2027-02-13T07:05:04.672930Z","next":"2027-02-13T07:15:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P1YT49H6279S"},{"every":"PT1855S"}],"timezone":"UTC"},"after":"2027-06-05T08:26:41.707111Z","next":"2027-06-05T08:30:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 0 1 * *","bad cron"],"intervals":[{"every":"P10000000000000000000D","offset":"P1Y4DT1508S"}]},"after":"2028-01-10T11:01:47.905985Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly","@hourly"],"intervals":[{"every":"P4M1D"}],"timezone":"America/New_York"},"after":"2028-08-21T00:14:45.933969Z","next":"2028-08-21T01:00:00.000000Z"} -{"spec":{"cron_expressions":["","30 2 * * SUN"],"intervals":[{"every":"PT33H"}]},"after":"2028-09-08T00:50:57.190736Z","next":"2028-09-09T06:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT1031S"},{"every":"P0Y","offset":"P8M"}],"timezone":"America/New_York"},"after":"2026-07-09T19:08:06.719351Z","next":"2026-07-09T19:20:45.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *","@hourly"],"intervals":[{"every":"PT7H"},{"every":"P2W16DT6643S"}]},"after":"2026-04-01T00:44:31.015730Z","next":"2026-04-01T01:00:00.000000Z"} +{"spec":{"cron_expressions":["@hourly","@hourly"],"intervals":[{"every":"P4M1D"}],"timezone":"America/New_York"},"after":"2028-08-21T00:14:45.933969Z","next":"2028-08-21T01:00:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":["","30 2 * * SUN"],"intervals":[{"every":"PT33H"}]},"after":"2028-09-08T00:50:57.190736Z","next":"2028-09-09T06:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT1031S"},{"every":"P0Y","offset":"P8M"}],"timezone":"America/New_York"},"after":"2026-07-09T19:08:06.719351Z","next":"2026-07-09T19:20:45.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *","@hourly"],"intervals":[{"every":"PT7H"},{"every":"P2W16DT6643S"}]},"after":"2026-04-01T00:44:31.015730Z","next":"2026-04-01T01:00:00.000000Z","offset":"+00:00"} {"spec":{"intervals":[{"every":"p1d"}],"timezone":"America/New_York"},"after":"2026-11-02T01:30:32.374592Z","next":null} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P1Y"},{"every":"PT1263S"}],"timezone":"Europe/Budapest"},"after":"2027-04-18T19:28:48.702431Z","next":"2027-04-18T19:30:00.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P1Y"},{"every":"PT1263S"}],"timezone":"Europe/Budapest"},"after":"2027-04-18T19:28:48.702431Z","next":"2027-04-18T19:30:00.000000Z","offset":"+02:00"} {"spec":{"cron_expressions":["5 4 L * ?",""],"intervals":[{"every":"P10000000000000000000D"},{"every":"P37DT26H"}],"timezone":"Mars/Base"},"after":"2026-12-05T14:34:07.107324Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["@hourly","0 9 * * 1-5"],"timezone":"+05:30"},"after":"2026-04-05T04:13:06.749465Z","next":"2026-04-05T04:30:00.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 9 * * 1-5"],"timezone":"+05:30"},"after":"2026-04-05T04:13:06.749465Z","next":"2026-04-05T04:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["0 9 * * 1-5","bad cron"],"intervals":[{"every":"P0Y38DT36M"}]},"after":"2025-02-15T06:33:06.646846Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P10DT24M"},{"every":"P1MT9H3574S","offset":"PT1285S"}],"timezone":"+05:30"},"after":"2025-02-04T10:09:02.830622Z","next":"2025-02-04T11:36:00.000000Z"} +{"spec":{"intervals":[{"every":"P10DT24M"},{"every":"P1MT9H3574S","offset":"PT1285S"}],"timezone":"+05:30"},"after":"2025-02-04T10:09:02.830622Z","next":"2025-02-04T11:36:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"America/New_York"},"after":"2028-01-30T14:28:26.867003Z","next":null} -{"spec":{"intervals":[{"every":"P0Y"},{"every":"P1W6DT24H"}],"timezone":""},"after":"2027-09-16T17:34:46.701421Z","next":"2027-09-23T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 3 * * *"],"intervals":[{"every":"PT0S"}],"timezone":"America/New_York"},"after":"2026-12-25T17:39:21.139614Z","next":"2026-12-26T08:00:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P13M10DT6H"},{"every":"PT9M"}],"timezone":"+05:30"},"after":"2027-04-26T15:02:21.996166Z","next":"2027-04-26T15:09:00.000000Z"} +{"spec":{"intervals":[{"every":"P0Y"},{"every":"P1W6DT24H"}],"timezone":""},"after":"2027-09-16T17:34:46.701421Z","next":"2027-09-23T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 3 * * *"],"intervals":[{"every":"PT0S"}],"timezone":"America/New_York"},"after":"2026-12-25T17:39:21.139614Z","next":"2026-12-26T08:00:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P13M10DT6H"},{"every":"PT9M"}],"timezone":"+05:30"},"after":"2027-04-26T15:02:21.996166Z","next":"2027-04-26T15:09:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"Australia/Lord_Howe"},"after":"2025-11-22T04:44:14.866184Z","next":null} -{"spec":{"cron_expressions":["*/15 * * * *"],"timezone":"Asia/Kolkata"},"after":"2025-11-09T06:08:16.426273Z","next":"2025-11-09T06:15:00.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"],"timezone":"Asia/Kolkata"},"after":"2025-11-09T06:08:16.426273Z","next":"2025-11-09T06:15:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["0 3 * * *"],"timezone":"Mars/Base"},"after":"2025-02-07T19:00:30.824249Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["0 3 * * *","bad cron"],"timezone":"+05:30"},"after":"2028-03-17T11:11:34.043760Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P5M","offset":"P0YT5599S"},{"every":"P2YT23H22M"}]},"after":"2026-04-16T20:11:11.548571Z","next":"2026-04-30T04:05:00.000000Z"} -{"spec":{"cron_expressions":["","@hourly"],"timezone":"Europe/Budapest"},"after":"2027-11-21T00:48:10.798476Z","next":"2027-11-21T01:00:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P5M","offset":"P0YT5599S"},{"every":"P2YT23H22M"}]},"after":"2026-04-16T20:11:11.548571Z","next":"2026-04-30T04:05:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","@hourly"],"timezone":"Europe/Budapest"},"after":"2027-11-21T00:48:10.798476Z","next":"2027-11-21T01:00:00.000000Z","offset":"+01:00"} {"spec":[],"after":"2026-05-19T13:25:34.926627Z","next":null} {"spec":[],"after":"2025-07-02T13:16:49.841335Z","next":null} -{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2025-12-15T04:52:26.906823Z","next":"2025-12-30T17:05:00.000000Z"} -{"spec":{"intervals":[{"every":"PT12H56M"}],"timezone":"Europe/Budapest"},"after":"2027-05-16T05:24:43.238155Z","next":"2027-05-16T16:40:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","@hourly"]},"after":"2027-06-20T17:01:54.547722Z","next":"2027-06-20T18:00:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2025-12-15T04:52:26.906823Z","next":"2025-12-30T17:05:00.000000Z","offset":"+11:00"} +{"spec":{"intervals":[{"every":"PT12H56M"}],"timezone":"Europe/Budapest"},"after":"2027-05-16T05:24:43.238155Z","next":"2027-05-16T16:40:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","@hourly"]},"after":"2027-06-20T17:01:54.547722Z","next":"2027-06-20T18:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["@hourly","5 4 L * ?"],"intervals":[{"every":"P0D"},{"every":"PT15H56M"}],"timezone":"Mars/Base"},"after":"2025-07-10T13:01:34.097668Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron"]},"after":"2025-11-22T02:28:47.208865Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P1DT"},{"every":"P16DT171S","offset":"PT5497S"}],"timezone":"UTC"},"after":"2025-07-07T13:59:54.754036Z","next":"2025-07-07T14:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P1YT6377S","offset":"P2Y3WT87M"},{"every":"P1WT41H","offset":"PT5967S"}],"timezone":"Asia/Kolkata"},"after":"2028-10-18T22:41:06.863948Z","next":"2028-10-26T12:39:27.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P1DT"},{"every":"P16DT171S","offset":"PT5497S"}],"timezone":"UTC"},"after":"2025-07-07T13:59:54.754036Z","next":"2025-07-07T14:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P1YT6377S","offset":"P2Y3WT87M"},{"every":"P1WT41H","offset":"PT5967S"}],"timezone":"Asia/Kolkata"},"after":"2028-10-18T22:41:06.863948Z","next":"2028-10-26T12:39:27.000000Z","offset":"+00:00"} {"spec":{"timezone":"Mars/Base"},"after":"2028-11-27T01:00:50.961735Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2025-03-23T00:58:04.286253Z","next":"2025-04-01T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *","0 0 1 * *"],"intervals":[{"every":"P0WT37H","offset":"P3MT1786S"},{"every":"PT64M","offset":"P1YT77M"}]},"after":"2027-11-10T21:22:53.385961Z","next":"2027-11-10T22:05:00.000000Z"} -{"spec":{"intervals":[{"every":"P1Y14M","offset":"PT539S"},{"every":"P19D","offset":"P3MT7M4385S"}],"timezone":"UTC"},"after":"2027-09-20T21:01:21.389915Z","next":"2027-09-24T01:20:05.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT6H33M"},{"every":"P2Y3M8D"}]},"after":"2026-09-26T07:06:40.804278Z","next":"2026-09-26T13:30:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2YT4037S"}],"timezone":"Australia/Lord_Howe"},"after":"2027-04-13T10:21:35.098325Z","next":"2027-04-13T10:30:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2025-03-23T00:58:04.286253Z","next":"2025-04-01T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *","0 0 1 * *"],"intervals":[{"every":"P0WT37H","offset":"P3MT1786S"},{"every":"PT64M","offset":"P1YT77M"}]},"after":"2027-11-10T21:22:53.385961Z","next":"2027-11-10T22:05:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P1Y14M","offset":"PT539S"},{"every":"P19D","offset":"P3MT7M4385S"}],"timezone":"UTC"},"after":"2027-09-20T21:01:21.389915Z","next":"2027-09-24T01:20:05.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT6H33M"},{"every":"P2Y3M8D"}]},"after":"2026-09-26T07:06:40.804278Z","next":"2026-09-26T13:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2YT4037S"}],"timezone":"Australia/Lord_Howe"},"after":"2027-04-13T10:21:35.098325Z","next":"2027-04-13T10:30:00.000000Z","offset":"+10:30"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"PT661S"},{"every":"PT12M"}],"timezone":"America/New_York"},"after":"2027-03-21T20:37:17.728379Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly","5 4 L * ?"],"timezone":"America/New_York"},"after":"2027-04-27T15:06:01.336689Z","next":"2027-04-27T16:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"timezone":"+05:30"},"after":"2025-06-25T10:22:04.314053Z","next":"2025-06-26T03:30:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P3MT10H"}],"timezone":"Australia/Lord_Howe"},"after":"2025-06-20T11:37:54.014879Z","next":"2025-06-21T16:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT2926S","offset":"P14M1W"},{"every":"P10MT87M"}],"timezone":""},"after":"2026-04-19T09:05:14.306835Z","next":"2026-04-19T09:13:10.000000Z"} +{"spec":{"cron_expressions":["@hourly","5 4 L * ?"],"timezone":"America/New_York"},"after":"2027-04-27T15:06:01.336689Z","next":"2027-04-27T16:00:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"timezone":"+05:30"},"after":"2025-06-25T10:22:04.314053Z","next":"2025-06-26T03:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P3MT10H"}],"timezone":"Australia/Lord_Howe"},"after":"2025-06-20T11:37:54.014879Z","next":"2025-06-21T16:00:00.000000Z","offset":"+10:30"} +{"spec":{"intervals":[{"every":"PT2926S","offset":"P14M1W"},{"every":"P10MT87M"}],"timezone":""},"after":"2026-04-19T09:05:14.306835Z","next":"2026-04-19T09:13:10.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 3 * * *"],"timezone":""},"after":"2026-12-09T20:43:35.085404Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"Australia/Lord_Howe"},"after":"2027-10-01T08:37:14.968155Z","next":null} {"spec":{"timezone":"Asia/Kolkata"},"after":"2025-05-19T15:15:09.829744Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *","0 3 * * *"],"intervals":[{"every":"P1M22DT16H"},{"every":"P2M3WT11H"}]},"after":"2027-07-25T08:39:48.059771Z","next":"2027-07-26T03:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"],"timezone":"Europe/Budapest"},"after":"2027-01-31T16:46:15.098593Z","next":"2027-01-31T23:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","30 2 * * SUN"],"intervals":[{"every":" P1D"}],"timezone":"UTC"},"after":"2025-05-30T19:45:25.730448Z","next":"2025-05-31T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 0 1 * *"],"intervals":[{"every":"PT1679S"}]},"after":"2025-04-23T08:05:42.645380Z","next":"2025-04-23T08:14:15.000000Z"} -{"spec":{"intervals":[{"every":"PT50H"},{"every":"PT2506S","offset":"P3M8D"}],"timezone":"+05:30"},"after":"2027-09-06T20:52:13.573710Z","next":"2027-09-06T21:11:44.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1Y"},{"every":"PT38M","offset":"PT20H"}],"timezone":"Australia/Lord_Howe"},"after":"2026-05-14T16:49:28.472159Z","next":"2026-05-14T16:52:00.000000Z"} -{"spec":{"cron_expressions":["","*/15 * * * *"],"timezone":"EST"},"after":"2028-06-03T10:03:41.468336Z","next":"2028-06-03T10:15:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P19DT48H"},{"every":"PT"}],"timezone":"Asia/Kolkata"},"after":"2028-11-19T04:07:50.889215Z","next":"2028-11-30T18:30:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","5 4 L * ?"],"intervals":[{"every":"P3M3W4DT1911S"},{"every":"P1YT36H5863S","offset":"P25D"}],"timezone":"Asia/Kolkata"},"after":"2026-03-15T22:48:17.312055Z","next":"2026-03-15T23:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P1Y"}]},"after":"2027-04-24T08:42:37.232804Z","next":"2027-12-18T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P1Y3WT7H72M"}],"timezone":"UTC"},"after":"2026-10-11T01:05:44.863602Z","next":"2027-02-13T10:48:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *","0 3 * * *"],"intervals":[{"every":"P1M22DT16H"},{"every":"P2M3WT11H"}]},"after":"2027-07-25T08:39:48.059771Z","next":"2027-07-26T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"],"timezone":"Europe/Budapest"},"after":"2027-01-31T16:46:15.098593Z","next":"2027-01-31T23:00:00.000000Z","offset":"+01:00"} +{"spec":{"cron_expressions":["0 3 * * *","30 2 * * SUN"],"intervals":[{"every":" P1D"}],"timezone":"UTC"},"after":"2025-05-30T19:45:25.730448Z","next":"2025-05-31T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 0 1 * *"],"intervals":[{"every":"PT1679S"}]},"after":"2025-04-23T08:05:42.645380Z","next":"2025-04-23T08:14:15.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT50H"},{"every":"PT2506S","offset":"P3M8D"}],"timezone":"+05:30"},"after":"2027-09-06T20:52:13.573710Z","next":"2027-09-06T21:11:44.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1Y"},{"every":"PT38M","offset":"PT20H"}],"timezone":"Australia/Lord_Howe"},"after":"2026-05-14T16:49:28.472159Z","next":"2026-05-14T16:52:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","*/15 * * * *"],"timezone":"EST"},"after":"2028-06-03T10:03:41.468336Z","next":"2028-06-03T10:15:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P19DT48H"},{"every":"PT"}],"timezone":"Asia/Kolkata"},"after":"2028-11-19T04:07:50.889215Z","next":"2028-11-30T18:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["*/15 * * * *","5 4 L * ?"],"intervals":[{"every":"P3M3W4DT1911S"},{"every":"P1YT36H5863S","offset":"P25D"}],"timezone":"Asia/Kolkata"},"after":"2026-03-15T22:48:17.312055Z","next":"2026-03-15T23:00:00.000000Z","offset":"+05:30"} +{"spec":{"intervals":[{"every":"P1Y"}]},"after":"2027-04-24T08:42:37.232804Z","next":"2027-12-18T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P1Y3WT7H72M"}],"timezone":"UTC"},"after":"2026-10-11T01:05:44.863602Z","next":"2027-02-13T10:48:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 0 1 * *","@hourly"],"timezone":""},"after":"2028-06-07T21:21:00.707932Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"+05:30"},"after":"2025-03-10T12:50:32.346852Z","next":null} -{"spec":{"intervals":[{"every":"P2YT36M2062S"},{"every":"PT3206S"}]},"after":"2025-07-25T04:24:27.007658Z","next":"2025-07-25T04:51:48.000000Z"} -{"spec":{"intervals":[{"every":"P0WT6970S"},{"every":"P0YT21H5M","offset":"P36D"}],"timezone":"+05:30"},"after":"2027-10-14T18:21:28.985741Z","next":"2027-10-14T18:56:30.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2WT71M3889S","offset":"P-1D"}]},"after":"2026-04-03T07:06:17.931867Z","next":"2026-04-03T08:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P2YT36M2062S"},{"every":"PT3206S"}]},"after":"2025-07-25T04:24:27.007658Z","next":"2025-07-25T04:51:48.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0WT6970S"},{"every":"P0YT21H5M","offset":"P36D"}],"timezone":"+05:30"},"after":"2027-10-14T18:21:28.985741Z","next":"2027-10-14T18:56:30.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2WT71M3889S","offset":"P-1D"}]},"after":"2026-04-03T07:06:17.931867Z","next":"2026-04-03T08:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":""},"after":"2025-09-30T19:10:26.746532Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["5 4 L * ?",""],"timezone":"Australia/Lord_Howe"},"after":"2025-04-02T10:52:02.889782Z","next":"2025-04-29T17:35:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?",""],"timezone":"Australia/Lord_Howe"},"after":"2025-04-02T10:52:02.889782Z","next":"2025-04-29T17:35:00.000000Z","offset":"+10:30"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P0000-00-00T00:00:01"}],"timezone":"+05:30"},"after":"2027-02-02T18:17:55.945007Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT26H2352S","offset":"P1Y0W29DT85M"},{"every":"PT0S"}]},"after":"2026-04-02T14:04:52.320925Z","next":"2026-04-02T14:15:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"]},"after":"2026-07-27T10:22:12.554345Z","next":"2028-02-29T12:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P0DT48H"}]},"after":"2027-01-11T23:02:03.334959Z","next":"2027-01-12T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P11MT37H74M6508S","offset":"P10M"},{"every":"PT1657S"}],"timezone":"America/New_York"},"after":"2028-08-18T10:00:15.446742Z","next":"2028-08-18T10:10:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2027-12-30T11:36:18.476223Z","next":"2028-01-02T02:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P0Y0WT14H63M"}],"timezone":"Europe/Budapest"},"after":"2026-05-20T03:38:21.495944Z","next":"2026-05-20T10:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"P2Y11MT4291S","offset":"PT784S"},{"every":"PT2567S"}]},"after":"2028-08-06T16:58:36.383785Z","next":"2028-08-06T17:15:24.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P27DT38H","offset":"P1Y5MT5515S"}]},"after":"2026-05-31T18:45:36.926881Z","next":"2026-06-05T03:31:55.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT26H2352S","offset":"P1Y0W29DT85M"},{"every":"PT0S"}]},"after":"2026-04-02T14:04:52.320925Z","next":"2026-04-02T14:15:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"]},"after":"2026-07-27T10:22:12.554345Z","next":"2028-02-29T12:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0DT48H"}]},"after":"2027-01-11T23:02:03.334959Z","next":"2027-01-12T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P11MT37H74M6508S","offset":"P10M"},{"every":"PT1657S"}],"timezone":"America/New_York"},"after":"2028-08-18T10:00:15.446742Z","next":"2028-08-18T10:10:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2027-12-30T11:36:18.476223Z","next":"2028-01-02T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0Y0WT14H63M"}],"timezone":"Europe/Budapest"},"after":"2026-05-20T03:38:21.495944Z","next":"2026-05-20T10:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"P2Y11MT4291S","offset":"PT784S"},{"every":"PT2567S"}]},"after":"2028-08-06T16:58:36.383785Z","next":"2028-08-06T17:15:24.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P27DT38H","offset":"P1Y5MT5515S"}]},"after":"2026-05-31T18:45:36.926881Z","next":"2026-06-05T03:31:55.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["@hourly","@hourly"],"intervals":[{"every":"P2WT2796S"}],"timezone":""},"after":"2028-02-14T06:16:57.010823Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["0 0 1 * *","0 3 * * *"],"intervals":[{"every":"P26DT2297S"}],"timezone":"Asia/Kolkata"},"after":"2026-09-02T15:28:45.643289Z","next":"2026-09-02T21:30:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *","0 3 * * *"],"intervals":[{"every":"P26DT2297S"}],"timezone":"Asia/Kolkata"},"after":"2026-09-02T15:28:45.643289Z","next":"2026-09-02T21:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["0 3 * * *","bad cron"],"intervals":[{"every":"PT3234S"},{"every":"PT1341S"}],"timezone":"UTC"},"after":"2027-03-04T04:36:31.463173Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P1YT85M4502S","offset":"P14DT0M"},{"every":"P3W"}],"timezone":"Mars/Base"},"after":"2025-08-14T23:31:04.261301Z","next":"2025-08-28T00:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P1YT85M4502S","offset":"P14DT0M"},{"every":"P3W"}],"timezone":"Mars/Base"},"after":"2025-08-14T23:31:04.261301Z","next":"2025-08-28T00:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P0W37DT6309S"},{"every":"P0Y15DT42H82M4932S"}],"timezone":"EST"},"after":"2026-11-12T01:57:28.816136Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P17DT42H2667S"}],"timezone":"EST"},"after":"2025-10-05T17:31:59.736568Z","next":"2025-10-16T05:48:15.000000Z"} -{"spec":{"intervals":[{"every":"PT0H85M","offset":"P1Y"},{"every":"P11M18DT0H2851S","offset":"P13MT1H75M4758S"}],"timezone":"America/New_York"},"after":"2027-01-11T23:57:46.247981Z","next":"2027-01-12T01:10:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT15M","offset":"PT68M4338S"},{"every":"PT3543S"}],"timezone":"EST"},"after":"2028-07-16T17:29:38.972844Z","next":"2028-07-16T17:35:18.000000Z"} +{"spec":{"intervals":[{"every":"P17DT42H2667S"}],"timezone":"EST"},"after":"2025-10-05T17:31:59.736568Z","next":"2025-10-16T05:48:15.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT0H85M","offset":"P1Y"},{"every":"P11M18DT0H2851S","offset":"P13MT1H75M4758S"}],"timezone":"America/New_York"},"after":"2027-01-11T23:57:46.247981Z","next":"2027-01-12T01:10:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT15M","offset":"PT68M4338S"},{"every":"PT3543S"}],"timezone":"EST"},"after":"2028-07-16T17:29:38.972844Z","next":"2028-07-16T17:35:18.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 3 * * *",""],"timezone":""},"after":"2028-03-02T22:43:27.071404Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"+05:30"},"after":"2026-05-13T08:43:50.050083Z","next":null} -{"spec":{"cron_expressions":["5 4 L * ?"]},"after":"2026-11-12T03:31:06.739811Z","next":"2026-11-30T04:05:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"]},"after":"2026-11-12T03:31:06.739811Z","next":"2026-11-30T04:05:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P0YT6610S"}],"timezone":"Mars/Base"},"after":"2028-09-22T10:00:02.582702Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["*/15 * * * *","5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2028-07-03T01:46:37.640319Z","next":"2028-07-03T02:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT1836S","offset":"PT2590S"},{"every":"P7M3W"}],"timezone":"UTC"},"after":"2026-07-15T22:08:44.987884Z","next":"2026-07-15T22:19:10.000000Z"} -{"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"P0001-00-02T00:00:00"},{"every":"P1Y4DT1813S","offset":"P0DT4573S"}],"timezone":"America/New_York"},"after":"2026-09-30T05:32:07.867223Z","next":"2026-09-30T13:00:00.000000Z"} -{"spec":{"cron_expressions":["","*/15 * * * *"],"intervals":[{"every":"P1Y11M","offset":"PT5620S"},{"every":"P22D"}],"timezone":"Europe/Budapest"},"after":"2025-11-18T23:04:30.215113Z","next":"2025-11-18T23:15:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT2773S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-02-26T15:14:15.785187Z","next":"2025-02-26T15:39:30.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"timezone":"UTC"},"after":"2025-09-08T04:30:23.984658Z","next":"2025-09-08T05:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"timezone":"Europe/Budapest"},"after":"2028-12-29T10:16:56.559580Z","next":"2028-12-31T01:30:00.000000Z"} -{"spec":{"intervals":[{"every":"PT778S"},{"every":"P1Y10M"}],"timezone":"Europe/Budapest"},"after":"2028-01-06T04:46:27.602969Z","next":"2028-01-06T04:46:50.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *","5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2028-07-03T01:46:37.640319Z","next":"2028-07-03T02:00:00.000000Z","offset":"+10:30"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT1836S","offset":"PT2590S"},{"every":"P7M3W"}],"timezone":"UTC"},"after":"2026-07-15T22:08:44.987884Z","next":"2026-07-15T22:19:10.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"P0001-00-02T00:00:00"},{"every":"P1Y4DT1813S","offset":"P0DT4573S"}],"timezone":"America/New_York"},"after":"2026-09-30T05:32:07.867223Z","next":"2026-09-30T13:00:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":["","*/15 * * * *"],"intervals":[{"every":"P1Y11M","offset":"PT5620S"},{"every":"P22D"}],"timezone":"Europe/Budapest"},"after":"2025-11-18T23:04:30.215113Z","next":"2025-11-18T23:15:00.000000Z","offset":"+01:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT2773S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-02-26T15:14:15.785187Z","next":"2025-02-26T15:39:30.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"UTC"},"after":"2025-09-08T04:30:23.984658Z","next":"2025-09-08T05:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"timezone":"Europe/Budapest"},"after":"2028-12-29T10:16:56.559580Z","next":"2028-12-31T01:30:00.000000Z","offset":"+01:00"} +{"spec":{"intervals":[{"every":"PT778S"},{"every":"P1Y10M"}],"timezone":"Europe/Budapest"},"after":"2028-01-06T04:46:27.602969Z","next":"2028-01-06T04:46:50.000000Z","offset":"+00:00"} {"spec":{"timezone":"Europe/Budapest"},"after":"2027-04-06T01:53:38.378676Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P14M"},{"every":"P18D"}],"timezone":"America/New_York"},"after":"2025-05-03T17:44:45.343398Z","next":"2025-05-05T13:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P3M3W26DT26M4938S"},{"every":"P33DT19H6247S"}],"timezone":"Europe/Budapest"},"after":"2028-11-10T21:31:20.827259Z","next":"2028-11-15T14:54:05.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P14M"},{"every":"P18D"}],"timezone":"America/New_York"},"after":"2025-05-03T17:44:45.343398Z","next":"2025-05-05T13:00:00.000000Z","offset":"-04:00"} +{"spec":{"intervals":[{"every":"P3M3W26DT26M4938S"},{"every":"P33DT19H6247S"}],"timezone":"Europe/Budapest"},"after":"2028-11-10T21:31:20.827259Z","next":"2028-11-15T14:54:05.000000Z","offset":"+00:00"} {"spec":{"intervals":[{"every":"P0D","offset":"P14MT9H5257S"}]},"after":"2028-04-24T06:52:01.134666Z","next":null} -{"spec":{"intervals":[{"every":"P0Y2WT6H"},{"every":"P2WT158S","offset":"P0D"}],"timezone":""},"after":"2028-11-13T03:30:28.021980Z","next":"2028-11-15T06:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P0Y2WT6H"},{"every":"P2WT158S","offset":"P0D"}],"timezone":""},"after":"2028-11-13T03:30:28.021980Z","next":"2028-11-15T06:00:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"+05:30"},"after":"2028-08-13T09:21:41.706576Z","next":null} -{"spec":{"cron_expressions":["@hourly"],"timezone":"Australia/Lord_Howe"},"after":"2028-04-06T19:02:35.208845Z","next":"2028-04-06T19:30:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P1Y0WT39H7137S"}],"timezone":"Europe/Budapest"},"after":"2027-05-12T06:47:55.663694Z","next":"2027-05-16T00:30:00.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"Australia/Lord_Howe"},"after":"2028-04-06T19:02:35.208845Z","next":"2028-04-06T19:30:00.000000Z","offset":"+10:30"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P1Y0WT39H7137S"}],"timezone":"Europe/Budapest"},"after":"2027-05-12T06:47:55.663694Z","next":"2027-05-16T00:30:00.000000Z","offset":"+02:00"} {"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P1WT54M"}],"timezone":"Mars/Base"},"after":"2025-06-28T11:41:26.754948Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P2Y3WT1672S"}]},"after":"2027-01-16T21:05:46.136744Z","next":"2027-07-29T13:00:16.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 3 * * *"],"timezone":"Asia/Kolkata"},"after":"2027-01-03T09:23:03.015597Z","next":"2027-01-03T21:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P6MT1376S","offset":"PT1005S"}],"timezone":"UTC"},"after":"2026-06-14T13:45:53.097101Z","next":"2026-09-05T20:14:05.000000Z"} -{"spec":{"cron_expressions":["@hourly","30 2 * * SUN"],"intervals":[{"every":"PT3184S"}],"timezone":"America/New_York"},"after":"2028-12-26T07:02:28.175818Z","next":"2028-12-26T07:54:40.000000Z"} +{"spec":{"intervals":[{"every":"P2Y3WT1672S"}]},"after":"2027-01-16T21:05:46.136744Z","next":"2027-07-29T13:00:16.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *","0 3 * * *"],"timezone":"Asia/Kolkata"},"after":"2027-01-03T09:23:03.015597Z","next":"2027-01-03T21:30:00.000000Z","offset":"+05:30"} +{"spec":{"intervals":[{"every":"P6MT1376S","offset":"PT1005S"}],"timezone":"UTC"},"after":"2026-06-14T13:45:53.097101Z","next":"2026-09-05T20:14:05.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","30 2 * * SUN"],"intervals":[{"every":"PT3184S"}],"timezone":"America/New_York"},"after":"2028-12-26T07:02:28.175818Z","next":"2028-12-26T07:54:40.000000Z","offset":"+00:00"} {"spec":{"timezone":"UTC"},"after":"2026-06-06T02:59:20.729849Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT2575S","offset":"P0WT25H255S"}]},"after":"2026-02-26T21:17:23.619421Z","next":"2026-02-26T21:21:20.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT2575S","offset":"P0WT25H255S"}]},"after":"2026-02-26T21:17:23.619421Z","next":"2026-02-26T21:21:20.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["5 4 L * ?","0 12 29 2 *"],"intervals":[{"every":"P10MT29H2643S"},{"every":"P2Y2WT52M5892S"}],"timezone":""},"after":"2026-06-23T22:07:15.509825Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["30 2 * * SUN","30 2 * * SUN"],"intervals":[{"every":"PT1.5S"}]},"after":"2027-12-11T18:11:11.447463Z","next":"2027-12-12T02:30:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN","30 2 * * SUN"],"intervals":[{"every":"PT1.5S"}]},"after":"2027-12-11T18:11:11.447463Z","next":"2027-12-12T02:30:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["30 2 * * SUN","bad cron"],"timezone":"America/New_York"},"after":"2026-08-18T11:02:42.000211Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["","0 3 * * *"]},"after":"2028-03-05T14:53:40.915003Z","next":"2028-03-06T03:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P7M2DT2760S","offset":"P2W"},{"every":"P40DT23H64M"}],"timezone":"+05:30"},"after":"2027-05-13T17:18:18.483080Z","next":"2027-05-14T10:04:00.000000Z"} -{"spec":{"cron_expressions":["","0 0 1 * *"],"intervals":[{"every":"P5M"},{"every":"PT3360S","offset":"PT"}]},"after":"2028-08-14T16:48:34.199692Z","next":"2028-08-14T16:56:00.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"PT7063S"}]},"after":"2026-06-08T13:24:51.398549Z","next":"2026-06-08T14:19:47.000000Z"} +{"spec":{"cron_expressions":["","0 3 * * *"]},"after":"2028-03-05T14:53:40.915003Z","next":"2028-03-06T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P7M2DT2760S","offset":"P2W"},{"every":"P40DT23H64M"}],"timezone":"+05:30"},"after":"2027-05-13T17:18:18.483080Z","next":"2027-05-14T10:04:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","0 0 1 * *"],"intervals":[{"every":"P5M"},{"every":"PT3360S","offset":"PT"}]},"after":"2028-08-14T16:48:34.199692Z","next":"2028-08-14T16:56:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"PT7063S"}]},"after":"2026-06-08T13:24:51.398549Z","next":"2026-06-08T14:19:47.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 9 * * 1-5","bad cron"],"intervals":[{"every":"P27DT46H79M3381S"},{"every":"P0YT12M"}],"timezone":"Europe/Budapest"},"after":"2027-05-20T04:33:25.787358Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["5 4 L * ?","*/15 * * * *"],"intervals":[{"every":"P0W25DT25M1382S","offset":"P1YT61M"}],"timezone":"EST"},"after":"2026-09-06T22:24:40.086473Z","next":"2026-09-06T22:30:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?","*/15 * * * *"],"intervals":[{"every":"P0W25DT25M1382S","offset":"P1YT61M"}],"timezone":"EST"},"after":"2026-09-06T22:24:40.086473Z","next":"2026-09-06T22:30:00.000000Z","offset":"-05:00"} {"spec":{"cron_expressions":["bad cron","30 2 * * SUN"],"intervals":[{"every":"PT20M"}],"timezone":"+05:30"},"after":"2025-02-07T12:54:37.780454Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["bad cron","0 12 29 2 *"],"intervals":[{"every":"P-1D"}],"timezone":"America/New_York"},"after":"2028-03-12T18:55:30.626285Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 3 * * *","5 4 L * ?"]},"after":"2025-09-10T03:37:15.157467Z","next":"2025-09-11T03:00:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2028-02-10T04:00:32.749257Z","next":"2028-02-28T17:05:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"P2YT37H","offset":"P0Y"}],"timezone":"Europe/Budapest"},"after":"2026-02-20T03:50:17.946148Z","next":"2026-02-20T04:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P0001-00-02T00:00:00"},{"every":"P0YT4515S","offset":"P9M3WT86M1621S"}]},"after":"2026-02-24T13:29:29.615777Z","next":"2026-02-24T14:39:46.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *","5 4 L * ?"]},"after":"2025-09-10T03:37:15.157467Z","next":"2025-09-11T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2028-02-10T04:00:32.749257Z","next":"2028-02-28T17:05:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"P2YT37H","offset":"P0Y"}],"timezone":"Europe/Budapest"},"after":"2026-02-20T03:50:17.946148Z","next":"2026-02-20T04:00:00.000000Z","offset":"+01:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P0001-00-02T00:00:00"},{"every":"P0YT4515S","offset":"P9M3WT86M1621S"}]},"after":"2026-02-24T13:29:29.615777Z","next":"2026-02-24T14:39:46.000000Z","offset":"+00:00"} {"spec":{"timezone":"Asia/Kolkata"},"after":"2028-02-12T19:40:41.573202Z","next":null} -{"spec":{"intervals":[{"every":"P4M13DT1134S"}]},"after":"2026-07-06T06:12:54.486276Z","next":"2026-10-24T01:08:24.000000Z"} +{"spec":{"intervals":[{"every":"P4M13DT1134S"}]},"after":"2026-07-06T06:12:54.486276Z","next":"2026-10-24T01:08:24.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 9 * * 1-5","0 3 * * *"],"intervals":[{"every":"P1WT4H82M4361S","offset":"PT1H0M"}],"timezone":""},"after":"2025-04-19T07:30:53.387137Z","error":"DateInvalidTimeZoneException"} {"spec":[],"after":"2027-06-08T11:08:26.880261Z","next":null} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT2017S","offset":"P29DT13M"},{"every":"P35D"}],"timezone":"+05:30"},"after":"2027-03-10T12:07:23.696530Z","next":"2027-03-10T12:29:21.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *","5 4 L * ?"],"intervals":[{"every":"P1H","offset":"P2Y1WT1762S"}],"timezone":"EST"},"after":"2025-11-23T19:13:50.968843Z","next":"2025-11-30T09:05:00.000000Z"} -{"spec":{"intervals":[{"every":"P0WT11H2M"}]},"after":"2028-12-02T09:51:05.986142Z","next":"2028-12-02T12:24:00.000000Z"} -{"spec":{"intervals":[{"every":"P3WT27H"},{"every":"P11MT31H","offset":"P1YT1015S"}],"timezone":"Europe/Budapest"},"after":"2027-02-19T20:28:44.692764Z","next":"2027-03-09T00:00:00.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT2017S","offset":"P29DT13M"},{"every":"P35D"}],"timezone":"+05:30"},"after":"2027-03-10T12:07:23.696530Z","next":"2027-03-10T12:29:21.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *","5 4 L * ?"],"intervals":[{"every":"P1H","offset":"P2Y1WT1762S"}],"timezone":"EST"},"after":"2025-11-23T19:13:50.968843Z","next":"2025-11-30T09:05:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"P0WT11H2M"}]},"after":"2028-12-02T09:51:05.986142Z","next":"2028-12-02T12:24:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P3WT27H"},{"every":"P11MT31H","offset":"P1YT1015S"}],"timezone":"Europe/Budapest"},"after":"2027-02-19T20:28:44.692764Z","next":"2027-03-09T00:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["*/15 * * * *","0 12 29 2 *"],"intervals":[{"every":"P26D","offset":"P3WT64M4072S"},{"every":"PT83M"}],"timezone":""},"after":"2026-12-23T16:27:56.727124Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P12M0W32DT43H5978S","offset":"PT6M"},{"every":"P1Y4M8DT35H24M"}]},"after":"2026-10-11T23:16:34.702546Z","next":"2026-11-10T22:48:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 0 1 * *"]},"after":"2025-11-26T12:57:50.592965Z","next":"2025-12-01T00:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P12M0W32DT43H5978S","offset":"PT6M"},{"every":"P1Y4M8DT35H24M"}]},"after":"2026-10-11T23:16:34.702546Z","next":"2026-11-10T22:48:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 0 1 * *"]},"after":"2025-11-26T12:57:50.592965Z","next":"2025-12-01T00:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P17DT33H47M"}],"timezone":"Asia/Kolkata"},"after":"2027-02-28T08:02:01.193376Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P1Y14M1W","offset":"PT4254S"},{"every":"PT60M6499S","offset":"PT3335S"}],"timezone":""},"after":"2027-12-06T10:24:22.555205Z","next":"2027-12-06T11:53:38.000000Z"} +{"spec":{"intervals":[{"every":"P1Y14M1W","offset":"PT4254S"},{"every":"PT60M6499S","offset":"PT3335S"}],"timezone":""},"after":"2027-12-06T10:24:22.555205Z","next":"2027-12-06T11:53:38.000000Z","offset":"+00:00"} {"spec":{"timezone":"+05:30"},"after":"2027-01-31T00:27:59.659286Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT2230S"},{"every":"P2Y13M","offset":"P12D"}],"timezone":"America/New_York"},"after":"2025-04-18T07:44:07.900674Z","next":"2025-04-18T08:10:50.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT2230S"},{"every":"P2Y13M","offset":"P12D"}],"timezone":"America/New_York"},"after":"2025-04-18T07:44:07.900674Z","next":"2025-04-18T08:10:50.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"timezone":"EST"},"after":"2027-08-15T03:46:49.865937Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P24DT2361S","offset":"P1W"}],"timezone":"Europe/Budapest"},"after":"2026-12-02T10:40:18.138782Z","next":"2026-12-03T15:17:45.000000Z"} +{"spec":{"intervals":[{"every":"P24DT2361S","offset":"P1W"}],"timezone":"Europe/Budapest"},"after":"2026-12-02T10:40:18.138782Z","next":"2026-12-03T15:17:45.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron",""],"intervals":[{"every":"P25DT10H36M"}],"timezone":"+05:30"},"after":"2025-05-25T17:38:44.058260Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly","0 3 * * *"],"intervals":[{"every":"P1Y","offset":"PT21H"},{"every":"PT12H"}],"timezone":"UTC"},"after":"2026-09-29T21:36:21.772996Z","next":"2026-09-29T22:00:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *",""],"timezone":"+05:30"},"after":"2025-03-14T12:15:10.893408Z","next":"2025-03-31T18:30:00.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 3 * * *"],"intervals":[{"every":"P1Y","offset":"PT21H"},{"every":"PT12H"}],"timezone":"UTC"},"after":"2026-09-29T21:36:21.772996Z","next":"2026-09-29T22:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *",""],"timezone":"+05:30"},"after":"2025-03-14T12:15:10.893408Z","next":"2025-03-31T18:30:00.000000Z","offset":"+05:30"} {"spec":{"timezone":"EST"},"after":"2026-10-30T11:31:38.151792Z","next":null} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P"},{"every":"PT1H1D"}]},"after":"2026-06-20T02:23:02.676005Z","next":"2028-02-29T12:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *",""],"intervals":[{"every":"P2Y6MT65M"}],"timezone":"UTC"},"after":"2027-01-05T19:13:26.746558Z","next":"2027-04-23T00:55:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"]},"after":"2028-05-12T16:42:40.852450Z","next":"2028-05-12T16:45:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"timezone":"America/New_York"},"after":"2026-04-12T17:13:45.002188Z","next":"2026-04-12T18:00:00.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P"},{"every":"PT1H1D"}]},"after":"2026-06-20T02:23:02.676005Z","next":"2028-02-29T12:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *",""],"intervals":[{"every":"P2Y6MT65M"}],"timezone":"UTC"},"after":"2027-01-05T19:13:26.746558Z","next":"2027-04-23T00:55:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *"]},"after":"2028-05-12T16:42:40.852450Z","next":"2028-05-12T16:45:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"America/New_York"},"after":"2026-04-12T17:13:45.002188Z","next":"2026-04-12T18:00:00.000000Z","offset":"-04:00"} {"spec":{"cron_expressions":["bad cron","0 9 * * 1-5"],"timezone":"UTC"},"after":"2026-06-22T15:01:01.549774Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["*/15 * * * *","@hourly"],"timezone":"Asia/Kolkata"},"after":"2026-10-24T17:49:42.988910Z","next":"2026-10-24T18:00:00.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P1Y14MT2564S"}]},"after":"2025-07-08T02:54:42.438598Z","next":"2025-11-18T18:31:04.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *","@hourly"],"timezone":"Asia/Kolkata"},"after":"2026-10-24T17:49:42.988910Z","next":"2026-10-24T18:00:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P1Y14MT2564S"}]},"after":"2025-07-08T02:54:42.438598Z","next":"2025-11-18T18:31:04.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"P10DT68M2844S","offset":"P2W"},{"every":"P0M3WT31H26M"}],"timezone":"Mars/Base"},"after":"2028-04-24T01:53:46.502007Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["5 4 L * ?","bad cron"],"intervals":[{"every":"PT15H"}],"timezone":"Australia/Lord_Howe"},"after":"2028-06-06T17:15:28.914994Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P2D1W"},{"every":"PT39M","offset":"P0YT15H75M"}],"timezone":""},"after":"2026-08-01T01:49:18.040844Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron","bad cron"],"intervals":[{"every":"P2Y13M0D"}],"timezone":"EST"},"after":"2025-06-02T08:18:51.515593Z","error":"InvalidArgumentException"} {"spec":{"timezone":"Europe/Budapest"},"after":"2028-10-03T19:28:42.711159Z","next":null} -{"spec":{"cron_expressions":["0 12 29 2 *",""],"timezone":"Asia/Kolkata"},"after":"2028-05-04T05:43:36.605712Z","next":"2032-02-29T06:30:00.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *",""],"timezone":"Asia/Kolkata"},"after":"2028-05-04T05:43:36.605712Z","next":"2032-02-29T06:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["bad cron","bad cron"],"intervals":[{"every":"PT82M5189S"},{"every":"PT30H"}]},"after":"2028-10-22T09:13:21.689430Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P0M3D"},{"every":"P12D"}],"timezone":"Mars/Base"},"after":"2028-10-01T17:17:24.931279Z","next":"2028-10-02T00:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","5 4 L * ?"]},"after":"2025-09-22T17:56:23.343505Z","next":"2025-09-28T02:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P0YT26H"}],"timezone":""},"after":"2028-06-05T20:53:27.828648Z","next":"2028-06-06T16:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"PT56M","offset":"P2Y7M14DT19H2813S"},{"every":"P2M2W24D","offset":"PT1942S"}]},"after":"2028-02-07T08:32:59.196619Z","next":"2028-02-07T09:00:00.000000Z"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P0M3D"},{"every":"P12D"}],"timezone":"Mars/Base"},"after":"2028-10-01T17:17:24.931279Z","next":"2028-10-02T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","5 4 L * ?"]},"after":"2025-09-22T17:56:23.343505Z","next":"2025-09-28T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0YT26H"}],"timezone":""},"after":"2028-06-05T20:53:27.828648Z","next":"2028-06-06T16:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"PT56M","offset":"P2Y7M14DT19H2813S"},{"every":"P2M2W24D","offset":"PT1942S"}]},"after":"2028-02-07T08:32:59.196619Z","next":"2028-02-07T09:00:00.000000Z","offset":"+00:00"} {"spec":[],"after":"2026-02-05T22:37:46.075230Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P17D"},{"every":"PT15H"}]},"after":"2027-08-09T00:07:53.007469Z","next":"2027-08-09T09:00:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P17D"},{"every":"PT15H"}]},"after":"2027-08-09T00:07:53.007469Z","next":"2027-08-09T09:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":""},"after":"2026-05-21T20:23:28.044173Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT76M","offset":"P1Y5DT0H"}],"timezone":"Australia/Lord_Howe"},"after":"2025-02-15T16:22:50.709285Z","next":"2025-02-15T16:44:00.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT76M","offset":"P1Y5DT0H"}],"timezone":"Australia/Lord_Howe"},"after":"2025-02-15T16:22:50.709285Z","next":"2025-02-15T16:44:00.000000Z","offset":"+00:00"} {"spec":[],"after":"2028-06-03T13:07:12.296777Z","next":null} -{"spec":{"intervals":[{"every":"P2Y0WT17H30M4320S","offset":"P4M0WT19H74M5148S"},{"every":"PT2985S"}]},"after":"2028-06-18T02:03:03.456788Z","next":"2028-06-18T02:45:00.000000Z"} +{"spec":{"intervals":[{"every":"P2Y0WT17H30M4320S","offset":"P4M0WT19H74M5148S"},{"every":"PT2985S"}]},"after":"2028-06-18T02:03:03.456788Z","next":"2028-06-18T02:45:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"UTC"},"after":"2026-11-28T09:13:17.290511Z","next":null} {"spec":[],"after":"2025-01-11T23:30:24.551344Z","next":null} -{"spec":{"cron_expressions":["0 3 * * *","0 12 29 2 *"],"intervals":[{"every":"P0YT75M","offset":"PT110S"}],"timezone":"America/New_York"},"after":"2027-12-18T22:20:00.794731Z","next":"2027-12-18T22:31:50.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *","0 12 29 2 *"],"intervals":[{"every":"P0YT75M","offset":"PT110S"}],"timezone":"America/New_York"},"after":"2027-12-18T22:20:00.794731Z","next":"2027-12-18T22:31:50.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"intervals":[{"every":"P0YT49H1983S","offset":"PT1308S"}],"timezone":"Mars/Base"},"after":"2027-03-11T14:16:51.934207Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P0M2W"},{"every":"P3W"}],"timezone":"UTC"},"after":"2025-05-24T14:20:12.350841Z","next":"2025-06-05T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"]},"after":"2027-02-09T14:55:34.314491Z","next":"2027-02-10T09:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P0M2W"},{"every":"P3W"}],"timezone":"UTC"},"after":"2025-05-24T14:20:12.350841Z","next":"2025-06-05T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"]},"after":"2027-02-09T14:55:34.314491Z","next":"2027-02-10T09:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P1YT38H5590S","offset":"P0Y0M2WT48H61M6837S"},{"every":"P39DT6564S"}],"timezone":"Europe/Budapest"},"after":"2027-03-16T19:51:12.457792Z","error":"InvalidArgumentException"} {"spec":{"timezone":"America/New_York"},"after":"2028-01-12T21:58:45.089881Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"+05:30"},"after":"2026-02-26T19:34:34.752186Z","next":"2026-02-28T18:30:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P0WT55M","offset":"p1d"}]},"after":"2028-04-03T09:24:55.424400Z","next":"2028-04-03T09:35:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","@hourly"],"intervals":[{"every":"P8M10DT1659S"}],"timezone":"Europe/Budapest"},"after":"2028-07-23T21:31:58.580462Z","next":"2028-07-23T22:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P14M31D"},{"every":"PT6161S","offset":"P4M"}],"timezone":"Mars/Base"},"after":"2028-07-16T18:20:04.017594Z","next":"2028-07-16T19:06:49.000000Z"} -{"spec":{"intervals":[{"every":"P0W38DT42H"}]},"after":"2027-08-08T08:37:58.719755Z","next":"2027-09-06T12:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT4890S"}],"timezone":"EST"},"after":"2026-09-19T21:34:57.528178Z","next":"2026-09-19T22:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P1Y6M27DT26H6878S"},{"every":"PT1917S"}],"timezone":"Mars/Base"},"after":"2025-02-11T23:04:08.836547Z","next":"2025-02-11T23:06:27.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P10DT3583S"}]},"after":"2027-02-27T15:55:16.816079Z","next":"2027-03-09T06:10:40.000000Z"} -{"spec":{"intervals":[{"every":"P13MT5H68M","offset":"P37DT10H84M"}],"timezone":"Mars/Base"},"after":"2028-09-27T01:39:35.009516Z","next":"2028-11-13T12:44:00.000000Z"} -{"spec":{"intervals":[{"every":"PT2260S"},{"every":"P2WT37H4040S"}],"timezone":"EST"},"after":"2025-03-28T00:57:04.956252Z","next":"2025-03-28T01:14:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"+05:30"},"after":"2026-02-26T19:34:34.752186Z","next":"2026-02-28T18:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P0WT55M","offset":"p1d"}]},"after":"2028-04-03T09:24:55.424400Z","next":"2028-04-03T09:35:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","@hourly"],"intervals":[{"every":"P8M10DT1659S"}],"timezone":"Europe/Budapest"},"after":"2028-07-23T21:31:58.580462Z","next":"2028-07-23T22:00:00.000000Z","offset":"+02:00"} +{"spec":{"intervals":[{"every":"P14M31D"},{"every":"PT6161S","offset":"P4M"}],"timezone":"Mars/Base"},"after":"2028-07-16T18:20:04.017594Z","next":"2028-07-16T19:06:49.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0W38DT42H"}]},"after":"2027-08-08T08:37:58.719755Z","next":"2027-09-06T12:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT4890S"}],"timezone":"EST"},"after":"2026-09-19T21:34:57.528178Z","next":"2026-09-19T22:00:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"P1Y6M27DT26H6878S"},{"every":"PT1917S"}],"timezone":"Mars/Base"},"after":"2025-02-11T23:04:08.836547Z","next":"2025-02-11T23:06:27.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P10DT3583S"}]},"after":"2027-02-27T15:55:16.816079Z","next":"2027-03-09T06:10:40.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P13MT5H68M","offset":"P37DT10H84M"}],"timezone":"Mars/Base"},"after":"2028-09-27T01:39:35.009516Z","next":"2028-11-13T12:44:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT2260S"},{"every":"P2WT37H4040S"}],"timezone":"EST"},"after":"2025-03-28T00:57:04.956252Z","next":"2025-03-28T01:14:00.000000Z","offset":"+00:00"} {"spec":[],"after":"2026-02-14T12:12:29.042953Z","next":null} -{"spec":{"intervals":[{"every":"P2Y9M3WT68M","offset":"P2Y0WT34H"}]},"after":"2028-08-28T21:49:45.649810Z","next":"2030-09-16T09:48:00.000000Z"} +{"spec":{"intervals":[{"every":"P2Y9M3WT68M","offset":"P2Y0WT34H"}]},"after":"2028-08-28T21:49:45.649810Z","next":"2030-09-16T09:48:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P","offset":"P0Y20DT28M"}],"timezone":"Mars/Base"},"after":"2027-07-14T09:25:37.801341Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P0Y1W28DT1902S"},{"every":"PT25M"}],"timezone":"UTC"},"after":"2027-02-03T12:12:10.354387Z","next":"2027-02-03T12:25:00.000000Z"} -{"spec":{"intervals":[{"every":"P2YT2H"}]},"after":"2025-07-22T05:55:58.202946Z","next":"2025-12-20T08:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT4M","offset":"P14M21DT43H16M"}]},"after":"2025-10-26T02:49:29.367377Z","next":"2025-10-26T02:52:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P3W26DT27H58M4430S"},{"every":"PT48M"}],"timezone":"America/New_York"},"after":"2026-01-24T17:03:38.342263Z","next":"2026-01-24T17:36:00.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P0Y1W28DT1902S"},{"every":"PT25M"}],"timezone":"UTC"},"after":"2027-02-03T12:12:10.354387Z","next":"2027-02-03T12:25:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2YT2H"}]},"after":"2025-07-22T05:55:58.202946Z","next":"2025-12-20T08:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT4M","offset":"P14M21DT43H16M"}]},"after":"2025-10-26T02:49:29.367377Z","next":"2025-10-26T02:52:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P3W26DT27H58M4430S"},{"every":"PT48M"}],"timezone":"America/New_York"},"after":"2026-01-24T17:03:38.342263Z","next":"2026-01-24T17:36:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT2318S","offset":"P7M32D"},{"every":"PT1.5S","offset":"P0Y1W10DT2779S"}],"timezone":"Mars/Base"},"after":"2025-04-15T23:54:54.775905Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["@hourly","30 2 * * SUN"],"intervals":[{"every":"P","offset":"P2Y1WT46H"},{"every":"PT90M","offset":"P7M0WT90M"}],"timezone":"Asia/Kolkata"},"after":"2025-07-07T09:21:30.832055Z","next":"2025-07-07T09:30:00.000000Z"} +{"spec":{"cron_expressions":["@hourly","30 2 * * SUN"],"intervals":[{"every":"P","offset":"P2Y1WT46H"},{"every":"PT90M","offset":"P7M0WT90M"}],"timezone":"Asia/Kolkata"},"after":"2025-07-07T09:21:30.832055Z","next":"2025-07-07T09:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT35H","offset":"P3W"},{"every":"P3M","offset":"P0W"}],"timezone":""},"after":"2025-08-05T13:39:47.480038Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P2Y"}],"timezone":"Australia/Lord_Howe"},"after":"2027-01-19T17:26:57.856138Z","next":"2027-01-20T16:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P1MT25H"},{"every":"P0WT3252S"}],"timezone":"UTC"},"after":"2027-01-15T01:57:28.837817Z","next":"2027-01-15T02:05:48.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"intervals":[{"every":"P4MT2283S","offset":"P2YT8H32M"}],"timezone":"America/New_York"},"after":"2028-01-30T06:33:10.210035Z","next":"2028-01-30T07:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P2Y"}],"timezone":"Australia/Lord_Howe"},"after":"2027-01-19T17:26:57.856138Z","next":"2027-01-20T16:00:00.000000Z","offset":"+11:00"} +{"spec":{"intervals":[{"every":"P1MT25H"},{"every":"P0WT3252S"}],"timezone":"UTC"},"after":"2027-01-15T01:57:28.837817Z","next":"2027-01-15T02:05:48.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"intervals":[{"every":"P4MT2283S","offset":"P2YT8H32M"}],"timezone":"America/New_York"},"after":"2028-01-30T06:33:10.210035Z","next":"2028-01-30T07:00:00.000000Z","offset":"-05:00"} {"spec":{"timezone":""},"after":"2028-04-05T20:15:02.057570Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P3W","offset":"P24DT17H6657S"}],"timezone":"Australia/Lord_Howe"},"after":"2028-09-04T09:04:05.323208Z","next":"2028-09-04T22:30:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P3W","offset":"P24DT17H6657S"}],"timezone":"Australia/Lord_Howe"},"after":"2028-09-04T09:04:05.323208Z","next":"2028-09-04T22:30:00.000000Z","offset":"+10:30"} {"spec":{"cron_expressions":["5 4 L * ?"],"timezone":""},"after":"2028-05-18T20:36:07.157216Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron","0 3 * * *"],"intervals":[{"every":"PT23H"},{"every":"PT19H21M","offset":"P0YT6735S"}]},"after":"2026-08-22T21:38:46.402801Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 3 * * *"],"intervals":[{"every":"P0W","offset":"P9MT87M"}],"timezone":"UTC"},"after":"2025-12-30T19:59:28.748808Z","next":"2025-12-31T03:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 9 * * 1-5"],"intervals":[{"every":"P0W14DT32M"}],"timezone":"Europe/Budapest"},"after":"2026-07-21T16:47:19.415310Z","next":"2026-07-22T01:00:00.000000Z"} -{"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"P01D"}],"timezone":"EST"},"after":"2025-08-23T18:42:19.820471Z","next":"2025-08-24T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT290S"}],"timezone":""},"after":"2028-02-01T17:24:09.518820Z","next":"2028-02-01T17:24:30.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2025-09-18T22:19:52.766568Z","next":"2025-09-30T18:30:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *",""],"intervals":[{"every":"P1DT","offset":"P21D"}],"timezone":"+05:30"},"after":"2025-06-19T02:11:28.883773Z","next":"2025-06-30T18:30:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 3 * * *"],"intervals":[{"every":"P0W","offset":"P9MT87M"}],"timezone":"UTC"},"after":"2025-12-30T19:59:28.748808Z","next":"2025-12-31T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *","0 9 * * 1-5"],"intervals":[{"every":"P0W14DT32M"}],"timezone":"Europe/Budapest"},"after":"2026-07-21T16:47:19.415310Z","next":"2026-07-22T01:00:00.000000Z","offset":"+02:00"} +{"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"P01D"}],"timezone":"EST"},"after":"2025-08-23T18:42:19.820471Z","next":"2025-08-24T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT290S"}],"timezone":""},"after":"2028-02-01T17:24:09.518820Z","next":"2028-02-01T17:24:30.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2025-09-18T22:19:52.766568Z","next":"2025-09-30T18:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["0 0 1 * *",""],"intervals":[{"every":"P1DT","offset":"P21D"}],"timezone":"+05:30"},"after":"2025-06-19T02:11:28.883773Z","next":"2025-06-30T18:30:00.000000Z","offset":"+05:30"} {"spec":{"timezone":"Europe/Budapest"},"after":"2025-05-04T20:18:25.525518Z","next":null} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P2W37DT73M"},{"every":"PT280S"}]},"after":"2028-12-30T22:37:18.978187Z","next":"2028-12-30T22:37:20.000000Z"} -{"spec":{"intervals":[{"every":"P7M"},{"every":"P7MT1H78M","offset":"PT60M"}],"timezone":"Australia/Lord_Howe"},"after":"2025-06-25T10:58:24.572656Z","next":"2025-10-09T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","*/15 * * * *"],"intervals":[{"every":"PT710S"}]},"after":"2026-10-27T21:23:11.704232Z","next":"2026-10-27T21:24:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P2W37DT73M"},{"every":"PT280S"}]},"after":"2028-12-30T22:37:18.978187Z","next":"2028-12-30T22:37:20.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P7M"},{"every":"P7MT1H78M","offset":"PT60M"}],"timezone":"Australia/Lord_Howe"},"after":"2025-06-25T10:58:24.572656Z","next":"2025-10-09T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","*/15 * * * *"],"intervals":[{"every":"PT710S"}]},"after":"2026-10-27T21:23:11.704232Z","next":"2026-10-27T21:24:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"Asia/Kolkata"},"after":"2025-12-19T15:46:08.887758Z","next":null} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P4M","offset":"PT49H3849S"}],"timezone":"UTC"},"after":"2026-08-05T09:36:56.132476Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT681S","offset":"PT32H218S"},{"every":"P0M0W"}],"timezone":"Europe/Budapest"},"after":"2025-06-13T15:21:48.473463Z","next":"2025-06-13T15:27:47.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?","0 12 29 2 *"],"timezone":"Asia/Kolkata"},"after":"2028-12-03T19:27:24.708727Z","next":"2028-12-30T22:35:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT13H"},{"every":" P1D"}],"timezone":"America/New_York"},"after":"2025-08-21T14:23:33.418404Z","next":"2025-08-21T17:00:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT681S","offset":"PT32H218S"},{"every":"P0M0W"}],"timezone":"Europe/Budapest"},"after":"2025-06-13T15:21:48.473463Z","next":"2025-06-13T15:27:47.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?","0 12 29 2 *"],"timezone":"Asia/Kolkata"},"after":"2028-12-03T19:27:24.708727Z","next":"2028-12-30T22:35:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT13H"},{"every":" P1D"}],"timezone":"America/New_York"},"after":"2025-08-21T14:23:33.418404Z","next":"2025-08-21T17:00:00.000000Z","offset":"+00:00"} {"spec":{"intervals":[{"every":"PT1H1D"}],"timezone":"Australia/Lord_Howe"},"after":"2026-06-03T10:27:06.424615Z","next":null} {"spec":{"timezone":"America/New_York"},"after":"2028-09-06T22:50:35.297934Z","next":null} -{"spec":{"intervals":[{"every":"P20DT42H64M367S","offset":"P37DT177S"},{"every":"PT16M6580S"}],"timezone":"America/New_York"},"after":"2026-04-06T19:14:26.598740Z","next":"2026-04-06T19:35:20.000000Z"} +{"spec":{"intervals":[{"every":"P20DT42H64M367S","offset":"P37DT177S"},{"every":"PT16M6580S"}],"timezone":"America/New_York"},"after":"2026-04-06T19:14:26.598740Z","next":"2026-04-06T19:35:20.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["*/15 * * * *","0 12 29 2 *"],"intervals":[{"every":"P32D","offset":"P1D "},{"every":"P0Y26DT7M"}],"timezone":""},"after":"2026-07-15T22:21:09.814577Z","error":"DateInvalidTimeZoneException"} {"spec":[],"after":"2027-06-27T18:49:22.862856Z","next":null} -{"spec":{"cron_expressions":["30 2 * * SUN","*/15 * * * *"],"timezone":"Australia/Lord_Howe"},"after":"2025-11-30T14:58:32.313439Z","next":"2025-11-30T15:00:00.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P1YT5918S"},{"every":"PT38H33M","offset":"P34D"}],"timezone":"+05:30"},"after":"2028-04-11T08:44:33.544721Z","next":"2028-04-12T07:03:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","*/15 * * * *"],"intervals":[{"every":"PT3795S"},{"every":"P0W33DT41H","offset":"PT473S"}],"timezone":"EST"},"after":"2027-02-28T21:52:28.665375Z","next":"2027-02-28T22:00:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN","*/15 * * * *"],"timezone":"Australia/Lord_Howe"},"after":"2025-11-30T14:58:32.313439Z","next":"2025-11-30T15:00:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P1YT5918S"},{"every":"PT38H33M","offset":"P34D"}],"timezone":"+05:30"},"after":"2028-04-11T08:44:33.544721Z","next":"2028-04-12T07:03:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","*/15 * * * *"],"intervals":[{"every":"PT3795S"},{"every":"P0W33DT41H","offset":"PT473S"}],"timezone":"EST"},"after":"2027-02-28T21:52:28.665375Z","next":"2027-02-28T22:00:00.000000Z","offset":"-05:00"} {"spec":{"cron_expressions":["0 12 29 2 *","0 0 1 * *"],"intervals":[{"every":"P6D","offset":"PT1702S"},{"every":"PT9H"}],"timezone":"Mars/Base"},"after":"2027-05-29T13:03:58.913042Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P39DT858S"}]},"after":"2028-11-07T02:09:20.460706Z","next":"2028-12-15T11:33:36.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P39DT858S"}]},"after":"2028-11-07T02:09:20.460706Z","next":"2028-12-15T11:33:36.000000Z","offset":"+00:00"} {"spec":{"timezone":"UTC"},"after":"2028-04-30T05:30:51.590818Z","next":null} {"spec":{"intervals":[{"every":"P10000000000000000000D","offset":"P32DT30H5494S"}],"timezone":"+05:30"},"after":"2025-08-27T10:46:27.602244Z","next":null} {"spec":{"timezone":"+05:30"},"after":"2027-05-13T07:09:58.083532Z","next":null} {"spec":{"cron_expressions":[""],"timezone":"UTC"},"after":"2025-11-04T22:27:47.081161Z","next":null} -{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2028-03-21T00:06:50.016769Z","next":"2028-03-30T17:05:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P1WT1585S","offset":"P14MT35H6058S"},{"every":"P3WT87M"}],"timezone":"Europe/Budapest"},"after":"2025-12-18T00:23:47.684916Z","next":"2025-12-21T01:30:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT4179S"},{"every":"P0Y"}],"timezone":"UTC"},"after":"2026-01-26T15:36:49.126614Z","next":"2026-01-26T15:55:27.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"Australia/Lord_Howe"},"after":"2028-03-21T00:06:50.016769Z","next":"2028-03-30T17:05:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P1WT1585S","offset":"P14MT35H6058S"},{"every":"P3WT87M"}],"timezone":"Europe/Budapest"},"after":"2025-12-18T00:23:47.684916Z","next":"2025-12-21T01:30:00.000000Z","offset":"+01:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT4179S"},{"every":"P0Y"}],"timezone":"UTC"},"after":"2026-01-26T15:36:49.126614Z","next":"2026-01-26T15:55:27.000000Z","offset":"+00:00"} {"spec":{"timezone":"Mars/Base"},"after":"2025-09-16T08:19:19.226970Z","next":null} -{"spec":{"cron_expressions":["0 0 1 * *","0 9 * * 1-5"],"intervals":[{"every":"P0Y","offset":"P2Y"},{"every":"PT61M4517S","offset":"P2WT6816S"}],"timezone":"Europe/Budapest"},"after":"2026-05-29T12:30:50.939478Z","next":"2026-05-29T14:38:47.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *","0 9 * * 1-5"],"intervals":[{"every":"P0Y","offset":"P2Y"},{"every":"PT61M4517S","offset":"P2WT6816S"}],"timezone":"Europe/Budapest"},"after":"2026-05-29T12:30:50.939478Z","next":"2026-05-29T14:38:47.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","bad cron"],"intervals":[{"every":"P39DT6H384S"},{"every":"P20DT27H"}],"timezone":"Mars/Base"},"after":"2025-03-07T00:30:21.003180Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["5 4 L * ?","0 3 * * *"],"timezone":"UTC"},"after":"2026-08-22T00:55:33.193573Z","next":"2026-08-22T03:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 9 * * 1-5"],"timezone":"Asia/Kolkata"},"after":"2025-08-16T10:36:51.323995Z","next":"2025-08-18T03:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P7M","offset":"P1D "},{"every":"P1M1WT1902S"}],"timezone":"America/New_York"},"after":"2027-04-19T10:36:54.086094Z","next":"2027-05-16T11:02:12.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"EST"},"after":"2028-01-15T02:44:37.614243Z","next":"2028-01-31T09:05:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"Europe/Budapest"},"after":"2026-07-02T09:38:41.561526Z","next":"2026-07-05T00:30:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?","0 3 * * *"],"timezone":"UTC"},"after":"2026-08-22T00:55:33.193573Z","next":"2026-08-22T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 9 * * 1-5"],"timezone":"Asia/Kolkata"},"after":"2025-08-16T10:36:51.323995Z","next":"2025-08-18T03:30:00.000000Z","offset":"+05:30"} +{"spec":{"intervals":[{"every":"P7M","offset":"P1D "},{"every":"P1M1WT1902S"}],"timezone":"America/New_York"},"after":"2027-04-19T10:36:54.086094Z","next":"2027-05-16T11:02:12.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?"],"timezone":"EST"},"after":"2028-01-15T02:44:37.614243Z","next":"2028-01-31T09:05:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"Europe/Budapest"},"after":"2026-07-02T09:38:41.561526Z","next":"2026-07-05T00:30:00.000000Z","offset":"+02:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P9MT507S"}],"timezone":""},"after":"2025-05-07T07:12:52.164454Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"PT47H5235S"}],"timezone":"EST"},"after":"2025-04-25T00:11:32.296346Z","next":"2025-04-25T08:50:45.000000Z"} -{"spec":{"cron_expressions":["","@hourly"],"intervals":[{"every":"P0001-00-02T00:00:00"}]},"after":"2027-03-01T16:20:10.099185Z","next":"2027-03-01T17:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 9 * * 1-5"],"intervals":[{"every":"P1Y"},{"every":"PT15H3056S","offset":"P"}]},"after":"2028-06-05T07:20:19.977361Z","next":"2028-06-05T09:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"timezone":"EST"},"after":"2025-01-22T22:53:16.394003Z","next":"2025-01-22T23:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Asia/Kolkata"},"after":"2026-12-22T02:45:03.120749Z","next":"2028-02-29T06:30:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"timezone":"UTC"},"after":"2027-07-31T06:34:00.577717Z","next":"2027-07-31T07:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P0Y31DT2H"}],"timezone":"Australia/Lord_Howe"},"after":"2025-03-10T15:57:53.143767Z","next":"2025-03-26T02:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *",""],"intervals":[{"every":"PT21H","offset":"PT36H52M"}]},"after":"2028-05-14T03:55:18.487731Z","next":"2028-05-14T06:52:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"PT47H5235S"}],"timezone":"EST"},"after":"2025-04-25T00:11:32.296346Z","next":"2025-04-25T08:50:45.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","@hourly"],"intervals":[{"every":"P0001-00-02T00:00:00"}]},"after":"2027-03-01T16:20:10.099185Z","next":"2027-03-01T17:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *","0 9 * * 1-5"],"intervals":[{"every":"P1Y"},{"every":"PT15H3056S","offset":"P"}]},"after":"2028-06-05T07:20:19.977361Z","next":"2028-06-05T09:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"EST"},"after":"2025-01-22T22:53:16.394003Z","next":"2025-01-22T23:00:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Asia/Kolkata"},"after":"2026-12-22T02:45:03.120749Z","next":"2028-02-29T06:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"UTC"},"after":"2027-07-31T06:34:00.577717Z","next":"2027-07-31T07:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0Y31DT2H"}],"timezone":"Australia/Lord_Howe"},"after":"2025-03-10T15:57:53.143767Z","next":"2025-03-26T02:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *",""],"intervals":[{"every":"PT21H","offset":"PT36H52M"}]},"after":"2028-05-14T03:55:18.487731Z","next":"2028-05-14T06:52:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","0 3 * * *"],"intervals":[{"every":"P2YT49H"}],"timezone":"Asia/Kolkata"},"after":"2026-09-15T23:10:32.398680Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["5 4 L * ?","0 3 * * *"],"intervals":[{"every":"PT58M6403S"},{"every":"PT0001H","offset":"P8D"}],"timezone":"UTC"},"after":"2026-09-01T04:32:20.268467Z","next":"2026-09-01T05:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2MT23H53M"},{"every":"P0WT52M"}],"timezone":"Asia/Kolkata"},"after":"2028-05-18T14:59:37.518692Z","next":"2028-05-18T15:16:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?","0 3 * * *"],"intervals":[{"every":"PT58M6403S"},{"every":"PT0001H","offset":"P8D"}],"timezone":"UTC"},"after":"2026-09-01T04:32:20.268467Z","next":"2026-09-01T05:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2MT23H53M"},{"every":"P0WT52M"}],"timezone":"Asia/Kolkata"},"after":"2028-05-18T14:59:37.518692Z","next":"2028-05-18T15:16:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"Europe/Budapest"},"after":"2025-01-25T10:14:28.816783Z","next":null} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"intervals":[{"every":" P1D"},{"every":"P2YT1213S"}]},"after":"2025-08-27T08:05:10.744539Z","next":"2025-08-27T09:00:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 12 29 2 *"],"intervals":[{"every":" P1D"},{"every":"P2YT1213S"}]},"after":"2025-08-27T08:05:10.744539Z","next":"2025-08-27T09:00:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"Australia/Lord_Howe"},"after":"2026-03-24T00:52:36.997737Z","next":null} {"spec":{"intervals":[{"every":"PT1H1D"}]},"after":"2025-09-28T09:34:24.019639Z","next":null} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"PT3180S","offset":"PT3095S"},{"every":"PT36M5891S"}],"timezone":"Europe/Budapest"},"after":"2028-07-01T04:16:33.927473Z","next":"2028-07-01T04:19:03.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"PT3180S","offset":"PT3095S"},{"every":"PT36M5891S"}],"timezone":"Europe/Budapest"},"after":"2028-07-01T04:16:33.927473Z","next":"2028-07-01T04:19:03.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":[""],"intervals":[{"every":"P0Y"}]},"after":"2028-01-18T13:50:58.920347Z","next":null} -{"spec":{"intervals":[{"every":"P10M"}],"timezone":"EST"},"after":"2025-01-18T19:05:57.867674Z","next":"2025-11-08T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P21DT46H"}],"timezone":"Mars/Base"},"after":"2028-03-08T12:21:03.412222Z","next":"2028-03-23T16:00:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT1360S"},{"every":"P1Y11M2WT11H"}],"timezone":"America/New_York"},"after":"2026-04-17T13:18:27.891305Z","next":"2026-04-17T13:20:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2027-06-16T01:40:37.235997Z","next":"2027-06-20T02:30:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"P1W"},{"every":"P1WT50H84M"}],"timezone":"Europe/Budapest"},"after":"2026-08-05T21:06:29.049442Z","next":"2026-08-05T22:00:00.000000Z"} -{"spec":{"cron_expressions":["","@hourly"],"intervals":[{"every":"P7M1WT18H65M5161S"}]},"after":"2026-07-04T07:04:23.124652Z","next":"2026-07-04T08:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2026-03-27T01:44:50.751481Z","next":"2026-03-27T21:30:00.000000Z"} +{"spec":{"intervals":[{"every":"P10M"}],"timezone":"EST"},"after":"2025-01-18T19:05:57.867674Z","next":"2025-11-08T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P21DT46H"}],"timezone":"Mars/Base"},"after":"2028-03-08T12:21:03.412222Z","next":"2028-03-23T16:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT1360S"},{"every":"P1Y11M2WT11H"}],"timezone":"America/New_York"},"after":"2026-04-17T13:18:27.891305Z","next":"2026-04-17T13:20:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2027-06-16T01:40:37.235997Z","next":"2027-06-20T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"P1W"},{"every":"P1WT50H84M"}],"timezone":"Europe/Budapest"},"after":"2026-08-05T21:06:29.049442Z","next":"2026-08-05T22:00:00.000000Z","offset":"+02:00"} +{"spec":{"cron_expressions":["","@hourly"],"intervals":[{"every":"P7M1WT18H65M5161S"}]},"after":"2026-07-04T07:04:23.124652Z","next":"2026-07-04T08:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *","0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2026-03-27T01:44:50.751481Z","next":"2026-03-27T21:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["0 0 1 * *","bad cron"],"intervals":[{"every":"P14MT1234S"}]},"after":"2028-05-20T05:56:53.160699Z","error":"InvalidArgumentException"} {"spec":{"timezone":"+05:30"},"after":"2025-05-19T14:42:07.228540Z","next":null} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P9M35DT37H1054S"}],"timezone":"America/New_York"},"after":"2026-11-30T21:25:50.844234Z","next":"2026-12-01T08:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 9 * * 1-5"],"timezone":"+05:30"},"after":"2027-10-13T15:49:56.846238Z","next":"2027-10-14T03:30:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 9 * * 1-5"],"intervals":[{"every":"P1W11DT41H51M"},{"every":"P2MT56M","offset":"P0001-00-02T00:00:00"}]},"after":"2025-12-19T06:03:33.787931Z","next":"2025-12-19T09:00:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P9M35DT37H1054S"}],"timezone":"America/New_York"},"after":"2026-11-30T21:25:50.844234Z","next":"2026-12-01T08:00:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 9 * * 1-5"],"timezone":"+05:30"},"after":"2027-10-13T15:49:56.846238Z","next":"2027-10-14T03:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 9 * * 1-5"],"intervals":[{"every":"P1W11DT41H51M"},{"every":"P2MT56M","offset":"P0001-00-02T00:00:00"}]},"after":"2025-12-19T06:03:33.787931Z","next":"2025-12-19T09:00:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["30 2 * * SUN","bad cron"],"timezone":"UTC"},"after":"2026-03-11T15:18:05.561693Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["bad cron"],"timezone":"Asia/Kolkata"},"after":"2027-02-19T16:41:34.793050Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"P2M34DT21M","offset":"PT0H2068S"},{"every":"P1YT16H"}],"timezone":"Mars/Base"},"after":"2027-02-10T17:28:21.760356Z","error":"DateInvalidTimeZoneException"} {"spec":{"intervals":[{"every":"P2D1W","offset":"PT5H38M"}]},"after":"2027-09-06T10:44:19.577934Z","next":null} -{"spec":{"cron_expressions":["@hourly",""],"intervals":[{"every":"P0WT6H4375S"}]},"after":"2025-02-19T11:37:15.995304Z","next":"2025-02-19T12:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT21H"},{"every":"PT48H"}],"timezone":"Asia/Kolkata"},"after":"2026-05-15T09:24:35.154539Z","next":"2026-05-15T18:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P6MT23H76M"},{"every":"PT2327S"}],"timezone":"Mars/Base"},"after":"2028-06-22T02:52:12.417648Z","next":"2028-06-22T02:52:32.000000Z"} +{"spec":{"cron_expressions":["@hourly",""],"intervals":[{"every":"P0WT6H4375S"}]},"after":"2025-02-19T11:37:15.995304Z","next":"2025-02-19T12:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"PT21H"},{"every":"PT48H"}],"timezone":"Asia/Kolkata"},"after":"2026-05-15T09:24:35.154539Z","next":"2026-05-15T18:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P6MT23H76M"},{"every":"PT2327S"}],"timezone":"Mars/Base"},"after":"2028-06-22T02:52:12.417648Z","next":"2028-06-22T02:52:32.000000Z","offset":"+00:00"} {"spec":{"timezone":"Mars/Base"},"after":"2025-03-24T15:00:12.366398Z","next":null} -{"spec":{"intervals":[{"every":"PT352S"}]},"after":"2027-08-07T09:12:13.590173Z","next":"2027-08-07T09:15:44.000000Z"} +{"spec":{"intervals":[{"every":"PT352S"}]},"after":"2027-08-07T09:12:13.590173Z","next":"2027-08-07T09:15:44.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P1W2D"},{"every":"P0Y18DT16H59M"}],"timezone":"Mars/Base"},"after":"2027-06-09T12:56:16.785554Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron"],"timezone":"Europe/Budapest"},"after":"2027-01-31T13:26:12.757105Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P10000000000000000000D"},{"every":"P1Y","offset":"PT42H4414S"}],"timezone":""},"after":"2025-05-19T06:15:19.873782Z","next":"2025-12-19T19:13:34.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?","0 0 1 * *"],"intervals":[{"every":"PT80M3878S","offset":" P1D"}]},"after":"2025-11-08T09:35:26.065396Z","next":"2025-11-08T10:14:38.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"PT2957S"},{"every":"P7M19DT1127S"}],"timezone":"Asia/Kolkata"},"after":"2025-04-16T01:27:54.634186Z","next":"2025-04-16T02:02:59.000000Z"} -{"spec":{"intervals":[{"every":"P32DT12H52M"}],"timezone":"+05:30"},"after":"2025-02-06T23:25:25.115886Z","next":"2025-02-20T20:28:00.000000Z"} +{"spec":{"intervals":[{"every":"P10000000000000000000D"},{"every":"P1Y","offset":"PT42H4414S"}],"timezone":""},"after":"2025-05-19T06:15:19.873782Z","next":"2025-12-19T19:13:34.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?","0 0 1 * *"],"intervals":[{"every":"PT80M3878S","offset":" P1D"}]},"after":"2025-11-08T09:35:26.065396Z","next":"2025-11-08T10:14:38.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"PT2957S"},{"every":"P7M19DT1127S"}],"timezone":"Asia/Kolkata"},"after":"2025-04-16T01:27:54.634186Z","next":"2025-04-16T02:02:59.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P32DT12H52M"}],"timezone":"+05:30"},"after":"2025-02-06T23:25:25.115886Z","next":"2025-02-20T20:28:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"+05:30"},"after":"2028-06-29T16:22:17.749149Z","next":null} -{"spec":{"intervals":[{"every":"P0YT47M"}],"timezone":"Mars/Base"},"after":"2026-12-03T02:58:56.016708Z","next":"2026-12-03T03:45:00.000000Z"} +{"spec":{"intervals":[{"every":"P0YT47M"}],"timezone":"Mars/Base"},"after":"2026-12-03T02:58:56.016708Z","next":"2026-12-03T03:45:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"timezone":"Europe/Budapest"},"after":"2028-12-21T02:58:32.751986Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P1WT24H89M","offset":"PT1.5S"},{"every":"P10M11DT49H3395S","offset":"P3WT446S"}]},"after":"2026-12-11T11:27:37.257261Z","next":"2026-12-12T11:00:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","@hourly"],"intervals":[{"every":"PT33M5297S","offset":"PT59M"},{"every":"PT52M"}],"timezone":"Australia/Lord_Howe"},"after":"2027-03-10T12:10:30.418249Z","next":"2027-03-10T12:15:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":"Asia/Kolkata"},"after":"2027-03-25T08:23:50.295558Z","next":"2027-03-26T03:30:00.000000Z"} +{"spec":{"intervals":[{"every":"P1WT24H89M","offset":"PT1.5S"},{"every":"P10M11DT49H3395S","offset":"P3WT446S"}]},"after":"2026-12-11T11:27:37.257261Z","next":"2026-12-12T11:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","@hourly"],"intervals":[{"every":"PT33M5297S","offset":"PT59M"},{"every":"PT52M"}],"timezone":"Australia/Lord_Howe"},"after":"2027-03-10T12:10:30.418249Z","next":"2027-03-10T12:15:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":"Asia/Kolkata"},"after":"2027-03-25T08:23:50.295558Z","next":"2027-03-26T03:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["bad cron","0 9 * * 1-5"]},"after":"2028-08-20T23:08:35.468998Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P0W5D"}]},"after":"2025-10-04T03:14:25.526172Z","next":"2025-10-09T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT3007S","offset":"PT44H"},{"every":"P27DT49H"}],"timezone":"America/New_York"},"after":"2027-02-12T21:06:31.528839Z","next":"2027-02-12T21:16:37.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P3M4DT2855S"}],"timezone":"Europe/Budapest"},"after":"2028-11-10T23:45:32.730300Z","next":"2028-12-15T13:36:35.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *","*/15 * * * *"],"intervals":[{"every":"P3WT24H6608S"},{"every":"PT8M","offset":"P14MT17M"}],"timezone":"UTC"},"after":"2026-06-19T09:44:32.385273Z","next":"2026-06-19T09:45:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2028-07-09T19:45:23.909735Z","next":"2028-08-01T00:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 12 29 2 *"],"intervals":[{"every":"P6MT73M"}],"timezone":"EST"},"after":"2026-12-29T11:06:06.183637Z","next":"2027-01-03T07:30:00.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P11M1W","offset":"P0YT6619S"}],"timezone":"+05:30"},"after":"2028-12-08T00:46:53.242429Z","next":"2029-01-19T01:50:19.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *","0 0 1 * *"],"timezone":"Australia/Lord_Howe"},"after":"2025-12-23T23:00:08.534955Z","next":"2025-12-31T13:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P0W5D"}]},"after":"2025-10-04T03:14:25.526172Z","next":"2025-10-09T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT3007S","offset":"PT44H"},{"every":"P27DT49H"}],"timezone":"America/New_York"},"after":"2027-02-12T21:06:31.528839Z","next":"2027-02-12T21:16:37.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P3M4DT2855S"}],"timezone":"Europe/Budapest"},"after":"2028-11-10T23:45:32.730300Z","next":"2028-12-15T13:36:35.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *","*/15 * * * *"],"intervals":[{"every":"P3WT24H6608S"},{"every":"PT8M","offset":"P14MT17M"}],"timezone":"UTC"},"after":"2026-06-19T09:44:32.385273Z","next":"2026-06-19T09:45:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"]},"after":"2028-07-09T19:45:23.909735Z","next":"2028-08-01T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 12 29 2 *"],"intervals":[{"every":"P6MT73M"}],"timezone":"EST"},"after":"2026-12-29T11:06:06.183637Z","next":"2027-01-03T07:30:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P11M1W","offset":"P0YT6619S"}],"timezone":"+05:30"},"after":"2028-12-08T00:46:53.242429Z","next":"2029-01-19T01:50:19.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *","0 0 1 * *"],"timezone":"Australia/Lord_Howe"},"after":"2025-12-23T23:00:08.534955Z","next":"2025-12-31T13:00:00.000000Z","offset":"+11:00"} {"spec":{"timezone":"UTC"},"after":"2027-07-07T02:04:39.748455Z","next":null} {"spec":{"cron_expressions":["@hourly","bad cron"],"intervals":[{"every":"P1Y3M"},{"every":"PT11M"}]},"after":"2025-08-13T18:28:10.001052Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"PT15M","offset":"P13M2W40DT5614S"},{"every":"P1W"}]},"after":"2027-06-20T09:36:27.964154Z","next":"2027-06-20T09:48:34.000000Z"} +{"spec":{"intervals":[{"every":"PT15M","offset":"P13M2W40DT5614S"},{"every":"P1W"}]},"after":"2027-06-20T09:36:27.964154Z","next":"2027-06-20T09:48:34.000000Z","offset":"+00:00"} {"spec":{"timezone":"America/New_York"},"after":"2026-05-27T13:27:37.280399Z","next":null} -{"spec":{"intervals":[{"every":"PT841S"},{"every":"P2Y1W2DT16H"}],"timezone":"America/New_York"},"after":"2026-08-11T08:11:47.676166Z","next":"2026-08-11T08:17:01.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P9M24DT36H31M","offset":"PT2911S"}]},"after":"2026-11-11T04:32:03.768302Z","next":"2026-11-11T05:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"P1W"}],"timezone":"+05:30"},"after":"2026-12-10T04:10:14.107477Z","next":"2026-12-10T04:30:00.000000Z"} +{"spec":{"intervals":[{"every":"PT841S"},{"every":"P2Y1W2DT16H"}],"timezone":"America/New_York"},"after":"2026-08-11T08:11:47.676166Z","next":"2026-08-11T08:17:01.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P9M24DT36H31M","offset":"PT2911S"}]},"after":"2026-11-11T04:32:03.768302Z","next":"2026-11-11T05:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly","0 0 1 * *"],"intervals":[{"every":"P1W"}],"timezone":"+05:30"},"after":"2026-12-10T04:10:14.107477Z","next":"2026-12-10T04:30:00.000000Z","offset":"+05:30"} {"spec":{"timezone":"America/New_York"},"after":"2025-01-20T12:38:15.731407Z","next":null} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P2WT240S","offset":"PT0H3359S"},{"every":"P1YT12M4718S","offset":"PT1799S"}],"timezone":"America/New_York"},"after":"2025-09-03T13:12:27.729164Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"America/New_York"},"after":"2028-12-11T20:58:08.791187Z","next":"2028-12-17T07:30:00.000000Z"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"America/New_York"},"after":"2028-12-11T20:58:08.791187Z","next":"2028-12-17T07:30:00.000000Z","offset":"-05:00"} {"spec":{"timezone":"Mars/Base"},"after":"2028-08-23T11:10:48.787613Z","next":null} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P14M"},{"every":"PT887S"}],"timezone":"Australia/Lord_Howe"},"after":"2028-11-03T07:03:39.212632Z","next":"2028-11-03T07:14:21.000000Z"} -{"spec":{"intervals":[{"every":"P2YT87M1244S"}],"timezone":"America/New_York"},"after":"2026-05-07T14:24:59.522654Z","next":"2027-12-20T04:04:16.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT1.5S"}],"timezone":"Europe/Budapest"},"after":"2027-11-04T16:15:30.391066Z","next":"2027-11-05T02:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"intervals":[{"every":"P2D1W","offset":"P7D"}]},"after":"2027-09-24T14:49:07.429099Z","next":"2027-09-26T02:30:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"PT13H79M2379S"},{"every":"P0001-00-02T00:00:00"}],"timezone":"UTC"},"after":"2026-12-27T06:24:43.629134Z","next":"2026-12-27T08:33:27.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P14M"},{"every":"PT887S"}],"timezone":"Australia/Lord_Howe"},"after":"2028-11-03T07:03:39.212632Z","next":"2028-11-03T07:14:21.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2YT87M1244S"}],"timezone":"America/New_York"},"after":"2026-05-07T14:24:59.522654Z","next":"2027-12-20T04:04:16.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT1.5S"}],"timezone":"Europe/Budapest"},"after":"2027-11-04T16:15:30.391066Z","next":"2027-11-05T02:00:00.000000Z","offset":"+01:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"intervals":[{"every":"P2D1W","offset":"P7D"}]},"after":"2027-09-24T14:49:07.429099Z","next":"2027-09-26T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"PT13H79M2379S"},{"every":"P0001-00-02T00:00:00"}],"timezone":"UTC"},"after":"2026-12-27T06:24:43.629134Z","next":"2026-12-27T08:33:27.000000Z","offset":"+00:00"} {"spec":{"timezone":"Europe/Budapest"},"after":"2027-05-12T17:09:10.245632Z","next":null} -{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"PT365S","offset":"PT6012S"},{"every":"P1M33D"}],"timezone":"UTC"},"after":"2027-05-06T18:35:26.651698Z","next":"2027-05-06T18:36:02.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"PT365S","offset":"PT6012S"},{"every":"P1M33D"}],"timezone":"UTC"},"after":"2027-05-06T18:35:26.651698Z","next":"2027-05-06T18:36:02.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":[""],"timezone":"Mars/Base"},"after":"2026-03-10T10:39:07.478198Z","next":null} {"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT5H3741S"}],"timezone":""},"after":"2028-01-05T18:20:34.888588Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P4M0WT2322S"}]},"after":"2026-07-21T16:28:15.662861Z","next":"2026-07-21T17:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P0000-00-00T00:00:01"},{"every":"P0M26D","offset":"PT46H5M"}],"timezone":""},"after":"2027-06-04T00:58:09.456761Z","next":"2027-06-04T00:58:10.000000Z"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P4M0WT2322S"}]},"after":"2026-07-21T16:28:15.662861Z","next":"2026-07-21T17:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P0000-00-00T00:00:01"},{"every":"P0M26D","offset":"PT46H5M"}],"timezone":""},"after":"2027-06-04T00:58:09.456761Z","next":"2027-06-04T00:58:10.000000Z","offset":"+00:00"} {"spec":{"timezone":"+05:30"},"after":"2027-01-27T09:08:05.832968Z","next":null} {"spec":{"cron_expressions":["bad cron"],"timezone":"Australia/Lord_Howe"},"after":"2028-12-25T04:26:27.107672Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"timezone":"EST"},"after":"2028-05-29T01:31:21.413723Z","next":"2028-05-29T02:00:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P0WT42H","offset":"PT1199S"}]},"after":"2028-01-04T18:16:16.915036Z","next":"2028-01-04T18:30:00.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"timezone":"EST"},"after":"2028-05-29T01:31:21.413723Z","next":"2028-05-29T02:00:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P0WT42H","offset":"PT1199S"}]},"after":"2028-01-04T18:16:16.915036Z","next":"2028-01-04T18:30:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 0 1 * *","5 4 L * ?"],"intervals":[{"every":"P1W2D"},{"every":"PT679S"}],"timezone":""},"after":"2028-03-04T03:20:11.545837Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron","bad cron"],"intervals":[{"every":"PT1447S"},{"every":"P21DT63M3717S"}],"timezone":"+05:30"},"after":"2025-12-26T02:29:16.499383Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 12 29 2 *",""],"timezone":"+05:30"},"after":"2027-07-15T01:40:42.095387Z","next":"2028-02-29T06:30:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 0 1 * *"],"intervals":[{"every":"P1YT5H4M"}],"timezone":"+05:30"},"after":"2028-04-19T02:09:53.218402Z","next":"2028-04-19T03:30:00.000000Z"} +{"spec":{"cron_expressions":["0 12 29 2 *",""],"timezone":"+05:30"},"after":"2027-07-15T01:40:42.095387Z","next":"2028-02-29T06:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 0 1 * *"],"intervals":[{"every":"P1YT5H4M"}],"timezone":"+05:30"},"after":"2028-04-19T02:09:53.218402Z","next":"2028-04-19T03:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P0000-00-00T00:00:01","offset":"P3WT3M"},{"every":"P0YT88M4546S"}],"timezone":"Europe/Budapest"},"after":"2028-10-07T22:05:54.257137Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly","0 9 * * 1-5"],"intervals":[{"every":"P0YT6H24M6322S"}],"timezone":"EST"},"after":"2028-10-26T01:31:52.303616Z","next":"2028-10-26T02:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","0 12 29 2 *"],"intervals":[{"every":"PT30H","offset":"PT5H"},{"every":"P1YT14M"}]},"after":"2027-06-02T15:17:32.785214Z","next":"2027-06-03T03:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P0Y3W"}]},"after":"2026-05-28T21:25:27.136769Z","next":"2026-05-28T22:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P7DT3H4M1770S","offset":"P2YT8H43M"},{"every":"P3WT78M646S","offset":"P0Y1W27DT4353S"}],"timezone":"Europe/Budapest"},"after":"2025-01-29T10:37:45.084511Z","next":"2025-02-04T14:28:30.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 9 * * 1-5"],"intervals":[{"every":"P0YT6H24M6322S"}],"timezone":"EST"},"after":"2028-10-26T01:31:52.303616Z","next":"2028-10-26T02:00:00.000000Z","offset":"-05:00"} +{"spec":{"cron_expressions":["0 3 * * *","0 12 29 2 *"],"intervals":[{"every":"PT30H","offset":"PT5H"},{"every":"P1YT14M"}]},"after":"2027-06-02T15:17:32.785214Z","next":"2027-06-03T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P0Y3W"}]},"after":"2026-05-28T21:25:27.136769Z","next":"2026-05-28T22:00:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P7DT3H4M1770S","offset":"P2YT8H43M"},{"every":"P3WT78M646S","offset":"P0Y1W27DT4353S"}],"timezone":"Europe/Budapest"},"after":"2025-01-29T10:37:45.084511Z","next":"2025-02-04T14:28:30.000000Z","offset":"+00:00"} {"spec":{"timezone":"America/New_York"},"after":"2025-04-12T14:27:45.093767Z","next":null} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT2059S"},{"every":"P0WT1487S"}],"timezone":"UTC"},"after":"2027-04-28T14:09:01.570182Z","next":"2027-04-28T14:15:00.000000Z"} -{"spec":{"intervals":[{"every":"P2Y13M3WT23M2798S"}],"timezone":"UTC"},"after":"2028-04-30T19:08:55.882884Z","next":"2029-05-10T22:03:02.000000Z"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"PT2059S"},{"every":"P0WT1487S"}],"timezone":"UTC"},"after":"2027-04-28T14:09:01.570182Z","next":"2027-04-28T14:15:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P2Y13M3WT23M2798S"}],"timezone":"UTC"},"after":"2028-04-30T19:08:55.882884Z","next":"2029-05-10T22:03:02.000000Z","offset":"+00:00"} {"spec":{"timezone":"+05:30"},"after":"2027-02-17T20:04:45.834270Z","next":null} {"spec":{"timezone":"UTC"},"after":"2025-02-17T10:29:07.447213Z","next":null} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P12MT2744S"}],"timezone":"Europe/Budapest"},"after":"2026-04-10T12:32:48.747533Z","next":"2026-04-11T01:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"intervals":[{"every":"P2Y0DT62M"}],"timezone":"Australia/Lord_Howe"},"after":"2026-09-23T18:09:40.405162Z","next":"2026-09-23T18:30:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","@hourly"],"timezone":"EST"},"after":"2026-11-12T23:46:25.107691Z","next":"2026-11-13T00:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P2YT84M","offset":"P1D "},{"every":"P1YT42H1751S","offset":"P2Y11M25DT3333S"}],"timezone":""},"after":"2025-09-09T16:54:14.086905Z","next":"2025-12-20T15:12:00.000000Z"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P12MT2744S"}],"timezone":"Europe/Budapest"},"after":"2026-04-10T12:32:48.747533Z","next":"2026-04-11T01:00:00.000000Z","offset":"+02:00"} +{"spec":{"cron_expressions":["@hourly","0 12 29 2 *"],"intervals":[{"every":"P2Y0DT62M"}],"timezone":"Australia/Lord_Howe"},"after":"2026-09-23T18:09:40.405162Z","next":"2026-09-23T18:30:00.000000Z","offset":"+10:30"} +{"spec":{"cron_expressions":["0 9 * * 1-5","@hourly"],"timezone":"EST"},"after":"2026-11-12T23:46:25.107691Z","next":"2026-11-13T00:00:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"P2YT84M","offset":"P1D "},{"every":"P1YT42H1751S","offset":"P2Y11M25DT3333S"}],"timezone":""},"after":"2025-09-09T16:54:14.086905Z","next":"2025-12-20T15:12:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","@hourly"],"timezone":"Europe/Budapest"},"after":"2027-08-10T09:28:31.100791Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["","@hourly"],"timezone":"+05:30"},"after":"2026-07-03T05:24:12.839482Z","next":"2026-07-03T05:30:00.000000Z"} -{"spec":{"intervals":[{"every":"P1YT32M6644S"}]},"after":"2026-06-15T16:00:41.356533Z","next":"2026-12-23T15:35:48.000000Z"} -{"spec":{"intervals":[{"every":"P6M","offset":"PT48S"},{"every":"PT6H","offset":"P5MT22H25M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-12-19T18:07:36.150317Z","next":"2028-12-19T22:25:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":"EST"},"after":"2026-03-31T00:05:56.526078Z","next":"2026-03-31T14:00:00.000000Z"} -{"spec":{"intervals":[{"every":"PT1603S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-05-21T10:52:55.835917Z","next":"2025-05-21T11:17:21.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT32M"}]},"after":"2025-09-04T12:46:58.433206Z","next":"2025-09-04T12:48:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?","0 9 * * 1-5"],"intervals":[{"every":"P1W4DT18M4172S"},{"every":"P2WT2H5M"}]},"after":"2025-03-07T22:26:01.676230Z","next":"2025-03-10T09:00:00.000000Z"} +{"spec":{"cron_expressions":["","@hourly"],"timezone":"+05:30"},"after":"2026-07-03T05:24:12.839482Z","next":"2026-07-03T05:30:00.000000Z","offset":"+05:30"} +{"spec":{"intervals":[{"every":"P1YT32M6644S"}]},"after":"2026-06-15T16:00:41.356533Z","next":"2026-12-23T15:35:48.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P6M","offset":"PT48S"},{"every":"PT6H","offset":"P5MT22H25M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-12-19T18:07:36.150317Z","next":"2028-12-19T22:25:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"timezone":"EST"},"after":"2026-03-31T00:05:56.526078Z","next":"2026-03-31T14:00:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"PT1603S"}],"timezone":"Australia/Lord_Howe"},"after":"2025-05-21T10:52:55.835917Z","next":"2025-05-21T11:17:21.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT32M"}]},"after":"2025-09-04T12:46:58.433206Z","next":"2025-09-04T12:48:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?","0 9 * * 1-5"],"intervals":[{"every":"P1W4DT18M4172S"},{"every":"P2WT2H5M"}]},"after":"2025-03-07T22:26:01.676230Z","next":"2025-03-10T09:00:00.000000Z","offset":"+00:00"} {"spec":{"timezone":"Europe/Budapest"},"after":"2028-06-02T01:03:28.593956Z","next":null} {"spec":{"cron_expressions":["bad cron","5 4 L * ?"],"intervals":[{"every":"P12M11DT5606S"}]},"after":"2027-02-20T15:51:28.737245Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P2Y0W"},{"every":"P1YT22H"}]},"after":"2026-11-21T20:57:43.086715Z","next":"2027-02-08T06:00:00.000000Z"} -{"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"PT43M"}],"timezone":"Asia/Kolkata"},"after":"2026-07-21T01:21:39.190170Z","next":"2026-07-21T01:55:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P16DT11H"}],"timezone":"Europe/Budapest"},"after":"2025-10-10T17:20:39.897813Z","next":"2025-10-14T10:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1Y1WT76M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-11-27T17:25:11.888760Z","next":"2028-11-28T16:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2MT16H57M","offset":"P2WT17H"}]},"after":"2028-04-09T01:18:43.454806Z","next":"2028-04-09T02:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"timezone":"UTC"},"after":"2026-09-20T08:31:47.183541Z","next":"2026-09-27T02:30:00.000000Z"} +{"spec":{"intervals":[{"every":"P2Y0W"},{"every":"P1YT22H"}]},"after":"2026-11-21T20:57:43.086715Z","next":"2027-02-08T06:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["","0 9 * * 1-5"],"intervals":[{"every":"PT43M"}],"timezone":"Asia/Kolkata"},"after":"2026-07-21T01:21:39.190170Z","next":"2026-07-21T01:55:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P16DT11H"}],"timezone":"Europe/Budapest"},"after":"2025-10-10T17:20:39.897813Z","next":"2025-10-14T10:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P1Y1WT76M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-11-27T17:25:11.888760Z","next":"2028-11-28T16:00:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"P2MT16H57M","offset":"P2WT17H"}]},"after":"2028-04-09T01:18:43.454806Z","next":"2028-04-09T02:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN","0 0 1 * *"],"timezone":"UTC"},"after":"2026-09-20T08:31:47.183541Z","next":"2026-09-27T02:30:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":""},"after":"2025-12-28T01:17:20.637191Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron",""],"intervals":[{"every":"P6M"},{"every":"P0Y19DT21M"}],"timezone":"Asia/Kolkata"},"after":"2028-12-26T13:46:01.187704Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["@hourly","0 9 * * 1-5"],"intervals":[{"every":"P7MT55M","offset":"P2YT10H"}],"timezone":"Australia/Lord_Howe"},"after":"2026-12-29T06:37:33.194389Z","next":"2026-12-29T07:00:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT2311S"},{"every":"P7MT28H23M3499S","offset":"P1H"}],"timezone":"+05:30"},"after":"2027-06-21T07:21:11.470798Z","next":"2027-06-21T07:49:43.000000Z"} +{"spec":{"cron_expressions":["@hourly","0 9 * * 1-5"],"intervals":[{"every":"P7MT55M","offset":"P2YT10H"}],"timezone":"Australia/Lord_Howe"},"after":"2026-12-29T06:37:33.194389Z","next":"2026-12-29T07:00:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"PT2311S"},{"every":"P7MT28H23M3499S","offset":"P1H"}],"timezone":"+05:30"},"after":"2027-06-21T07:21:11.470798Z","next":"2027-06-21T07:49:43.000000Z","offset":"+00:00"} {"spec":{"timezone":"+05:30"},"after":"2026-09-24T13:51:06.096924Z","next":null} -{"spec":{"intervals":[{"every":"P0Y3WT81M"},{"every":"P13M28DT53M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-02-23T12:54:04.920105Z","next":"2028-03-02T18:09:00.000000Z"} -{"spec":{"intervals":[{"every":"P8DT27H4252S"},{"every":"P10000000000000000000D","offset":"P11M0WT3H5951S"}],"timezone":"Asia/Kolkata"},"after":"2026-03-24T06:35:01.245998Z","next":"2026-03-29T01:30:28.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P0WT36M","offset":"P2YT31H5432S"}]},"after":"2028-01-27T05:04:39.934361Z","next":"2028-01-27T05:30:32.000000Z"} -{"spec":{"intervals":[{"every":"P7MT14M"}],"timezone":"Europe/Budapest"},"after":"2026-05-08T07:51:47.649487Z","next":"2026-12-03T23:06:00.000000Z"} +{"spec":{"intervals":[{"every":"P0Y3WT81M"},{"every":"P13M28DT53M"}],"timezone":"Australia/Lord_Howe"},"after":"2028-02-23T12:54:04.920105Z","next":"2028-03-02T18:09:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P8DT27H4252S"},{"every":"P10000000000000000000D","offset":"P11M0WT3H5951S"}],"timezone":"Asia/Kolkata"},"after":"2026-03-24T06:35:01.245998Z","next":"2026-03-29T01:30:28.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"intervals":[{"every":"P0WT36M","offset":"P2YT31H5432S"}]},"after":"2028-01-27T05:04:39.934361Z","next":"2028-01-27T05:30:32.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"P7MT14M"}],"timezone":"Europe/Budapest"},"after":"2026-05-08T07:51:47.649487Z","next":"2026-12-03T23:06:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P1YT39H"}],"timezone":"Asia/Kolkata"},"after":"2026-01-22T04:12:30.162444Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["0 9 * * 1-5","bad cron"],"intervals":[{"every":"P9M3W"},{"every":"P15D","offset":"P18D"}],"timezone":"Mars/Base"},"after":"2028-11-06T02:07:55.441990Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P0WT4725S"},{"every":"P3WT648S","offset":"P2Y24DT4083S"}],"timezone":"EST"},"after":"2025-02-08T11:26:44.253213Z","next":"2025-02-08T12:22:30.000000Z"} +{"spec":{"intervals":[{"every":"P0WT4725S"},{"every":"P3WT648S","offset":"P2Y24DT4083S"}],"timezone":"EST"},"after":"2025-02-08T11:26:44.253213Z","next":"2025-02-08T12:22:30.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","0 3 * * *"]},"after":"2028-08-09T08:48:08.237585Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P4M","offset":"PT86M"}],"timezone":"EST"},"after":"2027-12-04T22:26:08.716976Z","next":"2028-02-26T01:26:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P13M3WT3261S"}],"timezone":"America/New_York"},"after":"2026-01-19T19:09:33.174773Z","next":"2026-01-20T08:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P3M39DT46H77M"}],"timezone":"UTC"},"after":"2026-03-10T15:01:50.491354Z","next":"2026-04-19T07:29:00.000000Z"} -{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2026-06-29T04:16:30.557734Z","next":"2026-06-30T18:30:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"Asia/Kolkata"},"after":"2026-08-02T13:04:47.187823Z","next":"2026-08-08T21:00:00.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT2860S"},{"every":"PT2638S","offset":"PT"}],"timezone":"Europe/Budapest"},"after":"2028-04-27T02:21:47.408712Z","next":"2028-04-27T02:35:20.000000Z"} +{"spec":{"intervals":[{"every":"P4M","offset":"PT86M"}],"timezone":"EST"},"after":"2027-12-04T22:26:08.716976Z","next":"2028-02-26T01:26:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P13M3WT3261S"}],"timezone":"America/New_York"},"after":"2026-01-19T19:09:33.174773Z","next":"2026-01-20T08:00:00.000000Z","offset":"-05:00"} +{"spec":{"intervals":[{"every":"P3M39DT46H77M"}],"timezone":"UTC"},"after":"2026-03-10T15:01:50.491354Z","next":"2026-04-19T07:29:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Asia/Kolkata"},"after":"2026-06-29T04:16:30.557734Z","next":"2026-06-30T18:30:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"timezone":"Asia/Kolkata"},"after":"2026-08-02T13:04:47.187823Z","next":"2026-08-08T21:00:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["@hourly"],"intervals":[{"every":"PT2860S"},{"every":"PT2638S","offset":"PT"}],"timezone":"Europe/Budapest"},"after":"2028-04-27T02:21:47.408712Z","next":"2028-04-27T02:35:20.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":[""],"timezone":"+05:30"},"after":"2026-12-30T01:24:35.149947Z","next":null} -{"spec":{"intervals":[{"every":"P2WT41M5551S"}],"timezone":"America/New_York"},"after":"2025-09-26T18:33:13.884679Z","next":"2025-10-02T23:31:35.000000Z"} +{"spec":{"intervals":[{"every":"P2WT41M5551S"}],"timezone":"America/New_York"},"after":"2025-09-26T18:33:13.884679Z","next":"2025-10-02T23:31:35.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","@hourly"],"timezone":"+05:30"},"after":"2027-02-24T10:55:17.432973Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 0 1 * *","30 2 * * SUN"],"intervals":[{"every":"P1W"},{"every":"P13D"}],"timezone":"Australia/Lord_Howe"},"after":"2026-02-20T09:48:01.738348Z","next":"2026-02-21T15:30:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *","@hourly"],"intervals":[{"every":"PT80M","offset":"P0YT30M657S"},{"every":"P1H","offset":"P1WT51M"}],"timezone":"America/New_York"},"after":"2027-05-03T13:49:46.486180Z","next":"2027-05-03T14:00:00.000000Z"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P2W"},{"every":"P1WT27H"}],"timezone":"Australia/Lord_Howe"},"after":"2027-02-17T04:38:08.197029Z","next":"2027-02-24T03:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"PT66M6672S"},{"every":"P"}],"timezone":"+05:30"},"after":"2028-09-07T04:05:51.807222Z","next":"2028-09-07T04:27:36.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","@hourly"],"intervals":[{"every":"P2YT20H"},{"every":"PT2H16M"}],"timezone":"+05:30"},"after":"2026-09-04T02:58:08.866458Z","next":"2026-09-04T03:00:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2025-04-17T18:48:32.751543Z","next":"2025-04-20T02:30:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P0D"},{"every":"PT33H34M"}]},"after":"2026-10-24T03:55:17.295775Z","next":"2026-10-25T04:38:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *","30 2 * * SUN"],"intervals":[{"every":"P1W"},{"every":"P13D"}],"timezone":"Australia/Lord_Howe"},"after":"2026-02-20T09:48:01.738348Z","next":"2026-02-21T15:30:00.000000Z","offset":"+11:00"} +{"spec":{"cron_expressions":["0 3 * * *","@hourly"],"intervals":[{"every":"PT80M","offset":"P0YT30M657S"},{"every":"P1H","offset":"P1WT51M"}],"timezone":"America/New_York"},"after":"2027-05-03T13:49:46.486180Z","next":"2027-05-03T14:00:00.000000Z","offset":"-04:00"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P2W"},{"every":"P1WT27H"}],"timezone":"Australia/Lord_Howe"},"after":"2027-02-17T04:38:08.197029Z","next":"2027-02-24T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"],"intervals":[{"every":"PT66M6672S"},{"every":"P"}],"timezone":"+05:30"},"after":"2028-09-07T04:05:51.807222Z","next":"2028-09-07T04:27:36.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","@hourly"],"intervals":[{"every":"P2YT20H"},{"every":"PT2H16M"}],"timezone":"+05:30"},"after":"2026-09-04T02:58:08.866458Z","next":"2026-09-04T03:00:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2025-04-17T18:48:32.751543Z","next":"2025-04-20T02:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P0D"},{"every":"PT33H34M"}]},"after":"2026-10-24T03:55:17.295775Z","next":"2026-10-25T04:38:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","bad cron"],"intervals":[{"every":"PT2966S"}],"timezone":"Europe/Budapest"},"after":"2028-02-19T13:53:14.677613Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["0 0 1 * *","bad cron"],"intervals":[{"every":"PT51M5078S"}]},"after":"2026-08-14T17:39:52.890454Z","error":"InvalidArgumentException"} {"spec":{"cron_expressions":["0 0 1 * *"],"timezone":"Mars/Base"},"after":"2027-05-21T20:10:13.143227Z","error":"DateInvalidTimeZoneException"} {"spec":{"timezone":"Australia/Lord_Howe"},"after":"2027-04-05T00:11:09.055188Z","next":null} -{"spec":{"cron_expressions":["@hourly"]},"after":"2025-01-06T16:23:14.305637Z","next":"2025-01-06T17:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 3 * * *"]},"after":"2028-12-04T20:24:10.233883Z","next":"2028-12-05T03:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"P3W"}],"timezone":"+05:30"},"after":"2027-07-31T02:00:51.896288Z","next":"2027-08-12T00:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","30 2 * * SUN"]},"after":"2027-07-26T19:49:36.503106Z","next":"2027-07-27T09:00:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *",""]},"after":"2025-09-16T05:20:46.388159Z","next":"2025-09-17T03:00:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5","0 0 1 * *"],"intervals":[{"every":"P1YT13H3172S","offset":"PT3117S"},{"every":"PT15M"}],"timezone":"America/New_York"},"after":"2026-01-04T12:00:10.769130Z","next":"2026-01-04T12:15:00.000000Z"} -{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2026-08-31T22:28:14.121490Z","next":"2026-09-06T02:30:00.000000Z"} +{"spec":{"cron_expressions":["@hourly"]},"after":"2025-01-06T16:23:14.305637Z","next":"2025-01-06T17:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 3 * * *"]},"after":"2028-12-04T20:24:10.233883Z","next":"2028-12-05T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *","0 12 29 2 *"],"intervals":[{"every":"P3W"}],"timezone":"+05:30"},"after":"2027-07-31T02:00:51.896288Z","next":"2027-08-12T00:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","30 2 * * SUN"]},"after":"2027-07-26T19:49:36.503106Z","next":"2027-07-27T09:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *",""]},"after":"2025-09-16T05:20:46.388159Z","next":"2025-09-17T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5","0 0 1 * *"],"intervals":[{"every":"P1YT13H3172S","offset":"PT3117S"},{"every":"PT15M"}],"timezone":"America/New_York"},"after":"2026-01-04T12:00:10.769130Z","next":"2026-01-04T12:15:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["30 2 * * SUN"]},"after":"2026-08-31T22:28:14.121490Z","next":"2026-09-06T02:30:00.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["bad cron","5 4 L * ?"],"intervals":[{"every":"P0Y0WT86M"},{"every":"P2Y2M3W16DT27M","offset":"PT2120S"}],"timezone":"+05:30"},"after":"2027-07-15T21:26:34.731017Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["0 0 1 * *","0 3 * * *"],"intervals":[{"every":"P1YT90M"},{"every":"PT5018S","offset":"P1Y9MT37H71M4532S"}],"timezone":"Asia/Kolkata"},"after":"2027-12-21T21:30:06.658712Z","next":"2027-12-21T21:53:10.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P0YT6366S","offset":"P2Y1W"}],"timezone":"Asia/Kolkata"},"after":"2026-03-24T21:41:26.622374Z","next":"2026-03-24T21:45:00.000000Z"} -{"spec":{"cron_expressions":["","*/15 * * * *"],"intervals":[{"every":"P2W"}],"timezone":"EST"},"after":"2027-11-17T15:00:41.485866Z","next":"2027-11-17T15:15:00.000000Z"} +{"spec":{"cron_expressions":["0 0 1 * *","0 3 * * *"],"intervals":[{"every":"P1YT90M"},{"every":"PT5018S","offset":"P1Y9MT37H71M4532S"}],"timezone":"Asia/Kolkata"},"after":"2027-12-21T21:30:06.658712Z","next":"2027-12-21T21:53:10.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"intervals":[{"every":"P0YT6366S","offset":"P2Y1W"}],"timezone":"Asia/Kolkata"},"after":"2026-03-24T21:41:26.622374Z","next":"2026-03-24T21:45:00.000000Z","offset":"+05:30"} +{"spec":{"cron_expressions":["","*/15 * * * *"],"intervals":[{"every":"P2W"}],"timezone":"EST"},"after":"2027-11-17T15:00:41.485866Z","next":"2027-11-17T15:15:00.000000Z","offset":"-05:00"} {"spec":{"cron_expressions":["0 12 29 2 *","5 4 L * ?"],"intervals":[{"every":"P1W33D","offset":"P12MT378S"}],"timezone":"Mars/Base"},"after":"2028-04-19T05:22:05.237645Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["","0 9 * * 1-5"]},"after":"2026-10-07T10:43:41.406206Z","next":"2026-10-08T09:00:00.000000Z"} -{"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Europe/Budapest"},"after":"2025-11-19T08:15:58.552197Z","next":"2028-02-29T11:00:00.000000Z"} -{"spec":{"intervals":[{"every":"P0YT48H5728S"},{"every":"P0D"}],"timezone":"Asia/Kolkata"},"after":"2027-10-02T05:05:34.508435Z","next":"2027-10-03T19:39:12.000000Z"} +{"spec":{"cron_expressions":["","0 9 * * 1-5"]},"after":"2026-10-07T10:43:41.406206Z","next":"2026-10-08T09:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":"Europe/Budapest"},"after":"2025-11-19T08:15:58.552197Z","next":"2028-02-29T11:00:00.000000Z","offset":"+01:00"} +{"spec":{"intervals":[{"every":"P0YT48H5728S"},{"every":"P0D"}],"timezone":"Asia/Kolkata"},"after":"2027-10-02T05:05:34.508435Z","next":"2027-10-03T19:39:12.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["@hourly","bad cron"],"intervals":[{"every":"P0WT22M"},{"every":"PT623S","offset":"P12MT4H"}]},"after":"2026-06-12T03:09:06.754174Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P2WT23H"},{"every":"P1YT435S"}]},"after":"2025-02-24T20:15:53.177304Z","next":"2025-02-28T04:05:00.000000Z"} -{"spec":{"intervals":[{"every":"PT1551S"},{"every":"PT2326S","offset":"P2YT41H1729S"}]},"after":"2028-12-05T19:57:34.522907Z","next":"2028-12-05T20:10:57.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *","*/15 * * * *"],"timezone":"UTC"},"after":"2027-04-02T19:21:37.829761Z","next":"2027-04-02T19:30:00.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P0Y1WT9H"}],"timezone":"America/New_York"},"after":"2027-04-16T09:59:04.666378Z","next":"2027-04-17T07:00:00.000000Z"} +{"spec":{"cron_expressions":["5 4 L * ?"],"intervals":[{"every":"P2WT23H"},{"every":"P1YT435S"}]},"after":"2025-02-24T20:15:53.177304Z","next":"2025-02-28T04:05:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT1551S"},{"every":"PT2326S","offset":"P2YT41H1729S"}]},"after":"2028-12-05T19:57:34.522907Z","next":"2028-12-05T20:10:57.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *","*/15 * * * *"],"timezone":"UTC"},"after":"2027-04-02T19:21:37.829761Z","next":"2027-04-02T19:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P0Y1WT9H"}],"timezone":"America/New_York"},"after":"2027-04-16T09:59:04.666378Z","next":"2027-04-17T07:00:00.000000Z","offset":"-04:00"} {"spec":{"cron_expressions":["bad cron","*/15 * * * *"],"intervals":[{"every":"PT18H231S","offset":"P1D "}],"timezone":"EST"},"after":"2028-11-05T01:22:28.342817Z","error":"InvalidArgumentException"} -{"spec":{"intervals":[{"every":"P5MT3453S"},{"every":"P2WT37M"}]},"after":"2026-05-04T07:48:00.274407Z","next":"2026-05-16T17:16:00.000000Z"} -{"spec":{"intervals":[{"every":"PT9M","offset":"P2Y"}]},"after":"2026-03-09T07:12:49.000324Z","next":"2026-03-09T07:21:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *",""],"intervals":[{"every":"PT1474S"},{"every":"P13MT28M2342S","offset":"PT6295S"}]},"after":"2026-05-10T13:27:21.459455Z","next":"2026-05-10T13:30:00.000000Z"} -{"spec":{"cron_expressions":["5 4 L * ?","0 12 29 2 *"],"intervals":[{"every":"PT25H1355S","offset":"P2WT31H"}]},"after":"2025-10-22T08:58:36.990677Z","next":"2025-10-23T01:45:20.000000Z"} -{"spec":{"cron_expressions":["@hourly"],"timezone":"Australia/Lord_Howe"},"after":"2028-01-17T08:55:20.444833Z","next":"2028-01-17T09:00:00.000000Z"} +{"spec":{"intervals":[{"every":"P5MT3453S"},{"every":"P2WT37M"}]},"after":"2026-05-04T07:48:00.274407Z","next":"2026-05-16T17:16:00.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT9M","offset":"P2Y"}]},"after":"2026-03-09T07:12:49.000324Z","next":"2026-03-09T07:21:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *",""],"intervals":[{"every":"PT1474S"},{"every":"P13MT28M2342S","offset":"PT6295S"}]},"after":"2026-05-10T13:27:21.459455Z","next":"2026-05-10T13:30:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["5 4 L * ?","0 12 29 2 *"],"intervals":[{"every":"PT25H1355S","offset":"P2WT31H"}]},"after":"2025-10-22T08:58:36.990677Z","next":"2025-10-23T01:45:20.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["@hourly"],"timezone":"Australia/Lord_Howe"},"after":"2028-01-17T08:55:20.444833Z","next":"2028-01-17T09:00:00.000000Z","offset":"+11:00"} {"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"PT1.5S"}],"timezone":"Mars/Base"},"after":"2025-05-07T15:51:22.591059Z","error":"DateInvalidTimeZoneException"} -{"spec":{"intervals":[{"every":"P0Y31DT32H6046S","offset":"P38DT19H"},{"every":"P6MT78M6815S","offset":"PT1.5S"}],"timezone":"Australia/Lord_Howe"},"after":"2027-07-15T04:53:26.159920Z","next":"2027-08-06T03:16:48.000000Z"} -{"spec":{"intervals":[{"every":"PT6849S"},{"every":"P2WT23H","offset":"P20DT19H"}]},"after":"2027-05-07T12:45:07.017482Z","next":"2027-05-07T13:46:12.000000Z"} -{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P0YT41H17M3312S"}],"timezone":"UTC"},"after":"2027-12-29T23:08:49.524608Z","next":"2027-12-30T03:00:00.000000Z"} -{"spec":{"cron_expressions":["*/15 * * * *"],"timezone":"Europe/Budapest"},"after":"2026-09-27T08:30:11.537157Z","next":"2026-09-27T08:45:00.000000Z"} -{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P0WT5H3021S"}]},"after":"2028-04-30T05:58:26.585620Z","next":"2028-04-30T10:37:45.000000Z"} +{"spec":{"intervals":[{"every":"P0Y31DT32H6046S","offset":"P38DT19H"},{"every":"P6MT78M6815S","offset":"PT1.5S"}],"timezone":"Australia/Lord_Howe"},"after":"2027-07-15T04:53:26.159920Z","next":"2027-08-06T03:16:48.000000Z","offset":"+00:00"} +{"spec":{"intervals":[{"every":"PT6849S"},{"every":"P2WT23H","offset":"P20DT19H"}]},"after":"2027-05-07T12:45:07.017482Z","next":"2027-05-07T13:46:12.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["0 3 * * *"],"intervals":[{"every":"P0YT41H17M3312S"}],"timezone":"UTC"},"after":"2027-12-29T23:08:49.524608Z","next":"2027-12-30T03:00:00.000000Z","offset":"+00:00"} +{"spec":{"cron_expressions":["*/15 * * * *"],"timezone":"Europe/Budapest"},"after":"2026-09-27T08:30:11.537157Z","next":"2026-09-27T08:45:00.000000Z","offset":"+02:00"} +{"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P0WT5H3021S"}]},"after":"2028-04-30T05:58:26.585620Z","next":"2028-04-30T10:37:45.000000Z","offset":"+00:00"} {"spec":{"cron_expressions":["0 12 29 2 *"],"timezone":""},"after":"2027-12-17T10:20:14.550543Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["0 12 29 2 *"],"intervals":[{"every":"P2YT45H41M6210S","offset":"P6MT17H75M"},{"every":"PT44H"}],"timezone":""},"after":"2028-07-05T05:13:13.359070Z","error":"DateInvalidTimeZoneException"} -{"spec":{"cron_expressions":["0 9 * * 1-5","*/15 * * * *"],"timezone":"+05:30"},"after":"2028-11-21T09:28:50.578338Z","next":"2028-11-21T09:30:00.000000Z"} +{"spec":{"cron_expressions":["0 9 * * 1-5","*/15 * * * *"],"timezone":"+05:30"},"after":"2028-11-21T09:28:50.578338Z","next":"2028-11-21T09:30:00.000000Z","offset":"+05:30"} {"spec":{"cron_expressions":["0 9 * * 1-5"],"intervals":[{"every":"P37DT6105S","offset":"PT0001H"},{"every":"PT840S","offset":"P0WT41M"}],"timezone":""},"after":"2028-03-01T10:19:48.814592Z","error":"DateInvalidTimeZoneException"} {"spec":{"cron_expressions":["bad cron"],"intervals":[{"every":"P13M1WT4544S"},{"every":"P12M"}],"timezone":"EST"},"after":"2027-12-22T21:06:27.540112Z","error":"InvalidArgumentException"} -{"spec":{"cron_expressions":[""],"intervals":[{"every":"P0WT37M","offset":"P13MT13H"}],"timezone":"America/New_York"},"after":"2025-04-21T20:58:32.363793Z","next":"2025-04-21T21:06:00.000000Z"} +{"spec":{"cron_expressions":[""],"intervals":[{"every":"P0WT37M","offset":"P13MT13H"}],"timezone":"America/New_York"},"after":"2025-04-21T20:58:32.363793Z","next":"2025-04-21T21:06:00.000000Z","offset":"+00:00"} diff --git a/scripts/conformance/cron-oracle/README.md b/scripts/conformance/cron-oracle/README.md index 5f7cc4b40..75357388e 100644 --- a/scripts/conformance/cron-oracle/README.md +++ b/scripts/conformance/cron-oracle/README.md @@ -14,6 +14,7 @@ run() { docker run --rm --pull=never --network none --user 1000:1000 --read-only run next-run.php 7 2000 | head -1200 > rust/tests/fixtures/cron/php-2.5.14-next-run.jsonl run zone-names.php > rust/tests/fixtures/cron/php-2.5.14-zone-names.jsonl run next-fire.php 5 1500 | head -600 > rust/tests/fixtures/cron/php-2.5.14-next-fire.jsonl +run backfill-dates.php 3 700 > rust/tests/fixtures/cron/php-2.5.14-backfill-dates.jsonl ``` - `next-run.php SEED COUNT`: random expressions (names, ranges, steps, lists, @@ -25,7 +26,10 @@ run next-fire.php 5 1500 | head -600 > rust/tests/fixtures/cron/php-2.5.14-next- answers for three fixed cases. - `next-fire.php SEED COUNT`: whole schedule specifications (cron expressions, intervals with offsets, zones and malformed rules) with - `WorkflowSchedule::computeNextFireAt`. + `WorkflowSchedule::computeNextFireAt` and the UTC offset of its result. +- `backfill-dates.php SEED COUNT`: backfill time strings, ISO-8601 shapes + (marked `iso`) and PHP's other spellings, with Laravel's `date` rule and + the instant `new DateTimeImmutable()` reads. The zones skipped above, and America/Edmonton, Inuvik, Vancouver and Winnipeg, have rules that changed after PHP's database. Native uses the newer diff --git a/scripts/conformance/cron-oracle/backfill-dates.php b/scripts/conformance/cron-oracle/backfill-dates.php new file mode 100644 index 000000000..66f6a9780 --- /dev/null +++ b/scripts/conformance/cron-oracle/backfill-dates.php @@ -0,0 +1,75 @@ + $a[mt_rand(0, count($a) - 1)]; +$pad = fn (int $v, int $w = 2) => str_pad((string) $v, $w, '0', STR_PAD_LEFT); +$valid = function ($value): bool { + try { + if ((! is_string($value) && ! is_numeric($value)) || strtotime($value) === false) { + return false; + } + } catch (Exception) { + return false; + } + $date = date_parse($value); + + return checkdate($date['month'], $date['day'], $date['year']); +}; +$iso = function () use ($pick, $pad): string { + $year = mt_rand(0, 5) === 0 ? $pick([1970, 1999, 2000, 2024, 2100, 2400]) : mt_rand(1971, 2099); + $month = mt_rand(0, 9) === 0 ? mt_rand(0, 13) : mt_rand(1, 12); + $day = mt_rand(0, 4) === 0 ? $pick([0, 28, 29, 30, 31, 32]) : mt_rand(1, 28); + $text = $year.'-'.$pad($month).'-'.$pad($day); + if (mt_rand(0, 5) === 0) { + return $text; + } + $hour = mt_rand(0, 9) === 0 ? $pick([0, 23, 24, 25]) : mt_rand(0, 23); + $minute = mt_rand(0, 9) === 0 ? $pick([0, 59, 60]) : mt_rand(0, 59); + $text .= $pick(['T', 'T', 'T', 't', ' ']).$pad($hour).':'.$pad($minute); + if (mt_rand(0, 4) > 0) { + $second = mt_rand(0, 9) === 0 ? $pick([0, 59, 60, 61]) : mt_rand(0, 59); + $text .= ':'.$pad($second); + if (mt_rand(0, 2) === 0) { + $text .= '.'.substr((string) mt_rand(100000000, 999999999), 0, mt_rand(1, 9)); + } + } + $zone = mt_rand(0, 9); + if ($zone < 3) { + return $text; + } + if ($zone < 6) { + return $text.$pick(['Z', 'Z', 'z']); + } + $sign = $pick(['+', '-']); + $hours = mt_rand(0, 9) === 0 ? $pick([0, 14, 15, 23, 24, 25]) : mt_rand(0, 12); + $minutes = mt_rand(0, 9) === 0 ? $pick([0, 45, 59, 60]) : $pick([0, 0, 30, 45]); + return $text.($zone === 9 ? ' ' : '').$sign.$pad($hours).$pick([':'.$pad($minutes), $pad($minutes), '']); +}; +$others = ['now', 'yesterday', 'tomorrow 05:00', 'next monday', '+1 day', '2026-04-01 +1 day', '@1700000000', + '@1700000000.5', '1700000000', '20260401', '20260401T050000Z', '2026-4-1', '2026-04-1T5:00', '2026/04/01', + '04/01/2026', '01.04.2026', '1 April 2026', 'April 1, 2026', 'Wed, 01 Apr 2026 05:00:00 GMT', + '2026-04-01T05:00:00 UTC', '2026-04-01T05:00:00 Europe/Budapest', '2026-04-01T05:00:00+05:30:00', + '2026-04-01T05:00:00.000000Z', '2026-04-01T05', '2026-04-01T', '2026-W14-3', '2026-091', '-2026-04-01', + '12026-04-01', '0000-00-00', '0001-01-01', '9999-12-31T23:59:59Z', 'garbage', 'T05:00:00', '05:00', + '2026-04-01T05:00:00ZZ', '2026-04-01T05:00:00+2', '2026-04-01T05:00:00-0', '2026-04-01 05:00:00', + '2026-04-01T05:00:00.Z', '2026-04-01T05:00:00,5Z', '2026-02-29', '2028-02-29T00:00:00Z', '2100-02-29', + '2000-02-29', '2026-04-01T05:00:00 +02:00', '2026-04-01T05:00:00+02:00 ', ' 2026-04-01', '2026-04-01T05:00:00GMT+2']; +for ($i = 0; $i < (int) $argv[2]; ++$i) { + $family = $i < count($others) ? 'other' : 'iso'; + $value = $family === 'other' ? $others[$i] : $iso(); + $case = ['value' => $value, 'iso' => $family === 'iso', 'valid' => $valid($value)]; + if ($case['valid']) { + try { + $at = new DateTimeImmutable($value); + $case['at'] = $at->format('U.u'); + } catch (Throwable $e) { + $case['error'] = get_class($e); + } + } + echo json_encode($case, JSON_UNESCAPED_SLASHES), "\n"; +} diff --git a/scripts/conformance/cron-oracle/next-fire.php b/scripts/conformance/cron-oracle/next-fire.php index 6131ac26e..76f58ff8c 100644 --- a/scripts/conformance/cron-oracle/next-fire.php +++ b/scripts/conformance/cron-oracle/next-fire.php @@ -41,6 +41,9 @@ $schedule->spec = $spec; $next = $schedule->computeNextFireAt(new Carbon\Carbon($at)); $case['next'] = $next === null ? null : Carbon\Carbon::instance($next)->utc()->format('Y-m-d\TH:i:s.u\Z'); + if ($next !== null) { + $case['offset'] = $next->format('P'); + } } catch (Throwable $e) { $case['error'] = get_class($e); } diff --git a/scripts/conformance/server-parity/contract.mjs b/scripts/conformance/server-parity/contract.mjs index f3ff6667f..3ab8b1bff 100644 --- a/scripts/conformance/server-parity/contract.mjs +++ b/scripts/conformance/server-parity/contract.mjs @@ -13,6 +13,7 @@ import {checkLateWorkflowCompletion} from './late-workflow-completion-contract.m import {checkSearchAttributes} from './search-attribute-contract.mjs'; import {checkStorageTest} from './storage-test-contract.mjs'; import {checkSchedulePolicies} from './schedule-policies-contract.mjs'; +import {checkScheduleCatalog} from './schedule-catalog-contract.mjs'; import {checkWorkerListing} from './worker-listing-contract.mjs'; import {checkWorkerReplacement} from './worker-replacement-contract.mjs'; import {checkPatchDeployment, checkPublishedPatchArtifacts, checkPatchPackageObservation} from './patch-deployment-contract.mjs'; @@ -139,6 +140,7 @@ export function checkObservation(fixture, observation, workflowId, artifacts) { const searchAttributes = fixture.search_attributes ? checkSearchAttributes(fixture, observation, workflowId) : null; const storageTest = fixture.storage_test ? checkStorageTest(fixture, observation, workflowId) : null; const schedulePolicies = fixture.schedule_policies ? checkSchedulePolicies(fixture, observation, workflowId) : null; + const scheduleCatalog = fixture.schedule_catalog ? checkScheduleCatalog(fixture, observation, workflowId) : null; const workerListing = fixture.worker_listing ? checkWorkerListing(fixture, observation, workflowId) : null; const workerReplacement = fixture.worker_replacement ? checkWorkerReplacement(fixture, observation, workflowId) : null; const patchDeployment = fixture.patch_deployment ? (fixture.patch_deployment.legacy_marker_history @@ -682,6 +684,7 @@ export function checkObservation(fixture, observation, workflowId, artifacts) { ...(searchAttributes ? {search_attributes: searchAttributes} : {}), ...(storageTest ? {storage_test: storageTest} : {}), ...(schedulePolicies ? {schedule_policies: schedulePolicies} : {}), + ...(scheduleCatalog ? {schedule_catalog: scheduleCatalog} : {}), ...(workerListing ? {worker_listing: workerListing} : {}), ...(workerReplacement ? {worker_replacement: workerReplacement} : {}), ...(patchDeployment ? {patch_deployment: patchDeployment} : {}), diff --git a/scripts/conformance/server-parity/probe.php b/scripts/conformance/server-parity/probe.php index dcd99ac1d..d13bef34b 100644 --- a/scripts/conformance/server-parity/probe.php +++ b/scripts/conformance/server-parity/probe.php @@ -431,6 +431,9 @@ function httpObservation(array $fixture, string $workflowId, string $namespace, $searchAttributes = isset($fixture['search_attributes']) ? finishHttpSearchAttributes($client, $fixture, $workflowId, $url) : null; $storageTest = isset($fixture['storage_test']) ? finishHttpStorageTest($client, $fixture, $workflowId, $url) : null; $schedulePolicies = isset($fixture['schedule_policies']) ? finishHttpSchedulePolicies($client, $fixture, $workflowId, $url) : null; + $scheduleCatalog = isset($fixture['schedule_catalog']) + ? finishHttpSchedulePolicies($client, $fixture, $workflowId, $url, 'schedule_catalog') + : null; $workerListing = isset($fixture['worker_listing']) ? finishHttpWorkerListing($client, $fixture, $workflowId) : null; $workerReplacement = isset($fixture['worker_replacement']) ? finishHttpWorkerReplacement($client, $fixture, $workflowId) : null; $waitingHistory = isset($fixture['waiting_for_history']) ? finishHttpWaitingHistory($client, $fixture, $workflowId, $queue, $url) : null; @@ -523,6 +526,7 @@ function httpObservation(array $fixture, string $workflowId, string $namespace, 'search_attributes' => $searchAttributes, 'storage_test' => $storageTest, 'schedule_policies' => $schedulePolicies, + 'schedule_catalog' => $scheduleCatalog, 'worker_listing' => $workerListing, 'worker_replacement' => $workerReplacement, 'waiting_for_history' => $waitingHistory, @@ -978,6 +982,9 @@ function embeddedObservation(array $fixture, string $workflowId, string $namespa if ($mode === 'embedded' && isset($fixture['schedule_policies'])) { $observation['schedule_policies'] = ['applicable' => false, 'reason' => 'embedded_has_no_http_schedules']; } + if ($mode === 'embedded' && isset($fixture['schedule_catalog'])) { + $observation['schedule_catalog'] = ['applicable' => false, 'reason' => 'embedded_has_no_http_schedules']; + } $observation['mode'] = $mode; $observation['typed_output'] = typedValue($observation['output']); if ($mode === 'embedded' && isset($fixture['waiting_for_history'])) { diff --git a/scripts/conformance/server-parity/schedule-catalog-contract.mjs b/scripts/conformance/server-parity/schedule-catalog-contract.mjs new file mode 100644 index 000000000..88e1d7abd --- /dev/null +++ b/scripts/conformance/server-parity/schedule-catalog-contract.mjs @@ -0,0 +1,86 @@ +import assert from 'node:assert/strict'; +import {readFileSync} from 'node:fs'; +import {normalized} from './schedule-policies-contract.mjs'; + +// Published PHP's reviewed, normalized responses to every step. +const EXPECTED = JSON.parse(readFileSync(new URL('../../../tests/Fixtures/ServerParityExpected/schedule-catalog.json', import.meta.url))); + +/// The reviewed status of each step, in order. +export const STATUSES = [201, 201, 201, 201, 200, 200, 422, 200, 422, 200, 409, 200, 422, 422, 422, 422, 400, 400, 422, 422, + 200, 200, 200, 200, 200, 422, 422, 422, 422, 422, 422, 422, 422, 422, 200, 201, 200, 422, 200, 200, 200, 409, 404, + 200, 200, 200, 200, 200, 422, 200, 200, 200, 201, 422, 422, 422, 422, 200, 200, 200, 201, 200, 200, 201, 200, 201, + 200, 404, 200, 404, 200, 200]; + +/// PHP's fire times for each backfill request, in order. Normalization +/// hides times, so these are checked raw. +const FIRE_TIMES = [[], [], [], [], + ['2026-03-27T03:00:00+01:00', '2026-03-27T06:00:00+00:00', '2026-03-28T03:00:00+01:00', '2026-03-28T06:00:00+00:00', + '2026-03-29T03:00:00+02:00', '2026-03-29T06:00:00+00:00', '2026-03-30T03:00:00+02:00'], + ['2026-03-27T03:00:00+01:00', '2026-03-27T06:00:00+00:00', '2026-03-28T03:00:00+01:00', '2026-03-28T06:00:00+00:00', + '2026-03-29T03:00:00+02:00', '2026-03-29T06:00:00+00:00', '2026-03-30T03:00:00+02:00', '2026-03-30T06:00:00+00:00'], + ['2026-01-01T00:00:00+00:00', '2026-01-02T00:00:00+00:00', '2026-01-03T00:00:00+00:00'], + ['2026-02-01T00:00:00+00:00', '2026-02-02T00:00:00+00:00'], + ['2026-01-01T00:00:00+00:00', '2026-01-02T00:00:00+00:00', '2026-01-03T00:00:00+00:00'], + ['2026-01-01T00:00:00+00:00', '2026-01-02T00:00:00+00:00'], + ['2026-01-01T03:00:00+01:00', '2026-01-02T03:00:00+01:00'], []]; + +const ids = step => step.response.schedules.map(item => item.schedule_id); + +export function checkScheduleCatalog(fixture, observation, workflowId) { + const state = observation.schedule_catalog; + assert.ok(state && typeof state === 'object', 'actual schedule catalog observation'); + if (observation.mode === 'embedded') { + assert.deepStrictEqual(state, {applicable: false, reason: 'embedded_has_no_http_schedules'}, + 'embedded schedule surface explicitly inapplicable'); + return {scope: 'schedule_catalog'}; + } + assert.ok(Number.isInteger(state.attempts) && state.attempts >= 1 && state.attempts <= 3, 'recorded sequence attempts'); + // A sequence replayed after PHP's SQLite lock defect runs in a new namespace. + const namespace = `${workflowId}-catalog`.toLowerCase() + (state.attempts === 1 ? '' : `-r${state.attempts}`); + assert.deepStrictEqual([state.applicable, state.namespace], [true, namespace], 'schedule catalog namespace'); + assert.ok(Number.isInteger(state.retries) && state.retries >= 0, 'recorded lock retries'); + const raw = state.steps; + const names = {[namespace]: '@namespace', [state.queue]: '@queue'}; + const steps = raw.map(step => ({request: step.request, status: step.status, response: normalized(step.response, names)})); + assert.deepStrictEqual(steps.map(step => step.status), STATUSES, 'schedule catalog step statuses'); + // Newest first, filtered and paged. + assert.deepStrictEqual(ids(steps[4]), ['delta', 'gamma', 'beta', 'alpha'], 'newest schedules first'); + assert.deepStrictEqual(ids(steps[5]), ['beta'], 'status filter'); + assert.deepStrictEqual(ids(steps[7]), ['delta', 'gamma', 'alpha'], 'workflow type filter'); + assert.deepStrictEqual([ids(steps[9]), ids(steps[11])], [['delta', 'gamma'], ['beta', 'alpha']], 'two pages'); + assert.equal(typeof raw[9].response.next_page_token, 'string', 'continuation token'); + assert.equal(raw[11].response.next_page_token, null, 'last page'); + assert.deepStrictEqual([steps[10].response.reason, steps[10].response.last_safe_cursor.schedule_id], + ['schedule_page_token_filter_mismatch', 'gamma'], 'token bound to its filters'); + assert.deepStrictEqual([steps[16].response.reason, steps[17].response.reason], + ['malformed_schedule_page_token', 'malformed_schedule_page_token'], 'unsigned tokens'); + assert.deepStrictEqual(steps[14].response.errors, {page_size: ['The page size field must be an integer.']}, + 'Laravel sizes a non-numeric value by its length'); + assert.deepStrictEqual(ids(steps[22]), ['gamma'], 'workflow type and task queue predicates'); + assert.deepStrictEqual(ids(steps[23]), ['gamma'], 'quoted AND inside a literal'); + assert.equal(steps[25].response.reason, 'unsupported_schedule_visibility_predicate', 'inequality refused'); + assert.equal(steps[27].response.reason, 'unsupported_schedule_visibility_field', 'unknown field refused'); + assert.deepStrictEqual([ids(steps[36]), ids(steps[38])], [[], []], 'search attribute predicates match no schedule'); + assert.equal(steps[41].response.reason, 'stale_schedule_page_token', 'deleted cursor'); + // Updates merge the stored action and record PHP's changed fields. + const alpha = steps[49].response; + assert.deepStrictEqual(alpha.action, {workflow_type: fixture.workflow_type, task_queue: 'catalog-z', + input: {codec: 'avro', blob: fixture.schedule_catalog.input_blob}, execution_timeout_seconds: 60}, 'merged action'); + assert.deepStrictEqual([alpha.overlap_policy, alpha.state.note, alpha.memo], ['allow_all', 'changed', null], 'updated fields'); + assert.deepStrictEqual(steps[50].response.events.filter(event => event.event_type === 'ScheduleUpdated') + .map(event => event.payload.changed_fields), [['spec', 'action', 'overlap_policy', 'jitter_seconds', 'note'], + ['spec', 'action'], ['spec', 'action', 'memo', 'max_runs', 'remaining_actions'], ['spec', 'action', 'memo', 'search_attributes'], + ['spec', 'action']], 'changed fields'); + assert.deepStrictEqual(ids(steps[51]), ['alpha'], 'updated task queue predicate'); + // Backfills. + assert.deepStrictEqual(raw.filter(step => step.request.endsWith('/backfill')) + .map(step => (step.response.results ?? []).map(result => result.fire_time)), FIRE_TIMES, 'backfill fire times'); + assert.equal(steps[55].response.reason, 'invalid_time_range', 'reversed range'); + assert.deepStrictEqual(steps[61].response.results.map(result => result.outcome), ['started', 'skipped', 'skipped'], + 'skip policy while the first backfilled run is open'); + assert.deepStrictEqual(steps[64].response.results.map(result => result.outcome), ['started', 'started', 'started'], + 'buffering backfills start every occurrence'); + assert.equal(steps[66].response.fires_attempted, 2, 'quota ends the backfill'); + assert.deepStrictEqual(steps, EXPECTED, 'every response matches the reviewed published PHP responses'); + return {scope: 'schedule_catalog'}; +} diff --git a/scripts/conformance/server-parity/schedule-policies-contract.mjs b/scripts/conformance/server-parity/schedule-policies-contract.mjs index d58e80f61..3f8e42905 100644 --- a/scripts/conformance/server-parity/schedule-policies-contract.mjs +++ b/scripts/conformance/server-parity/schedule-policies-contract.mjs @@ -4,17 +4,21 @@ import {readFileSync} from 'node:fs'; // Published PHP's reviewed, normalized responses to every step. const EXPECTED = JSON.parse(readFileSync(new URL('../../../tests/Fixtures/ServerParityExpected/schedule-policies.json', import.meta.url))); -// Generated identities, times, audit fingerprints, route names and peer -// addresses differ between servers and runs. Next fire times are checked on -// their own below, against the published cron corpus semantics. +// Generated identities, times, audit fingerprints, route names, peer +// addresses and signed continuation tokens differ between servers and runs. +// Next fire times are checked on their own, against the published cron +// corpus semantics. const VOLATILE = [/^\d{4}-\d{2}-\d{2}T/, /^[0-9A-Za-z]{26}$/, /^sha256:[0-9a-f]{64}$/, /^generated::/, - /^api\.schedules\./, /^\d+\.\d+\.\d+\.\d+$/]; + /^api\.schedules\./, /^\d+\.\d+\.\d+\.\d+$/, /^[A-Za-z0-9_-]{40,}\.[0-9a-f]{64}$/]; +// How late a backfilled or scheduled occurrence fired depends on the clock. +const VOLATILE_FIELDS = new Set(['fire_lag_ms']); // The run's own namespace and task queue read as placeholders, wherever they appear. export function normalized(value, names = {}) { if (Array.isArray(value)) return value.map(item => normalized(item, names)); if (value && typeof value === 'object') { - return Object.fromEntries(Object.entries(value).map(([field, item]) => [field, normalized(item, names)])); + return Object.fromEntries(Object.entries(value).map(([field, item]) => + [field, VOLATILE_FIELDS.has(field) ? '@v' : normalized(item, names)])); } if (typeof value !== 'string') return value; if (VOLATILE.some(pattern => pattern.test(value))) return '@v'; @@ -45,7 +49,9 @@ export function checkSchedulePolicies(fixture, observation, workflowId) { 'embedded schedule surface explicitly inapplicable'); return {scope: 'schedule_policies'}; } - const namespace = `${workflowId}-schedules`.toLowerCase(); + assert.ok(Number.isInteger(state.attempts) && state.attempts >= 1 && state.attempts <= 3, 'recorded sequence attempts'); + // A sequence replayed after PHP's SQLite lock defect runs in a new namespace. + const namespace = `${workflowId}-schedules`.toLowerCase() + (state.attempts === 1 ? '' : `-r${state.attempts}`); assert.deepStrictEqual([state.applicable, state.namespace], [true, namespace], 'schedule policy namespace'); assert.ok(Number.isInteger(state.retries) && state.retries >= 0, 'recorded lock retries'); const raw = state.steps; diff --git a/scripts/conformance/server-parity/schedule-policies-probe.php b/scripts/conformance/server-parity/schedule-policies-probe.php index 9bd0b7956..511ecfbe6 100644 --- a/scripts/conformance/server-parity/schedule-policies-probe.php +++ b/scripts/conformance/server-parity/schedule-policies-probe.php @@ -7,13 +7,19 @@ // The HTTP schedule surface of a fresh namespace: the fixture's request // steps, with "@policy" expanded to a schedule of that overlap policy, three -// manual triggers and a description. Responses are recorded raw; the -// contract normalizes generated identities and times. -function finishHttpSchedulePolicies(Client $admin, array $fixture, string $workflowId, string $url): array +// manual triggers and a description, and "{token}" in a path replaced by the +// last continuation token a response returned. Responses are recorded raw; +// the contract normalizes generated identities and times. +// +// Published PHP on SQLite can lose a write race with its own maintenance +// roles ("database is locked"). A 500 for that rolls the whole operation +// back, so the step is sent again. A backfill instead records the lost +// occurrence as a failure and goes on, which changes the schedule, so the +// whole sequence is replayed once more in a new namespace. Each is recorded. +function finishHttpSchedulePolicies(Client $admin, array $fixture, string $workflowId, string $url, string $key = 'schedule_policies'): array { - $definition = $fixture['schedule_policies']; - $namespace = strtolower($workflowId.'-schedules'); - $admin->createNamespace($namespace, 'schedule policies λ', 30); + $definition = $fixture[$key]; + $base = strtolower($workflowId.($key === 'schedule_policies' ? '-schedules' : '-catalog')); $queue = strtolower($workflowId.'-queue'); $input = ['codec' => 'avro', 'blob' => $definition['input_blob']]; $token = getenv('DW_PARITY_TOKEN') ?: null; @@ -30,44 +36,60 @@ function finishHttpSchedulePolicies(Client $admin, array $fixture, string $workf return is_array($value) ? array_map($fill, $value) : $value; }; $retries = 0; - $send = static function (string $method, string $path, mixed $body = null) use ($http, $token, $namespace, &$retries): array { - for ($attempt = 1; ; $attempt++) { - $response = $http->request($method, $path, ['headers' => array_filter([ - 'Authorization' => $token === null ? null : 'Bearer '.$token, - 'Accept' => 'application/json', 'X-Namespace' => $namespace, - 'X-Durable-Workflow-Control-Plane-Version' => '2', - ]), ...($body === null ? [] : ['json' => $body === [] ? (object) [] : $body])]); - $text = (string) $response->getBody(); - // Published PHP on SQLite can lose a write race with its own - // maintenance roles. The whole operation rolls back first. - if ($response->getStatusCode() === 500 && str_contains($text, 'database is locked') && $attempt < 5) { - $retries++; - usleep(200000 * $attempt); + for ($attempt = 1; ; $attempt++) { + $namespace = $attempt === 1 ? $base : "$base-r$attempt"; + $admin->createNamespace($namespace, 'schedule policies λ', 30); + $pageToken = ''; + $send = static function (string $method, string $path, mixed $body = null) use ($http, $token, $namespace, &$retries, &$pageToken): array { + $target = str_replace('{token}', rawurlencode($pageToken), $path); + for ($try = 1; ; $try++) { + $response = $http->request($method, $target, ['headers' => array_filter([ + 'Authorization' => $token === null ? null : 'Bearer '.$token, + 'Accept' => 'application/json', 'X-Namespace' => $namespace, + 'X-Durable-Workflow-Control-Plane-Version' => '2', + ]), ...($body === null ? [] : ['json' => $body === [] ? (object) [] : $body])]); + $text = (string) $response->getBody(); + if ($response->getStatusCode() === 500 && str_contains($text, 'database is locked') && $try < 5) { + $retries++; + usleep(200000 * $try); - continue; + continue; + } + $decoded = json_decode($text, true, flags: JSON_THROW_ON_ERROR); + if (is_string($decoded['next_page_token'] ?? null)) { + $pageToken = $decoded['next_page_token']; + } + + return ['request' => "$method $path", 'status' => $response->getStatusCode(), 'response' => $decoded]; } + }; + $steps = []; + $locked = false; + foreach ($definition['steps'] as $step) { + if ($step[0] === '@policy') { + $policy = $step[1]; + $id = 'policy-'.str_replace('_', '-', $policy); + $steps[] = $send('POST', 'schedules', ['schedule_id' => $id, 'spec' => ['cron_expressions' => ['0 0 1 1 *']], + 'action' => ['workflow_type' => $fixture['workflow_type'], 'task_queue' => $queue, 'input' => $input], + 'overlap_policy' => $policy]); + for ($trigger = 0; $trigger < 3; $trigger++) { + $steps[] = $send('POST', "schedules/$id/trigger", []); + } + $steps[] = $send('GET', "schedules/$id"); - return ['request' => "$method $path", 'status' => $response->getStatusCode(), - 'response' => json_decode($text, true, flags: JSON_THROW_ON_ERROR)]; - } - }; - $steps = []; - foreach ($definition['steps'] as $step) { - if ($step[0] === '@policy') { - $policy = $step[1]; - $id = 'policy-'.str_replace('_', '-', $policy); - $steps[] = $send('POST', 'schedules', ['schedule_id' => $id, 'spec' => ['cron_expressions' => ['0 0 1 1 *']], - 'action' => ['workflow_type' => $fixture['workflow_type'], 'task_queue' => $queue, 'input' => $input], - 'overlap_policy' => $policy]); - for ($trigger = 0; $trigger < 3; $trigger++) { - $steps[] = $send('POST', "schedules/$id/trigger", []); + continue; } - $steps[] = $send('GET', "schedules/$id"); + $steps[] = $send($step[0], $step[1], array_key_exists(2, $step) ? $fill($step[2]) : null); + $last = end($steps); + if ($last['status'] !== 500 && str_contains(json_encode($last['response']), 'database is locked')) { + $locked = true; - continue; + break; + } + } + if (! $locked || $attempt === 3) { + return ['applicable' => true, 'namespace' => $namespace, 'queue' => $queue, 'retries' => $retries, + 'attempts' => $attempt, 'steps' => $steps]; } - $steps[] = $send($step[0], $step[1], array_key_exists(2, $step) ? $fill($step[2]) : null); } - - return ['applicable' => true, 'namespace' => $namespace, 'queue' => $queue, 'retries' => $retries, 'steps' => $steps]; } diff --git a/tests/Fixtures/ServerParity/schedule-catalog.json b/tests/Fixtures/ServerParity/schedule-catalog.json new file mode 100644 index 000000000..0ecee07ff --- /dev/null +++ b/tests/Fixtures/ServerParity/schedule-catalog.json @@ -0,0 +1,88 @@ +{ + "schema": "durable-workflow.server-parity-fixture/v1", + "id": "schedule-catalog", + "review_state": "reviewed", + "workflow_type": "parity.v1.echo", + "input": {"message": "schedule catalog λ", "count": 9007199254740993, "optional": null}, + "typed_value": {"type": "map", "value": {"message": {"type": "string", "value": "schedule catalog λ"}, "count": {"type": "int64", "value": "9007199254740993"}, "optional": {"type": "null", "value": null}}}, + "activity": false, + "expected_events": ["StartAccepted", "WorkflowStarted", "WorkflowCompleted"], + "schedule_catalog": { + "input_blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==", + "steps": [ + ["POST", "schedules", {"schedule_id": "alpha", "spec": {"intervals": [{"every": "P1D"}]}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "@queue", "input": "@input"}, "note": "first"}], + ["POST", "schedules", {"schedule_id": "beta", "spec": {"cron_expressions": ["0 3 * * *"], "timezone": "Europe/Budapest"}, "action": {"workflow_type": "parity.v1.other", "task_queue": "@queue", "input": "@input"}, "paused": true}], + ["POST", "schedules", {"schedule_id": "gamma", "spec": {"intervals": [{"every": "P1D"}]}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "catalog-b", "input": "@input"}, "note": "x AND y"}], + ["POST", "schedules", {"schedule_id": "delta", "spec": {"intervals": [{"every": "P1D"}]}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "@queue", "input": "@input"}}], + ["GET", "schedules"], + ["GET", "schedules?status=paused"], + ["GET", "schedules?status=deleted"], + ["GET", "schedules?workflow_type=parity.v1.echo"], + ["GET", "schedules?workflow_type=%20"], + ["GET", "schedules?page_size=2"], + ["GET", "schedules?page_size=2&status=active&next_page_token={token}"], + ["GET", "schedules?page_size=2&next_page_token={token}"], + ["GET", "schedules?page_size=0"], + ["GET", "schedules?page_size=201"], + ["GET", "schedules?page_size=x"], + ["GET", "schedules?page_size=2.5"], + ["GET", "schedules?next_page_token=garbage"], + ["GET", "schedules?next_page_token=eyJ2ZXJzaW9uIjoxfQ.0000000000000000000000000000000000000000000000000000000000000000"], + ["GET", "schedules?bogus=1"], + ["GET", "schedules?status[]=active"], + ["GET", "schedules?status=active&status=paused"], + ["GET", "schedules?query=Status%20%3D%20%27paused%27"], + ["GET", "schedules?query=WorkflowType%20%3D%20%22parity.v1.echo%22%20AND%20TaskQueue%20%3D%20%27catalog-b%27"], + ["GET", "schedules?query=Note%20%3D%20%27x%20AND%20y%27"], + ["GET", "schedules?query=ScheduleId%20%3D%20%27alpha%27%20and%20Status%20%3D%20%22active%22"], + ["GET", "schedules?query=Status%20%21%3D%20%27active%27"], + ["GET", "schedules?query=Status%20%3D%20%27a%27%20OR%20Note%20%3D%20%27b%27"], + ["GET", "schedules?query=Owner%20%3D%20%27x%27"], + ["GET", "schedules?query=ScheduleId%20%3D%2001"], + ["GET", "schedules?query=Status%20%3D%20%27deleted%27"], + ["GET", "schedules?query=Note%20%3D%20%27open"], + ["GET", "schedules?query=AND%20Note%20%3D%20%27x%27"], + ["GET", "schedules?query=Note%20%27x%27"], + ["GET", "schedules?query=Note%20%3D%20true"], + ["GET", "schedules?query=Note%20%3D%20%27it%5C%27s%27"], + ["POST", "search-attributes", {"name": "Team", "type": "keyword"}], + ["GET", "schedules?query=Team%20%3D%20%27x%27"], + ["GET", "schedules?query=Team%20%3D%205"], + ["GET", "schedules?query=Status%20%3D%20%27active%27%20AND%20Team%20%3D%20%27x%27"], + ["GET", "schedules?page_size=1"], + ["DELETE", "schedules/delta"], + ["GET", "schedules?page_size=1&next_page_token={token}"], + ["PUT", "schedules/missing", {"note": "x"}], + ["PUT", "schedules/alpha", {"note": "changed", "overlap_policy": "allow_all", "jitter_seconds": "0"}], + ["PUT", "schedules/alpha", {"spec": {"cron_expressions": ["0 4 * * *"], "timezone": "America/New_York"}, "action": {"task_queue": "catalog-z", "workflow_execution_timeout": 60}}], + ["PUT", "schedules/alpha", {"memo": {"k": "λ"}, "max_runs": 5}], + ["PUT", "schedules/alpha", {"memo": null, "search_attributes": null}], + ["PUT", "schedules/alpha", {}], + ["PUT", "schedules/alpha", {"overlap_policy": "bad", "jitter_seconds": 4000, "max_runs": 0, "note": 7, "spec": "x", "action": {"workflow_type": 5}}], + ["GET", "schedules/alpha"], + ["GET", "schedules/alpha/history?limit=20"], + ["GET", "schedules?query=TaskQueue%20%3D%20%27catalog-z%27"], + ["POST", "schedules", {"schedule_id": "bf", "spec": {"cron_expressions": ["0 3 * * *"], "intervals": [{"every": "P1D", "offset": "PT6H"}], "timezone": "Europe/Budapest"}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "@queue", "input": "@input"}, "overlap_policy": "allow_all"}], + ["POST", "schedules/bf/backfill", {}], + ["POST", "schedules/bf/backfill", {"start_time": "yesterday", "end_time": ["x"], "overlap_policy": "never"}], + ["POST", "schedules/bf/backfill", {"start_time": "2026-03-28T00:00:00Z", "end_time": "2026-03-27T00:00:00Z"}], + ["POST", "schedules/bf/backfill", {"start_time": "2026-03-28T00:00:00Z", "end_time": "2026-03-28T00:00:00+00:00"}], + ["POST", "schedules/bf/backfill", {"start_time": "2026-03-27T00:00:00Z", "end_time": "2026-03-30 06:00:00+02:00"}], + ["POST", "schedules/bf/backfill", {"start_time": "2026-03-27", "end_time": "2026-03-31t00:00z"}], + ["GET", "schedules/bf"], + ["POST", "schedules", {"schedule_id": "bf-skip", "spec": {"intervals": [{"every": "P1D"}]}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "@queue", "input": "@input"}, "overlap_policy": "skip"}], + ["POST", "schedules/bf-skip/backfill", {"start_time": "2026-01-01T00:00:00Z", "end_time": "2026-01-04T00:00:00Z"}], + ["POST", "schedules/bf-skip/backfill", {"start_time": "2026-02-01T00:00:00Z", "end_time": "2026-02-03T00:00:00Z", "overlap_policy": "terminate_other"}], + ["POST", "schedules", {"schedule_id": "bf-buffer", "spec": {"intervals": [{"every": "P1D"}]}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "@queue", "input": "@input"}, "overlap_policy": "buffer_one"}], + ["POST", "schedules/bf-buffer/backfill", {"start_time": "2026-01-01T00:00:00Z", "end_time": "2026-01-04T00:00:00Z"}], + ["POST", "schedules", {"schedule_id": "bf-quota", "spec": {"intervals": [{"every": "P1D"}]}, "action": {"workflow_type": "parity.v1.echo", "task_queue": "@queue", "input": "@input"}, "overlap_policy": "allow_all", "max_runs": 2}], + ["POST", "schedules/bf-quota/backfill", {"start_time": "2026-01-01T00:00:00Z", "end_time": "2026-01-06T00:00:00Z"}], + ["GET", "schedules/bf-quota"], + ["POST", "schedules/beta/backfill", {"start_time": "2026-01-01T00:00:00Z", "end_time": "2026-01-03T00:00:00Z"}], + ["POST", "schedules/missing/backfill", {"start_time": "2026-01-01T00:00:00Z", "end_time": "2026-01-03T00:00:00Z"}], + ["GET", "schedules/bf-skip/history?limit=20"], + ["GET", "schedules?page_size=10"] + ] + }, + "contract": "Listing, updating and backfilling schedules in a fresh namespace. Listing covers the status and workflow type filters, the visibility query (equality predicates joined by AND on schedule fields and registered search attributes, which no schedule holds) and its refusals, unsupported filters and Laravel's messages, and signed continuation tokens with filter-mismatch, malformed and stale-cursor refusals. Updates cover merged actions, specifications in another zone, memo, quotas and PHP's changed fields. Backfills cover validation, an empty or reversed range, every cron and interval occurrence in a range across a daylight-saving change with PHP's fire times, repeated occurrences, skip, terminate_other and buffering policies, a two-run quota and a paused schedule. Every response matches published PHP's apart from generated identities, wall-clock times, fire lags and continuation token bytes. Published PHP on SQLite can lose a backfilled occurrence to database is locked against its own maintenance roles and records it as a failure; the probe then replays the whole sequence in a new namespace, which native must never need. Native accepts the ISO-8601 time forms only, and answers an update to an unevaluable specification with 422 where PHP returns 500; neither case is in this fixture. Embedded applications have no HTTP schedule surface." +} diff --git a/tests/Fixtures/ServerParity/schedule-policies.json b/tests/Fixtures/ServerParity/schedule-policies.json index 8a6f3c1d4..ab5ebd056 100644 --- a/tests/Fixtures/ServerParity/schedule-policies.json +++ b/tests/Fixtures/ServerParity/schedule-policies.json @@ -52,5 +52,5 @@ ["GET", "schedules/policy-skip/history?after_sequence=7"] ] }, - "contract": "The HTTP schedule surface of a fresh namespace. Laravel validation names, messages and counts for creation; duplicate, invalid-cron and empty-spec refusals; a yearly cron schedule in Europe/Budapest and a paused buffer_all schedule mixing two cron expressions with an offset interval in America/New_York, each with PHP's next fire time; pausing and resuming with notes; manual triggers of all six overlap policies three times while no worker runs the started workflows, with buffering, a full buffer and closing the other run; a two-run quota that deletes the schedule; an overlap override, pausing twice and a skipped paused trigger; history pages; and deletion. Every response matches published PHP's apart from generated identities and wall-clock times other than next fire times. Published PHP on SQLite can fail a trigger with database is locked against its own maintenance roles; the whole trigger rolls back, so the probe retries exactly that failure, which native must never need. Scheduler-driven fires, update, listing and backfill are separate fixtures. Embedded applications have no HTTP schedule surface." + "contract": "The HTTP schedule surface of a fresh namespace. Laravel validation names, messages and counts for creation; duplicate, invalid-cron and empty-spec refusals; a yearly cron schedule in Europe/Budapest and a paused buffer_all schedule mixing two cron expressions with an offset interval in America/New_York, each with PHP's next fire time; pausing and resuming with notes; manual triggers of all six overlap policies three times while no worker runs the started workflows, with buffering, a full buffer and closing the other run; a two-run quota that deletes the schedule; an overlap override, pausing twice and a skipped paused trigger; history pages; and deletion. Every response matches published PHP's apart from generated identities and wall-clock times other than next fire times. Published PHP on SQLite can fail a trigger with database is locked against its own maintenance roles; the whole trigger rolls back, so the probe retries exactly that failure, and replays the whole sequence in a new namespace when a response records it instead, which native must never need. Scheduler-driven fires, update, listing and backfill are separate fixtures. Embedded applications have no HTTP schedule surface." } diff --git a/tests/Fixtures/ServerParityExpected/schedule-catalog.json b/tests/Fixtures/ServerParityExpected/schedule-catalog.json new file mode 100644 index 000000000..bdefaf3aa --- /dev/null +++ b/tests/Fixtures/ServerParityExpected/schedule-catalog.json @@ -0,0 +1,3077 @@ +[ + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "alpha", + "outcome": "created" + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "beta", + "outcome": "created" + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "gamma", + "outcome": "created" + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "delta", + "outcome": "created" + } + }, + { + "request": "GET schedules", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "delta", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "gamma", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "x AND y", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-b", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "beta", + "workflow_type": "parity.v1.other", + "status": "paused", + "paused": true, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.other", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "alpha", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "first", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 4, + "next_page_token": null + } + }, + { + "request": "GET schedules?status=paused", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "beta", + "workflow_type": "parity.v1.other", + "status": "paused", + "paused": true, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.other", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "GET schedules?status=deleted", + "status": 422, + "response": { + "message": "The selected status is invalid.", + "reason": "validation_failed", + "field": "status", + "errors": { + "status": [ + "The selected status is invalid." + ] + }, + "validation_errors": { + "status": [ + "The selected status is invalid." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?workflow_type=parity.v1.echo", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "delta", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "gamma", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "x AND y", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-b", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "alpha", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "first", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 3, + "next_page_token": null + } + }, + { + "request": "GET schedules?workflow_type=%20", + "status": 422, + "response": { + "message": "The workflow type field is required.", + "reason": "validation_failed", + "field": "workflow_type", + "errors": { + "workflow_type": [ + "The workflow type field is required." + ] + }, + "validation_errors": { + "workflow_type": [ + "The workflow type field is required." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?page_size=2", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "delta", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "gamma", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "x AND y", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-b", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 2, + "next_page_token": "@v" + } + }, + { + "request": "GET schedules?page_size=2&status=active&next_page_token={token}", + "status": 409, + "response": { + "message": "Schedule continuation token must be reused with the same status, workflow type, and visibility query.", + "reason": "schedule_page_token_filter_mismatch", + "field": "next_page_token", + "errors": { + "next_page_token": [ + "Schedule continuation token must be reused with the same status, workflow type, and visibility query." + ] + }, + "validation_errors": { + "next_page_token": [ + "Schedule continuation token must be reused with the same status, workflow type, and visibility query." + ] + }, + "last_safe_cursor": { + "created_at": "@v", + "schedule_id": "gamma" + } + } + }, + { + "request": "GET schedules?page_size=2&next_page_token={token}", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "beta", + "workflow_type": "parity.v1.other", + "status": "paused", + "paused": true, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.other", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "alpha", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "first", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 2, + "next_page_token": null + } + }, + { + "request": "GET schedules?page_size=0", + "status": 422, + "response": { + "message": "The page size field must be at least 1.", + "reason": "validation_failed", + "field": "page_size", + "errors": { + "page_size": [ + "The page size field must be at least 1." + ] + }, + "validation_errors": { + "page_size": [ + "The page size field must be at least 1." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?page_size=201", + "status": 422, + "response": { + "message": "The page size field must not be greater than 200.", + "reason": "validation_failed", + "field": "page_size", + "errors": { + "page_size": [ + "The page size field must not be greater than 200." + ] + }, + "validation_errors": { + "page_size": [ + "The page size field must not be greater than 200." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?page_size=x", + "status": 422, + "response": { + "message": "The page size field must be an integer.", + "reason": "validation_failed", + "field": "page_size", + "errors": { + "page_size": [ + "The page size field must be an integer." + ] + }, + "validation_errors": { + "page_size": [ + "The page size field must be an integer." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?page_size=2.5", + "status": 422, + "response": { + "message": "The page size field must be an integer.", + "reason": "validation_failed", + "field": "page_size", + "errors": { + "page_size": [ + "The page size field must be an integer." + ] + }, + "validation_errors": { + "page_size": [ + "The page size field must be an integer." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?next_page_token=garbage", + "status": 400, + "response": { + "message": "Schedule continuation token is malformed or has an invalid signature.", + "reason": "malformed_schedule_page_token", + "field": "next_page_token", + "errors": { + "next_page_token": [ + "Schedule continuation token is malformed or has an invalid signature." + ] + }, + "validation_errors": { + "next_page_token": [ + "Schedule continuation token is malformed or has an invalid signature." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?next_page_token=eyJ2ZXJzaW9uIjoxfQ.0000000000000000000000000000000000000000000000000000000000000000", + "status": 400, + "response": { + "message": "Schedule continuation token is malformed or has an invalid signature.", + "reason": "malformed_schedule_page_token", + "field": "next_page_token", + "errors": { + "next_page_token": [ + "Schedule continuation token is malformed or has an invalid signature." + ] + }, + "validation_errors": { + "next_page_token": [ + "Schedule continuation token is malformed or has an invalid signature." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?bogus=1", + "status": 422, + "response": { + "message": "Schedule list filter [bogus] is not supported.", + "reason": "unsupported_schedule_list_filter", + "field": "bogus", + "errors": { + "bogus": [ + "Schedule list filter [bogus] is not supported." + ] + }, + "validation_errors": { + "bogus": [ + "Schedule list filter [bogus] is not supported." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?status[]=active", + "status": 422, + "response": { + "message": "The status field must be a string.", + "reason": "validation_failed", + "field": "status", + "errors": { + "status": [ + "The status field must be a string.", + "The selected status is invalid." + ] + }, + "validation_errors": { + "status": [ + "The status field must be a string.", + "The selected status is invalid." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?status=active&status=paused", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "beta", + "workflow_type": "parity.v1.other", + "status": "paused", + "paused": true, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.other", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "GET schedules?query=Status%20%3D%20%27paused%27", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "beta", + "workflow_type": "parity.v1.other", + "status": "paused", + "paused": true, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.other", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "GET schedules?query=WorkflowType%20%3D%20%22parity.v1.echo%22%20AND%20TaskQueue%20%3D%20%27catalog-b%27", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "gamma", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "x AND y", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-b", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "GET schedules?query=Note%20%3D%20%27x%20AND%20y%27", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "gamma", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "x AND y", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-b", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "GET schedules?query=ScheduleId%20%3D%20%27alpha%27%20and%20Status%20%3D%20%22active%22", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "alpha", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "first", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "GET schedules?query=Status%20%21%3D%20%27active%27", + "status": 422, + "response": { + "message": "Schedule visibility supports only equality predicates joined by AND.", + "reason": "unsupported_schedule_visibility_predicate", + "field": "query", + "errors": { + "query": [ + "Schedule visibility supports only equality predicates joined by AND." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility supports only equality predicates joined by AND." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Status%20%3D%20%27a%27%20OR%20Note%20%3D%20%27b%27", + "status": 422, + "response": { + "message": "Schedule visibility supports only equality predicates joined by AND.", + "reason": "unsupported_schedule_visibility_predicate", + "field": "query", + "errors": { + "query": [ + "Schedule visibility supports only equality predicates joined by AND." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility supports only equality predicates joined by AND." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Owner%20%3D%20%27x%27", + "status": 422, + "response": { + "message": "Schedule visibility field [Owner] is not searchable. Use ScheduleId, Status, WorkflowType, TaskQueue, Note, or a registered search attribute.", + "reason": "unsupported_schedule_visibility_field", + "field": "query", + "errors": { + "query": [ + "Schedule visibility field [Owner] is not searchable. Use ScheduleId, Status, WorkflowType, TaskQueue, Note, or a registered search attribute." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility field [Owner] is not searchable. Use ScheduleId, Status, WorkflowType, TaskQueue, Note, or a registered search attribute." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=ScheduleId%20%3D%2001", + "status": 422, + "response": { + "message": "Schedule visibility literal [01] must be a quoted string, number, or boolean.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility literal [01] must be a quoted string, number, or boolean." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility literal [01] must be a quoted string, number, or boolean." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Status%20%3D%20%27deleted%27", + "status": 422, + "response": { + "message": "Schedule visibility field [Status] requires a quoted active or paused literal.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility field [Status] requires a quoted active or paused literal." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility field [Status] requires a quoted active or paused literal." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Note%20%3D%20%27open", + "status": 422, + "response": { + "message": "Schedule visibility query contains an unterminated string or empty predicate.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility query contains an unterminated string or empty predicate." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility query contains an unterminated string or empty predicate." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=AND%20Note%20%3D%20%27x%27", + "status": 422, + "response": { + "message": "Schedule visibility query contains an unterminated string or empty predicate.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility query contains an unterminated string or empty predicate." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility query contains an unterminated string or empty predicate." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Note%20%27x%27", + "status": 422, + "response": { + "message": "Schedule visibility predicates must use: Field = literal.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility predicates must use: Field = literal." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility predicates must use: Field = literal." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Note%20%3D%20true", + "status": 422, + "response": { + "message": "Schedule visibility field [Note] requires a quoted string literal.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility field [Note] requires a quoted string literal." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility field [Note] requires a quoted string literal." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Note%20%3D%20%27it%5C%27s%27", + "status": 200, + "response": { + "schedules": [], + "schedule_count": 0, + "next_page_token": null + } + }, + { + "request": "POST search-attributes", + "status": 201, + "response": { + "name": "Team", + "type": "keyword", + "outcome": "created" + } + }, + { + "request": "GET schedules?query=Team%20%3D%20%27x%27", + "status": 200, + "response": { + "schedules": [], + "schedule_count": 0, + "next_page_token": null + } + }, + { + "request": "GET schedules?query=Team%20%3D%205", + "status": 422, + "response": { + "message": "Schedule visibility field [Team] requires a quoted string literal.", + "reason": "invalid_schedule_visibility_query", + "field": "query", + "errors": { + "query": [ + "Schedule visibility field [Team] requires a quoted string literal." + ] + }, + "validation_errors": { + "query": [ + "Schedule visibility field [Team] requires a quoted string literal." + ] + }, + "last_safe_cursor": null + } + }, + { + "request": "GET schedules?query=Status%20%3D%20%27active%27%20AND%20Team%20%3D%20%27x%27", + "status": 200, + "response": { + "schedules": [], + "schedule_count": 0, + "next_page_token": null + } + }, + { + "request": "GET schedules?page_size=1", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "delta", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + } + ], + "schedule_count": 1, + "next_page_token": "@v" + } + }, + { + "request": "DELETE schedules/delta", + "status": 200, + "response": { + "schedule_id": "delta", + "outcome": "deleted" + } + }, + { + "request": "GET schedules?page_size=1&next_page_token={token}", + "status": 409, + "response": { + "message": "Schedule continuation token cursor is no longer present in the unchanged filtered set. Restart pagination without a token.", + "reason": "stale_schedule_page_token", + "field": "next_page_token", + "errors": { + "next_page_token": [ + "Schedule continuation token cursor is no longer present in the unchanged filtered set. Restart pagination without a token." + ] + }, + "validation_errors": { + "next_page_token": [ + "Schedule continuation token cursor is no longer present in the unchanged filtered set. Restart pagination without a token." + ] + }, + "last_safe_cursor": { + "created_at": "@v", + "schedule_id": "delta" + } + } + }, + { + "request": "PUT schedules/missing", + "status": 404, + "response": { + "message": "Schedule [missing] not found in namespace [@namespace].", + "reason": "schedule_not_found" + } + }, + { + "request": "PUT schedules/alpha", + "status": 200, + "response": { + "schedule_id": "alpha", + "outcome": "updated" + } + }, + { + "request": "PUT schedules/alpha", + "status": 200, + "response": { + "schedule_id": "alpha", + "outcome": "updated" + } + }, + { + "request": "PUT schedules/alpha", + "status": 200, + "response": { + "schedule_id": "alpha", + "outcome": "updated" + } + }, + { + "request": "PUT schedules/alpha", + "status": 200, + "response": { + "schedule_id": "alpha", + "outcome": "updated" + } + }, + { + "request": "PUT schedules/alpha", + "status": 200, + "response": { + "schedule_id": "alpha", + "outcome": "updated" + } + }, + { + "request": "PUT schedules/alpha", + "status": 422, + "response": { + "message": "The spec field must be an array. (and 5 more errors)", + "reason": "validation_failed", + "errors": { + "spec": [ + "The spec field must be an array." + ], + "action.workflow_type": [ + "The action.workflow type field must be a string." + ], + "overlap_policy": [ + "The selected overlap policy is invalid." + ], + "jitter_seconds": [ + "The jitter seconds field must not be greater than 3600." + ], + "max_runs": [ + "The max runs field must be at least 1." + ], + "note": [ + "The note field must be a string." + ] + }, + "validation_errors": { + "spec": [ + "The spec field must be an array." + ], + "action.workflow_type": [ + "The action.workflow type field must be a string." + ], + "overlap_policy": [ + "The selected overlap policy is invalid." + ], + "jitter_seconds": [ + "The jitter seconds field must not be greater than 3600." + ], + "max_runs": [ + "The max runs field must be at least 1." + ], + "note": [ + "The note field must be a string." + ] + } + } + }, + { + "request": "GET schedules/alpha", + "status": 200, + "response": { + "schedule_id": "alpha", + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "overlap_policy": "allow_all", + "state": { + "status": "active", + "paused": false, + "note": "changed" + }, + "info": { + "next_fire": "@v", + "last_fire": null, + "fires_count": 0, + "failures_count": 0, + "recent_actions": [], + "buffered_actions": [], + "skipped_trigger_count": 0, + "last_skip_reason": null, + "last_skipped_at": null + }, + "memo": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "namespace": "@namespace", + "status": "active", + "paused": false, + "note": "changed", + "fires_count": 0, + "failures_count": 0, + "next_fire_at": "@v", + "last_fired_at": null, + "paused_at": null, + "jitter_seconds": 0, + "max_runs": 5, + "remaining_actions": 5, + "latest_workflow_instance_id": null + } + }, + { + "request": "GET schedules/alpha/history?limit=20", + "status": 200, + "response": { + "schedule_id": "alpha", + "namespace": "@namespace", + "events": [ + { + "id": "@v", + "sequence": 1, + "event_type": "ScheduleCreated", + "payload": { + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "overlap_policy": "skip", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "alpha", + "command": "schedule.create", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "alpha", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0, + "note": "first" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 2, + "event_type": "ScheduleUpdated", + "payload": { + "changed_fields": [ + "spec", + "action", + "overlap_policy", + "jitter_seconds", + "note" + ], + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "PUT", + "path": "/api/schedules/alpha", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "alpha", + "command": "schedule.update", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "alpha", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0, + "note": "changed" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 3, + "event_type": "ScheduleUpdated", + "payload": { + "changed_fields": [ + "spec", + "action" + ], + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "PUT", + "path": "/api/schedules/alpha", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "alpha", + "command": "schedule.update", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "alpha", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0, + "note": "changed" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 4, + "event_type": "ScheduleUpdated", + "payload": { + "changed_fields": [ + "spec", + "action", + "memo", + "max_runs", + "remaining_actions" + ], + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "PUT", + "path": "/api/schedules/alpha", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "alpha", + "command": "schedule.update", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "alpha", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0, + "note": "changed" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 5, + "event_type": "ScheduleUpdated", + "payload": { + "changed_fields": [ + "spec", + "action", + "memo", + "search_attributes" + ], + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "PUT", + "path": "/api/schedules/alpha", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "alpha", + "command": "schedule.update", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "alpha", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0, + "note": "changed" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 6, + "event_type": "ScheduleUpdated", + "payload": { + "changed_fields": [ + "spec", + "action" + ], + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "PUT", + "path": "/api/schedules/alpha", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "alpha", + "command": "schedule.update", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "alpha", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "allow_all", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0, + "note": "changed" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + } + ], + "next_cursor": null, + "has_more": false + } + }, + { + "request": "GET schedules?query=TaskQueue%20%3D%20%27catalog-z%27", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "alpha", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "allow_all", + "note": "changed", + "namespace": "@namespace", + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0, + "max_runs": 5, + "remaining_actions": 5 + } + ], + "schedule_count": 1, + "next_page_token": null + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "bf", + "outcome": "created" + } + }, + { + "request": "POST schedules/bf/backfill", + "status": 422, + "response": { + "message": "The start time field is required. (and 1 more error)", + "reason": "validation_failed", + "errors": { + "start_time": [ + "The start time field is required." + ], + "end_time": [ + "The end time field is required." + ] + }, + "validation_errors": { + "start_time": [ + "The start time field is required." + ], + "end_time": [ + "The end time field is required." + ] + } + } + }, + { + "request": "POST schedules/bf/backfill", + "status": 422, + "response": { + "message": "The start time field must be a valid date. (and 2 more errors)", + "reason": "validation_failed", + "errors": { + "start_time": [ + "The start time field must be a valid date." + ], + "end_time": [ + "The end time field must be a valid date." + ], + "overlap_policy": [ + "The selected overlap policy is invalid." + ] + }, + "validation_errors": { + "start_time": [ + "The start time field must be a valid date." + ], + "end_time": [ + "The end time field must be a valid date." + ], + "overlap_policy": [ + "The selected overlap policy is invalid." + ] + } + } + }, + { + "request": "POST schedules/bf/backfill", + "status": 422, + "response": { + "message": "end_time must be after start_time.", + "reason": "invalid_time_range" + } + }, + { + "request": "POST schedules/bf/backfill", + "status": 422, + "response": { + "message": "end_time must be after start_time.", + "reason": "invalid_time_range" + } + }, + { + "request": "POST schedules/bf/backfill", + "status": 200, + "response": { + "schedule_id": "bf", + "outcome": "backfill_started", + "fires_attempted": 7, + "results": [ + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + } + ] + } + }, + { + "request": "POST schedules/bf/backfill", + "status": 200, + "response": { + "schedule_id": "bf", + "outcome": "backfill_started", + "fires_attempted": 8, + "results": [ + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + } + ] + } + }, + { + "request": "GET schedules/bf", + "status": 200, + "response": { + "schedule_id": "bf", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ], + "intervals": [ + { + "every": "P1D", + "offset": "PT6H" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "overlap_policy": "allow_all", + "state": { + "status": "active", + "paused": false, + "note": null + }, + "info": { + "next_fire": "@v", + "last_fire": "@v", + "fires_count": 8, + "failures_count": 0, + "recent_actions": [ + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + }, + { + "workflow_id": "@v", + "run_id": "@v", + "outcome": "backfilled", + "fired_at": "@v", + "occurrence_time": "@v", + "fire_lag_ms": "@v" + } + ], + "buffered_actions": [], + "skipped_trigger_count": 7, + "last_skip_reason": "already_fired_occurrence", + "last_skipped_at": "@v" + }, + "memo": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "namespace": "@namespace", + "status": "active", + "paused": false, + "note": null, + "fires_count": 8, + "failures_count": 0, + "next_fire_at": "@v", + "last_fired_at": "@v", + "paused_at": null, + "jitter_seconds": 0, + "max_runs": null, + "remaining_actions": null, + "latest_workflow_instance_id": "@v" + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "bf-skip", + "outcome": "created" + } + }, + { + "request": "POST schedules/bf-skip/backfill", + "status": 200, + "response": { + "schedule_id": "bf-skip", + "outcome": "backfill_started", + "fires_attempted": 3, + "results": [ + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + } + ] + } + }, + { + "request": "POST schedules/bf-skip/backfill", + "status": 200, + "response": { + "schedule_id": "bf-skip", + "outcome": "backfill_started", + "fires_attempted": 2, + "results": [ + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + } + ] + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "bf-buffer", + "outcome": "created" + } + }, + { + "request": "POST schedules/bf-buffer/backfill", + "status": 200, + "response": { + "schedule_id": "bf-buffer", + "outcome": "backfill_started", + "fires_attempted": 3, + "results": [ + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + } + ] + } + }, + { + "request": "POST schedules", + "status": 201, + "response": { + "schedule_id": "bf-quota", + "outcome": "created" + } + }, + { + "request": "POST schedules/bf-quota/backfill", + "status": 200, + "response": { + "schedule_id": "bf-quota", + "outcome": "backfill_started", + "fires_attempted": 2, + "results": [ + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + }, + { + "fire_time": "@v", + "workflow_id": "@v", + "outcome": "started" + } + ] + } + }, + { + "request": "GET schedules/bf-quota", + "status": 404, + "response": { + "message": "Schedule [bf-quota] not found in namespace [@namespace].", + "reason": "schedule_not_found" + } + }, + { + "request": "POST schedules/beta/backfill", + "status": 200, + "response": { + "schedule_id": "beta", + "outcome": "backfill_started", + "fires_attempted": 2, + "results": [ + { + "fire_time": "@v", + "outcome": "skipped" + }, + { + "fire_time": "@v", + "outcome": "skipped" + } + ] + } + }, + { + "request": "POST schedules/missing/backfill", + "status": 404, + "response": { + "message": "Schedule [missing] not found in namespace [@namespace].", + "reason": "schedule_not_found" + } + }, + { + "request": "GET schedules/bf-skip/history?limit=20", + "status": 200, + "response": { + "schedule_id": "bf-skip", + "namespace": "@namespace", + "events": [ + { + "id": "@v", + "sequence": 1, + "event_type": "ScheduleCreated", + "payload": { + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "overlap_policy": "skip", + "next_fire_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "bf-skip", + "command": "schedule.create", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "bf-skip", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0 + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 2, + "event_type": "ScheduleTriggered", + "payload": { + "workflow_instance_id": "@v", + "workflow_run_id": "@v", + "outcome": "backfilled", + "effective_overlap_policy": "skip", + "trigger_number": 1, + "occurrence_time": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules/bf-skip/backfill", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "bf-skip", + "command": "schedule.backfill", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "bf-skip", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "fires_count": 0, + "skipped_trigger_count": 0 + } + }, + "workflow_instance_id": "@v", + "workflow_run_id": "@v", + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 3, + "event_type": "ScheduleTriggerSkipped", + "payload": { + "reason": "overlap_policy_skip", + "skipped_trigger_count": 1, + "last_skipped_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules/bf-skip/backfill", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "bf-skip", + "command": "schedule.backfill", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "bf-skip", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "last_fired_at": "@v", + "last_skip_reason": "overlap_policy_skip", + "last_skipped_at": "@v", + "fires_count": 1, + "skipped_trigger_count": 1, + "latest_workflow_instance_id": "@v" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 4, + "event_type": "ScheduleTriggerSkipped", + "payload": { + "reason": "overlap_policy_skip", + "skipped_trigger_count": 2, + "last_skipped_at": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules/bf-skip/backfill", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "bf-skip", + "command": "schedule.backfill", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "bf-skip", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "last_fired_at": "@v", + "last_skip_reason": "overlap_policy_skip", + "last_skipped_at": "@v", + "fires_count": 1, + "skipped_trigger_count": 2, + "latest_workflow_instance_id": "@v" + } + }, + "workflow_instance_id": null, + "workflow_run_id": null, + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 5, + "event_type": "ScheduleTriggered", + "payload": { + "workflow_instance_id": "@v", + "workflow_run_id": "@v", + "outcome": "backfilled", + "effective_overlap_policy": "terminate_other", + "trigger_number": 2, + "occurrence_time": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules/bf-skip/backfill", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "bf-skip", + "command": "schedule.backfill", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "bf-skip", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "last_fired_at": "@v", + "last_skip_reason": "overlap_policy_skip", + "last_skipped_at": "@v", + "fires_count": 1, + "skipped_trigger_count": 2, + "latest_workflow_instance_id": "@v" + } + }, + "workflow_instance_id": "@v", + "workflow_run_id": "@v", + "recorded_at": "@v" + }, + { + "id": "@v", + "sequence": 6, + "event_type": "ScheduleTriggered", + "payload": { + "workflow_instance_id": "@v", + "workflow_run_id": "@v", + "outcome": "backfilled", + "effective_overlap_policy": "terminate_other", + "trigger_number": 3, + "occurrence_time": "@v", + "command_context": { + "source": "control_plane", + "context": { + "caller": { + "type": "server", + "label": "Standalone Server" + }, + "auth": { + "status": "authorized", + "method": "token", + "role": "admin", + "roles": [ + "admin" + ], + "principal": { + "subject": "legacy-token", + "roles": [ + "admin" + ], + "claims": { + "legacy_credential": true + }, + "legacy_full_access": true + } + }, + "request": { + "method": "POST", + "path": "/api/schedules/bf-skip/backfill", + "route_name": "@v", + "ip": "@v", + "user_agent": "GuzzleHttp/8", + "fingerprint": "@v" + }, + "server": { + "operation_id": "@v", + "namespace": "@namespace", + "workflow_id": "bf-skip", + "command": "schedule.backfill", + "metadata": [] + }, + "principal": { + "type": "auth:token", + "id": "legacy-token", + "label": "Admin" + } + } + }, + "schedule": { + "id": "@v", + "schedule_id": "bf-skip", + "namespace": "@namespace", + "status": "active", + "overlap_policy": "skip", + "next_fire_at": "@v", + "last_fired_at": "@v", + "last_skip_reason": "overlap_policy_skip", + "last_skipped_at": "@v", + "fires_count": 2, + "skipped_trigger_count": 2, + "latest_workflow_instance_id": "@v" + } + }, + "workflow_instance_id": "@v", + "workflow_run_id": "@v", + "recorded_at": "@v" + } + ], + "next_cursor": null, + "has_more": false + } + }, + { + "request": "GET schedules?page_size=10", + "status": 200, + "response": { + "schedules": [ + { + "schedule_id": "bf-buffer", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": "@v", + "overlap_policy": "buffer_one", + "note": null, + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": "@v", + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 3 + }, + { + "schedule_id": "bf-skip", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": "@v", + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": "@v", + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 3 + }, + { + "schedule_id": "bf", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": "@v", + "overlap_policy": "allow_all", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ], + "intervals": [ + { + "every": "P1D", + "offset": "PT6H" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": "@v", + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 8 + }, + { + "schedule_id": "gamma", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": "x AND y", + "namespace": "@namespace", + "spec": { + "intervals": [ + { + "every": "P1D" + } + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-b", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "beta", + "workflow_type": "parity.v1.other", + "status": "paused", + "paused": true, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "skip", + "note": null, + "namespace": "@namespace", + "spec": { + "timezone": "Europe/Budapest", + "cron_expressions": [ + "0 3 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.other", + "task_queue": "@queue", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + } + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0 + }, + { + "schedule_id": "alpha", + "workflow_type": "parity.v1.echo", + "status": "active", + "paused": false, + "next_fire": "@v", + "last_fire": null, + "overlap_policy": "allow_all", + "note": "changed", + "namespace": "@namespace", + "spec": { + "timezone": "America/New_York", + "cron_expressions": [ + "0 4 * * *" + ] + }, + "action": { + "workflow_type": "parity.v1.echo", + "task_queue": "catalog-z", + "input": { + "codec": "avro", + "blob": "wwHioz3/VYAiNwwCBIKAgICAgIAgAA==" + }, + "execution_timeout_seconds": 60 + }, + "next_fire_at": "@v", + "last_fired_at": null, + "search_attributes": null, + "created_at": "@v", + "updated_at": "@v", + "fires_count": 0, + "max_runs": 5, + "remaining_actions": 5 + } + ], + "schedule_count": 6, + "next_page_token": null + } + } +] diff --git a/tests/Unit/ServerParityScheduleCatalogContractTest.mjs b/tests/Unit/ServerParityScheduleCatalogContractTest.mjs new file mode 100644 index 000000000..aae0d771f --- /dev/null +++ b/tests/Unit/ServerParityScheduleCatalogContractTest.mjs @@ -0,0 +1,66 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {readFileSync} from 'node:fs'; +import {checkScheduleCatalog} from '../../scripts/conformance/server-parity/schedule-catalog-contract.mjs'; + +const fixture = JSON.parse(readFileSync(new URL('../Fixtures/ServerParity/schedule-catalog.json', import.meta.url))); +const expected = JSON.parse(readFileSync(new URL('../Fixtures/ServerParityExpected/schedule-catalog.json', import.meta.url))); +const workflowId = 'TEST-schedule-catalog'; +const namespace = 'test-schedule-catalog-catalog'; +const queue = 'test-schedule-catalog-queue'; +// PHP's raw backfill fire times, which normalization hides. +const FIRE_TIMES = {57: ['2026-03-27T03:00:00+01:00', '2026-03-27T06:00:00+00:00', '2026-03-28T03:00:00+01:00', + '2026-03-28T06:00:00+00:00', '2026-03-29T03:00:00+02:00', '2026-03-29T06:00:00+00:00', '2026-03-30T03:00:00+02:00'], +58: ['2026-03-27T03:00:00+01:00', '2026-03-27T06:00:00+00:00', '2026-03-28T03:00:00+01:00', '2026-03-28T06:00:00+00:00', + '2026-03-29T03:00:00+02:00', '2026-03-29T06:00:00+00:00', '2026-03-30T03:00:00+02:00', '2026-03-30T06:00:00+00:00'], +61: ['2026-01-01T00:00:00+00:00', '2026-01-02T00:00:00+00:00', '2026-01-03T00:00:00+00:00'], +62: ['2026-02-01T00:00:00+00:00', '2026-02-02T00:00:00+00:00'], +64: ['2026-01-01T00:00:00+00:00', '2026-01-02T00:00:00+00:00', '2026-01-03T00:00:00+00:00'], +66: ['2026-01-01T00:00:00+00:00', '2026-01-02T00:00:00+00:00'], +68: ['2026-01-01T03:00:00+01:00', '2026-01-02T03:00:00+01:00']}; +const TOKEN = `${'eyJ2ZXJzaW9uIjoxLCJuYW1lc3BhY2UiOiJkZWZhdWx0In0'}.${'ab'.repeat(32)}`; +function model() { + const steps = JSON.parse(JSON.stringify(expected).replaceAll('@namespace', namespace).replaceAll('@queue', queue)); + // Generated values as a server reports them before normalization. + for (const [index, times] of Object.entries(FIRE_TIMES)) { + steps[index].response.results.forEach((result, position) => { result.fire_time = times[position]; }); + } + steps[9].response.next_page_token = TOKEN; + steps[39].response.next_page_token = TOKEN; + steps[10].response.last_safe_cursor.created_at = '2026-10-21T05:00:00.123456Z'; + return {mode: 'http', schedule_catalog: {applicable: true, namespace, queue, retries: 0, attempts: 1, steps}}; +} +const projection = {scope: 'schedule_catalog'}; + +test('published PHP responses pass', () => assert.deepStrictEqual(checkScheduleCatalog(fixture, model(), workflowId), projection)); +test('a sequence replayed in a new namespace passes', () => { + const observation = model(); + const replayed = JSON.parse(JSON.stringify(observation).replaceAll(namespace, `${namespace}-r2`)); + replayed.schedule_catalog.attempts = 2; + assert.deepStrictEqual(checkScheduleCatalog(fixture, replayed, workflowId), projection); +}); +test('embedded explicitly declares the HTTP surface inapplicable', () => assert.deepStrictEqual(checkScheduleCatalog(fixture, + {mode: 'embedded', schedule_catalog: {applicable: false, reason: 'embedded_has_no_http_schedules'}}, workflowId), projection)); +for (const [label, mutate] of [ + ['another namespace', o => { o.schedule_catalog.namespace = 'default'; }], + ['unrecorded attempts', o => { delete o.schedule_catalog.attempts; }], + ['a missing step', o => { o.schedule_catalog.steps.pop(); }], + ['oldest schedules first', o => { o.schedule_catalog.steps[4].response.schedules.reverse(); }], + ['a last page with a token', o => { o.schedule_catalog.steps[11].response.next_page_token = TOKEN; }], + ['a token reused with other filters', o => { o.schedule_catalog.steps[10].status = 200; }], + ['a stale cursor that continues', o => { o.schedule_catalog.steps[41].response.reason = 'schedule_page_token_filter_mismatch'; }], + ['a page size measured as a number', o => { o.schedule_catalog.steps[14].response.errors.page_size.push('The page size field must be at least 1.'); }], + ['a search attribute predicate that matches', o => { o.schedule_catalog.steps[36].response.schedules.push(o.schedule_catalog.steps[4].response.schedules[0]); }], + ['an action replaced instead of merged', o => { delete o.schedule_catalog.steps[49].response.action.input; }], + ['other changed fields', o => { o.schedule_catalog.steps[50].response.events.at(-1).payload.changed_fields.pop(); }], + ['a fire time in UTC instead of the zone', o => { o.schedule_catalog.steps[57].response.results[0].fire_time = '2026-03-27T02:00:00+00:00'; }], + ['an occurrence at the exclusive end', o => { o.schedule_catalog.steps[57].response.results.push({fire_time: '2026-03-30T06:00:00+00:00', outcome: 'started', workflow_id: 'x'}); }], + ['a skip policy that starts every occurrence', o => { o.schedule_catalog.steps[61].response.results[1].outcome = 'started'; }], + ['a quota that does not end the backfill', o => { o.schedule_catalog.steps[66].response.fires_attempted = 5; }], +]) { + test(`rejects ${label}`, () => { + const observation = model(); + mutate(observation); + assert.throws(() => checkScheduleCatalog(fixture, observation, workflowId)); + }); +} diff --git a/tests/Unit/ServerParitySchedulePoliciesContractTest.mjs b/tests/Unit/ServerParitySchedulePoliciesContractTest.mjs index 0c4ad9817..aa36002c6 100644 --- a/tests/Unit/ServerParitySchedulePoliciesContractTest.mjs +++ b/tests/Unit/ServerParitySchedulePoliciesContractTest.mjs @@ -12,7 +12,7 @@ function model() { steps[3].response.next_fire_at = '2027-01-01T02:00:00+00:00'; steps[3].response.created_at = '2026-10-21T05:00:00+00:00'; return {mode: 'http', schedule_policies: {applicable: true, namespace: 'test-schedule-policies-schedules', - queue: 'test-schedule-policies-queue', retries: 0, steps: steps.map(step => JSON.parse(JSON.stringify(step) + queue: 'test-schedule-policies-queue', retries: 0, attempts: 1, steps: steps.map(step => JSON.parse(JSON.stringify(step) .replaceAll('@namespace', 'test-schedule-policies-schedules').replaceAll('@queue', 'test-schedule-policies-queue')))}}; } const projection = {scope: 'schedule_policies'}; @@ -29,6 +29,8 @@ test('embedded explicitly declares the HTTP surface inapplicable', () => assert. for (const [label, mutate] of [ ['another namespace', o => { o.schedule_policies.namespace = 'default'; }], ['unrecorded retries', o => { delete o.schedule_policies.retries; }], + ['unrecorded attempts', o => { delete o.schedule_policies.attempts; }], + ['a replay in the first namespace', o => { o.schedule_policies.attempts = 2; }], ['a missing step', o => { o.schedule_policies.steps.pop(); }], ['another status', o => { o.schedule_policies.steps[4].status = 422; }], ['a changed validation message', o => { o.schedule_policies.steps[1].response.message = 'The spec field is required.'; }],