### Install Cronos NuGet Package Source: https://github.com/hangfireio/cronos/blob/main/README.md Use this command in the Package Manager Console to install the Cronos library. ```powershell PM> Install-Package Cronos ``` -------------------------------- ### Cronos Example: Friday the Thirteenth Source: https://github.com/hangfireio/cronos/blob/main/README.md This example demonstrates how to specify a schedule that runs on a specific day of the month and a specific day of the week, such as Friday the thirteenth. ```cron 0 0 13 * 5 ``` -------------------------------- ### Autumn Daylight Saving Time - Interval Expression Example Source: https://github.com/hangfireio/cronos/blob/main/README.md Demonstrates the behavior of an interval-based Cron expression during an autumn Daylight Saving Time transition, ensuring periodic occurrences. ```cron "*/30 * * * *" interval expression. It should occur every 30 minutes no matter what. Nov 08, 00:30 +04:00 – run Nov 08, 01:00 +04:00 – run Nov 08, 01:30 +04:00 – run Nov 08, 01:00 +03:00 – run Nov 08, 01:30 +03:00 – run Nov 08, 02:00 +03:00 – run ``` -------------------------------- ### Spring Daylight Saving Time Transition Example Source: https://github.com/hangfireio/cronos/blob/main/README.md Illustrates how Cronos adjusts job occurrences during a spring Daylight Saving Time transition when a scheduled time becomes invalid. ```cron "30 02 * * *" (every day at 02:30 AM) Mar 13, 02:30 +03:00 – run Mar 14, 03:00 +04:00 – run (adjusted) Mar 15, 02:30 +04:00 – run ``` -------------------------------- ### Using Predefined Cron Expressions in C# Source: https://context7.com/hangfireio/cronos/llms.txt Utilize static readonly CronExpression instances for common schedules like yearly, monthly, weekly, daily, and hourly. Includes examples with jitter for distributed systems. ```csharp using Cronos; // Predefined static expressions CronExpression yearly = CronExpression.Yearly; // 0 0 1 1 * (Jan 1 at midnight) CronExpression monthly = CronExpression.Monthly; // 0 0 1 * * (1st of month at midnight) CronExpression weekly = CronExpression.Weekly; // 0 0 * * 0 (Sunday at midnight) CronExpression daily = CronExpression.Daily; // 0 0 * * * (Daily at midnight) CronExpression hourly = CronExpression.Hourly; // 0 * * * * (Every hour) CronExpression everyMinute = CronExpression.EveryMinute; // * * * * * CronExpression everySecond = CronExpression.EverySecond; // * * * * * * (6 fields) ``` ```csharp int seed = "my-job-id".GetHashCode(); CronExpression jitteredYearly = CronExpression.YearlyWithJitter(seed); CronExpression jitteredMonthly = CronExpression.MonthlyWithJitter(seed); CronExpression jitteredWeekly = CronExpression.WeeklyWithJitter(seed); CronExpression jitteredDaily = CronExpression.DailyWithJitter(seed); CronExpression jitteredHourly = CronExpression.HourlyWithJitter(seed); CronExpression jitteredMinutely = CronExpression.EveryMinuteWithJitter(seed); ``` ```csharp // Example: distribute jobs across the hour foreach (string jobId in new[] { "job-1", "job-2", "job-3" }) { var expr = CronExpression.HourlyWithJitter(jobId.GetHashCode()); DateTime? next = expr.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"{jobId} next run: {next:HH:mm:ss}"); } ``` -------------------------------- ### Autumn Daylight Saving Time - Non-Interval Expression Example Source: https://github.com/hangfireio/cronos/blob/main/README.md Shows how a non-interval-based Cron expression behaves during an autumn Daylight Saving Time transition, occurring only before the clock shift. ```cron "30 1 * * *" non-interval expression. It should occur once a day no matter what. Nov 07, 01:30 +04:00 – run Nov 08, 01:30 +04:00 – run Nov 08, 01:30 +03:00 – skip Nov 09, 01:30 +03:00 – run ``` -------------------------------- ### Get Occurrences Within a Date Range Source: https://github.com/hangfireio/cronos/blob/main/README.md Retrieves all occurrences within a specified date range (inclusive start, exclusive end by default). Supports DateTime arguments. ```csharp CronExpression expression = CronExpression.Parse("* * * * *"); IEnumerable occurrences = expression.GetOccurrences( DateTime.UtcNow, DateTime.UtcNow.AddYears(1), fromInclusive: true, toInclusive: false); ``` -------------------------------- ### GetOccurrences - Get Multiple Occurrences in Range Source: https://context7.com/hangfireio/cronos/llms.txt Returns all occurrences within a specified date range. By default, the 'from' time is included and the 'to' time is excluded. Supports controlling boundary inclusion and time zones. ```csharp using Cronos; CronExpression expression = CronExpression.Parse("0 9 * * MON-FRI"); // Weekdays at 9 AM // Get all occurrences in next month DateTime from = DateTime.UtcNow; DateTime to = from.AddMonths(1); IEnumerable occurrences = expression.GetOccurrences(from, to); Console.WriteLine("Next month's 9 AM occurrences:"); foreach (DateTime occurrence in occurrences.Take(10)) { Console.WriteLine($" {occurrence:yyyy-MM-dd HH:mm}"); } // Control boundary inclusion IEnumerable withBoundaries = expression.GetOccurrences( from, to, fromInclusive: true, toInclusive: true); // With time zone TimeZoneInfo zone = TimeZoneInfo.Local; IEnumerable localOccurrences = expression.GetOccurrences(from, to, zone); // With DateTimeOffset for precise offset handling IEnumerable offsetOccurrences = expression.GetOccurrences( DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1), zone); ``` -------------------------------- ### GetOccurrencesDescending - Get Occurrences in Reverse Order Source: https://context7.com/hangfireio/cronos/llms.txt Returns occurrences in reverse chronological order, from the 'from' bound down to the 'to' bound. Useful for finding recent past occurrences. Supports boundary inclusion and time zones. ```csharp using Cronos; CronExpression expression = CronExpression.Parse("0 0 1 * *"); // First of every month // Get last 5 monthly occurrences DateTime from = DateTime.UtcNow; DateTime to = from.AddYears(-1); IEnumerable pastOccurrences = expression.GetOccurrencesDescending( from, to, fromInclusive: true, toInclusive: false); Console.WriteLine("Past monthly occurrences:"); foreach (DateTime occurrence in pastOccurrences.Take(5)) { Console.WriteLine($" {occurrence:yyyy-MM-dd}"); } // With time zone TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); IEnumerable pastInEastern = expression.GetOccurrencesDescending( DateTime.UtcNow, DateTime.UtcNow.AddYears(-1), eastern); // With DateTimeOffset IEnumerable pastOffsets = expression.GetOccurrencesDescending( DateTimeOffset.Now, DateTimeOffset.Now.AddMonths(-6), eastern); ``` -------------------------------- ### Parse Cron Expression and Get Occurrences Source: https://github.com/hangfireio/cronos/blob/main/README.md Parses a cron expression and calculates the next and previous UTC occurrences. Throws CronFormatException for invalid expressions. ```csharp using Cronos; CronExpression expression = CronExpression.Parse("* * * * *"); DateTime? nextUtc = expression.GetNextOccurrence(DateTime.UtcNow); DateTime? previousUtc = expression.GetPreviousOccurrence(DateTime.UtcNow); ``` -------------------------------- ### Get Occurrences in Descending Order Within a Range Source: https://github.com/hangfireio/cronos/blob/main/README.md Retrieves occurrences in reverse order within a specified date range (inclusive start, exclusive end by default). Supports DateTime arguments. ```csharp IEnumerable previousOccurrences = expression.GetOccurrencesDescending( DateTime.UtcNow, DateTime.UtcNow.AddDays(-7), fromInclusive: true, toInclusive: false); ``` -------------------------------- ### Schedule Jitter with Cronos Source: https://github.com/hangfireio/cronos/blob/main/README.md Demonstrates how to use schedule jitter by passing a seed to CronExpression.Parse or using CronExpression.HourlyWithJitter. Ensure a seed is provided when using 'H' in cron expressions to avoid exceptions. ```csharp // if you're in a job-schedulig scenario, you would probably want to // use information from the job itself as a seed, but this can be anything var seed = jobId.GetHashCode(); // note that each of these 3 expressions are equivalent var hourlyExpressionWithoutJitter = CronExpression.Parse("0 * * * *"); var hourlyMacroWithoutJitter = CronExpression.Parse("@hourly"); var hourlyNamedWithoutJitter = CronExpression.Hourly; // and each of these are equivalent because the same seed was used var hourlyExpressionWithJitter = CronExpression.Parse("H H * * * *", CronFormat.IncludeSeconds, seed); var hourlyMacroWithJitter = CronExpression.Parse("@hourly", seed); var hourlyNamedWithJitter = CronExpression.HourlyWithJitter(seed); ``` -------------------------------- ### Handling DST Transitions with Cronos in C# Source: https://context7.com/hangfireio/cronos/llms.txt Demonstrates how Cronos manages Daylight Saving Time. Spring forward invalid times are adjusted, and fall back causes interval expressions to run twice. ```csharp using Cronos; TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); // Spring forward example: 2:30 AM doesn't exist on March 13, 2016 // Clock jumps from 1:59 AM to 3:00 AM CronExpression at230am = CronExpression.Parse("0 30 2 * * *", CronFormat.IncludeSeconds); DateTimeOffset beforeDST = new DateTimeOffset(2016, 3, 13, 1, 59, 0, TimeSpan.FromHours(-5)); DateTimeOffset? nextAfterDST = at230am.GetNextOccurrence(beforeDST, eastern); // Returns 3:00 AM -04:00 (adjusted to next valid time) Console.WriteLine($"2:30 AM adjusted to: {nextAfterDST}"); ``` ```csharp // Fall back example: 1:30 AM occurs twice on November 6, 2016 // Clock falls back from 2:00 AM DST to 1:00 AM ST CronExpression every30Min = CronExpression.Parse("0 */30 * * * *", CronFormat.IncludeSeconds); DateTimeOffset dstTime = new DateTimeOffset(2016, 11, 6, 1, 30, 0, TimeSpan.FromHours(-4)); DateTimeOffset? next1 = every30Min.GetNextOccurrence(dstTime, eastern, inclusive: false); // Interval expressions get both 1:30 -04:00 DST and 1:30 -05:00 ST Console.WriteLine($"After 1:30 DST: {next1}"); // 1:00 -05:00 ST ``` ```csharp // Non-interval expressions only run once (in DST period) CronExpression at130am = CronExpression.Parse("0 30 1 * * *", CronFormat.IncludeSeconds); DateTimeOffset? nonInterval = at130am.GetNextOccurrence(dstTime, eastern, inclusive: true); Console.WriteLine($"1:30 AM (non-interval): {nonInterval}"); ``` -------------------------------- ### CronExpression Equality and ToString Source: https://context7.com/hangfireio/cronos/llms.txt Compares CronExpressions for equality using == and Equals, and demonstrates ToString() for normalized output. Equivalent expressions yield true for comparisons and the same normalized string. ```csharp using Cronos; // Equivalent expressions are equal CronExpression expr1 = CronExpression.Parse("* * * * *"); CronExpression expr2 = CronExpression.Parse("0-59 0-23 1-31 1-12 0-6"); CronExpression expr3 = CronExpression.Parse("*/1 */1 */1 */1 */1"); Console.WriteLine($"expr1 == expr2: {expr1 == expr2}"); // true Console.WriteLine($"expr1.Equals(expr3): {expr1.Equals(expr3)}"); // true // Different expressions are not equal CronExpression different = CronExpression.Parse("0 0 * * *"); Console.WriteLine($"expr1 == different: {expr1 == different}"); // false // Hash codes are equal for equivalent expressions HashSet set = new HashSet { expr1, expr2, expr3 }; Console.WriteLine($"Unique expressions: {set.Count}"); // 1 // ToString returns normalized expression CronExpression complex = CronExpression.Parse("0,1,2-5 */2 1-10 JAN-MAR MON,WED,FRI"); Console.WriteLine($"Normalized: {complex}"); // 0,1,2,3,4,5 0,2,4,6,8,10,12,14,16,18,20,22 1,2,3,4,5,6,7,8,9,10 1,2,3 1,3,5 // Second field included when using IncludeSeconds format CronExpression withSeconds = CronExpression.Parse("30 * * * * *", CronFormat.IncludeSeconds); Console.WriteLine($"With seconds: {withSeconds}"); // 30 * * * * * ``` -------------------------------- ### Cronos Performance Benchmarks Source: https://github.com/hangfireio/cronos/blob/main/README.md Performance comparison of Cronos against NCrontab and Quartz for parsing cron expressions and calculating next occurrences. Results show Cronos is significantly faster. ```text Cronos Method | Mean | StdDev ------------------------------------------- | -------------- | ------------- CronExpression.Parse("* * * * *") | 30.8473 ns | 0.0515 ns CronExpression.Parse("*/10 12-20 ? DEC 3") | 81.5010 ns | 0.0924 ns Simple.GetNextOccurrence(DateTime.UtcNow) | 123.4712 ns | 0.5928 ns Complex.GetNextOccurrence(DateTime.UtcNow) | 212.0422 ns | 0.3997 ns NCrontab Method | Mean | StdDev ------------------------------------------- | -------------- | ------------- CrontabSchedule.Parse("* * * * *") | 1,813.7313 ns | 3.3718 ns CrontabSchedule.Parse("*/10 12-20 * DEC 3") | 3,174.3625 ns | 6.8522 ns Simple.GetNextOccurrence(DateTime.UtcNow) | 147.7866 ns | 0.1689 ns Complex.GetNextOccurrence(DateTime.UtcNow) | 1,001.3253 ns | 1.6205 ns Quartz Method | Mean | StdDev ------------------------------------------- | -------------- | ------------- new CronExpression("* * * * * ?") | 48,157.7744 ns | 1,417.3101 ns new CronExpression("* */10 12-20 ? DEC 3") | 33,731.9992 ns | 38.3192 ns Simple.GetTimeAfter(DateTimeOffset.Now) | 1,416.9867 ns | 1.2784 ns Complex.GetTimeAfter(DateTimeOffset.Now) | 6,573.0269 ns | 7.9192 ns ``` -------------------------------- ### Safe Parsing - Cronos Source: https://context7.com/hangfireio/cronos/llms.txt Use `CronExpression.TryParse` for safe parsing without exceptions. It returns `true` on success and `false` on failure. Supports specifying `CronFormat` and a jitter seed. ```csharp using Cronos; // Safe parsing with error handling if (CronExpression.TryParse("*/5 * * * *", out CronExpression? expression)) { DateTime? next = expression.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"Next occurrence: {next}"); } else { Console.WriteLine("Invalid cron expression"); } // With format specification if (CronExpression.TryParse("*/30 * * * * *", CronFormat.IncludeSeconds, out CronExpression? secondsExpr)) { Console.WriteLine($"Parsed: {secondsExpr}"); } // With jitter seed if (CronExpression.TryParse("H * * * *", CronFormat.Standard, 42, out CronExpression? jitteredExpr)) { Console.WriteLine($"Jittered expression parsed successfully"); } ``` -------------------------------- ### Cronos Macros for Common Schedules Source: https://github.com/hangfireio/cronos/blob/main/README.md Macros provide convenient shortcuts for frequently used cron expressions, simplifying the definition of schedules like every second, minute, hour, day, week, month, or year. ```cron @every_second ``` ```cron @every_minute ``` ```cron @hourly ``` ```cron @daily ``` ```cron @midnight ``` ```cron @weekly ``` ```cron @monthly ``` ```cron @yearly ``` ```cron @annually ``` -------------------------------- ### CronExpression.TryParse - Safe Parsing Source: https://context7.com/hangfireio/cronos/llms.txt The `TryParse` method attempts to parse a cron expression without throwing exceptions. Returns `true` if parsing succeeds and outputs the parsed `CronExpression`, or `false` with a null output if parsing fails. ```APIDOC ## CronExpression.TryParse - Safe Parsing ### Description Attempts to parse a cron expression string safely, returning a boolean indicating success and the parsed `CronExpression` object via an output parameter. ### Method `static bool TryParse(string expression, out CronExpression? result)` `static bool TryParse(string expression, CronFormat format, out CronExpression? result)` `static bool TryParse(string expression, CronFormat format, int? jitterSeed, out CronExpression? result)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp using Cronos; // Safe parsing with error handling if (CronExpression.TryParse("*/5 * * * *", out CronExpression? expression)) { DateTime? next = expression.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"Next occurrence: {next}"); } else { Console.WriteLine("Invalid cron expression"); } // With format specification if (CronExpression.TryParse("*/30 * * * * *", CronFormat.IncludeSeconds, out CronExpression? secondsExpr)) { Console.WriteLine($"Parsed: {secondsExpr}"); } // With jitter seed if (CronExpression.TryParse("H * * * *", CronFormat.Standard, 42, out CronExpression? jitteredExpr)) { Console.WriteLine("Jittered expression parsed successfully"); } ``` ### Response #### Success Response (bool) - **true**: If parsing is successful. - **false**: If parsing fails. ### Output Parameters - **result** (`CronExpression?`): The parsed `CronExpression` object if successful, otherwise `null`. ### Errors No exceptions are thrown. The method returns `false` for invalid expressions. ``` -------------------------------- ### Calculate Local Time Occurrences with DateTimeOffset Source: https://github.com/hangfireio/cronos/blob/main/README.md Calculates the next occurrence using local time with DateTimeOffset to avoid ambiguity during DST transitions. The local time can be accessed via the .DateTime property. ```csharp CronExpression expression = CronExpression.Parse("* * * * *"); DateTimeOffset? next = expression.GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Local); var nextLocalTime = next?.DateTime; ``` -------------------------------- ### Parse Cron Expression - Cronos Source: https://context7.com/hangfireio/cronos/llms.txt Use `CronExpression.Parse` to create a `CronExpression` from a cron string. Supports standard 5-field format by default, with an optional `CronFormat.IncludeSeconds` flag for 6-field expressions. Invalid expressions throw `CronFormatException`. Macros like `@hourly` and jittered expressions with a seed are also supported. ```csharp using Cronos; // Standard 5-field expression (minute, hour, day-of-month, month, day-of-week) CronExpression everyMinute = CronExpression.Parse("* * * * *"); CronExpression dailyAtMidnight = CronExpression.Parse("0 0 * * *"); CronExpression everyWeekdayAt9am = CronExpression.Parse("0 9 * * MON-FRI"); CronExpression lastDayOfMonth = CronExpression.Parse("0 0 L * *"); CronExpression nearestWeekday15th = CronExpression.Parse("0 0 15W * *"); CronExpression secondFriday = CronExpression.Parse("0 0 * * FRI#2"); // 6-field expression with seconds CronExpression everySecond = CronExpression.Parse("* * * * * *", CronFormat.IncludeSeconds); CronExpression every30Seconds = CronExpression.Parse("*/30 * * * * *", CronFormat.IncludeSeconds); // Using macros CronExpression hourly = CronExpression.Parse("@hourly"); CronExpression daily = CronExpression.Parse("@daily"); CronExpression weekly = CronExpression.Parse("@weekly"); CronExpression monthly = CronExpression.Parse("@monthly"); CronExpression yearly = CronExpression.Parse("@yearly"); // With jitter seed for load distribution int jobId = 12345; CronExpression jitteredHourly = CronExpression.Parse("H H * * * *", CronFormat.IncludeSeconds, jobId.GetHashCode()); ``` -------------------------------- ### Cron Grammar Definition Source: https://github.com/hangfireio/cronos/blob/main/README.md Defines the case-insensitive grammar used by the Cronos parser for scheduling expressions and macros. ```grammar cron ::= expression | macro expression ::= [second space] minute space hour space day-of-month space month space day-of-week second ::= field minute ::= field hour ::= field day-of-month ::= '*' [step] | '?' [step] | 'H' [step] | lastday | value [ 'W' | range [list] ] month ::= field day-of-week ::= '*' [step] | '?' [step] | 'H' [step] | value [ dowspec | range [list] ] macro ::= '@every_second' | '@every_minute' | '@hourly' | '@daily' | '@midnight' | '@weekly' | '@monthly'| '@yearly' | '@annually' field ::= '*' [step] | '?' [step] | 'H' [step] | value [range] [list] list ::= { ',' value [range] } range ::= '-' value [step] | [step] step ::= '/' number value ::= number | name name ::= month-name | dow-name month-name ::= 'JAN' | 'FEB' | 'MAR' | 'APR' | 'MAY' | 'JUN' | 'JUL' | 'AUG' | 'SEP' | 'OCT' | 'NOV' | 'DEC' dow-name ::= 'SUN' | 'MON' | 'TUE' | 'WED' | 'THU' | 'FRI' | 'SAT' dowspec ::= 'L' | '#' number lastday ::= 'L' ['-' number] ['W'] number ::= digit | number digit space ::= ' ' | '\t' ``` -------------------------------- ### CronExpression.Parse - Parse Cron Expression Source: https://context7.com/hangfireio/cronos/llms.txt The static `Parse` method creates a `CronExpression` from a cron string. It supports standard 5-field format by default, with an optional `CronFormat.IncludeSeconds` flag for 6-field expressions including seconds. Invalid expressions throw `CronFormatException`. ```APIDOC ## CronExpression.Parse - Parse Cron Expression ### Description Parses a cron expression string into a `CronExpression` object. Supports standard 5-field and optional 6-field (with seconds) formats, as well as macros and jitter. ### Method `static CronExpression Parse(string expression, CronFormat format = CronFormat.Standard, int? jitterSeed = null)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp using Cronos; // Standard 5-field expression CronExpression everyMinute = CronExpression.Parse("* * * * *"); CronExpression dailyAtMidnight = CronExpression.Parse("0 0 * * *"); CronExpression everyWeekdayAt9am = CronExpression.Parse("0 9 * * MON-FRI"); CronExpression lastDayOfMonth = CronExpression.Parse("0 0 L * *"); CronExpression nearestWeekday15th = CronExpression.Parse("0 0 15W * *"); CronExpression secondFriday = CronExpression.Parse("0 0 * * FRI#2"); // 6-field expression with seconds CronExpression everySecond = CronExpression.Parse("* * * * * *", CronFormat.IncludeSeconds); CronExpression every30Seconds = CronExpression.Parse("*/30 * * * * *", CronFormat.IncludeSeconds); // Using macros CronExpression hourly = CronExpression.Parse("@hourly"); CronExpression daily = CronExpression.Parse("@daily"); CronExpression weekly = CronExpression.Parse("@weekly"); CronExpression monthly = CronExpression.Parse("@monthly"); CronExpression yearly = CronExpression.Parse("@yearly"); // With jitter seed for load distribution int jobId = 12345; CronExpression jitteredHourly = CronExpression.Parse("H H * * * *", CronFormat.IncludeSeconds, jobId.GetHashCode()); ``` ### Response #### Success Response (CronExpression) - **CronExpression** - The parsed cron expression object. #### Response Example ```json { "expression": "* * * * *" } ``` ### Errors - **CronFormatException**: Thrown if the expression is invalid. ``` -------------------------------- ### CronExpression.GetNextOccurrence - Calculate Next Run Time Source: https://context7.com/hangfireio/cronos/llms.txt The `GetNextOccurrence` method calculates the next occurrence after a given time. It requires UTC `DateTime` objects or `DateTimeOffset` instances. The `inclusive` parameter determines whether the from time itself is considered a valid occurrence. ```APIDOC ## CronExpression.GetNextOccurrence - Calculate Next Run Time ### Description Calculates the next scheduled occurrence of the cron expression after a specified point in time. ### Method `DateTimeOffset? GetNextOccurrence(DateTimeOffset from, TimeZoneInfo? timeZone = null, bool inclusive = false)` `DateTime? GetNextOccurrence(DateTime from, TimeZoneInfo? timeZone = null, bool inclusive = false)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp using Cronos; CronExpression expression = CronExpression.Parse("0 */6 * * *"); // Every 6 hours // Basic usage with UTC DateTime DateTime? nextUtc = expression.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"Next occurrence (UTC): {nextUtc}"); // Inclusive vs exclusive DateTime now = DateTime.UtcNow; DateTime? nextExclusive = expression.GetNextOccurrence(now, inclusive: false); // After now DateTime? nextInclusive = expression.GetNextOccurrence(now, inclusive: true); // At or after now // With time zone - returns UTC DateTime TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); DateTime? nextInEastern = expression.GetNextOccurrence(DateTime.UtcNow, eastern); Console.WriteLine($"Next (Eastern): {TimeZoneInfo.ConvertTimeFromUtc(nextInEastern.Value, eastern)}"); // With DateTimeOffset - preserves correct offset including DST DateTimeOffset? nextOffset = expression.GetNextOccurrence(DateTimeOffset.UtcNow, eastern); Console.WriteLine($"Next with offset: {nextOffset}"); // Null is returned for impossible dates (e.g., Feb 30) CronExpression impossible = CronExpression.Parse("0 0 30 2 *"); // Feb 30 doesn't exist DateTime? neverHappens = impossible.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"Feb 30 occurrence: {neverHappens}"); // null ``` ### Response #### Success Response (DateTimeOffset? or DateTime?) - **DateTimeOffset?** or **DateTime?**: The next occurrence time. Returns `null` if no future occurrences are possible. #### Response Example ```json { "nextOccurrence": "2023-10-27T12:00:00Z" } ``` ### Errors - Returns `null` for impossible dates or if no future occurrences exist. ``` -------------------------------- ### Calculate Next Run Time - Cronos Source: https://context7.com/hangfireio/cronos/llms.txt Use `GetNextOccurrence` to calculate the next occurrence after a given time. Requires UTC `DateTime` or `DateTimeOffset`. The `inclusive` parameter controls whether the current time is considered. Time zone support is provided, returning UTC `DateTime` or `DateTimeOffset`. ```csharp using Cronos; CronExpression expression = CronExpression.Parse("0 */6 * * *"); // Every 6 hours // Basic usage with UTC DateTime DateTime? nextUtc = expression.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"Next occurrence (UTC): {nextUtc}"); // Inclusive vs exclusive DateTime now = DateTime.UtcNow; DateTime? nextExclusive = expression.GetNextOccurrence(now, inclusive: false); // After now DateTime? nextInclusive = expression.GetNextOccurrence(now, inclusive: true); // At or after now // With time zone - returns UTC DateTime TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); DateTime? nextInEastern = expression.GetNextOccurrence(DateTime.UtcNow, eastern); Console.WriteLine($"Next (Eastern): {TimeZoneInfo.ConvertTimeFromUtc(nextInEastern.Value, eastern)}"); // With DateTimeOffset - preserves correct offset including DST DateTimeOffset? nextOffset = expression.GetNextOccurrence(DateTimeOffset.UtcNow, eastern); Console.WriteLine($"Next with offset: {nextOffset}"); // Null is returned for impossible dates (e.g., Feb 30) CronExpression impossible = CronExpression.Parse("0 0 30 2 *"); // Feb 30 doesn't exist DateTime? neverHappens = impossible.GetNextOccurrence(DateTime.UtcNow); Console.WriteLine($"Feb 30 occurrence: {neverHappens}"); // null ``` -------------------------------- ### Parse Cron Expression Including Seconds Source: https://github.com/hangfireio/cronos/blob/main/README.md Parses a cron expression that includes seconds by specifying CronFormat.IncludeSeconds. Calculates the next UTC occurrence. ```csharp CronExpression expression = CronExpression.Parse("*/30 * * * * *", CronFormat.IncludeSeconds); DateTime? next = expression.GetNextOccurrence(DateTime.UtcNow); ``` -------------------------------- ### Calculate Occurrences with Specific Time Zones Source: https://github.com/hangfireio/cronos/blob/main/README.md Calculates next and previous occurrences within a specified time zone using UTC DateTime or DateTimeOffset. ```csharp CronExpression expression = CronExpression.Parse("* * * * *"); TimeZoneInfo easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); DateTime? next = expression.GetNextOccurrence(DateTime.UtcNow, easternTimeZone); DateTimeOffset? next = expression.GetNextOccurrence(DateTimeOffset.UtcNow, easternTimeZone); DateTime? previous = expression.GetPreviousOccurrence(DateTime.UtcNow, easternTimeZone); DateTimeOffset? previous = expression.GetPreviousOccurrence(DateTimeOffset.UtcNow, easternTimeZone); ``` -------------------------------- ### GetPreviousOccurrence - Calculate Previous Run Time Source: https://context7.com/hangfireio/cronos/llms.txt Calculates the most recent occurrence before a given time. Useful for determining when a job last ran. Supports specifying inclusive/exclusive boundaries and time zones. ```csharp using Cronos; CronExpression expression = CronExpression.Parse("0 0 * * *"); // Daily at midnight // Basic usage DateTime? previousUtc = expression.GetPreviousOccurrence(DateTime.UtcNow); Console.WriteLine($"Last midnight (UTC): {previousUtc}"); // With inclusive parameter DateTime? prevInclusive = expression.GetPreviousOccurrence(DateTime.UtcNow, inclusive: true); DateTime? prevExclusive = expression.GetPreviousOccurrence(DateTime.UtcNow, inclusive: false); // With time zone TimeZoneInfo pacific = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); DateTime? prevInPacific = expression.GetPreviousOccurrence(DateTime.UtcNow, pacific); // With DateTimeOffset for correct offset handling DateTimeOffset? prevOffset = expression.GetPreviousOccurrence(DateTimeOffset.Now, pacific); Console.WriteLine($"Previous with offset: {prevOffset}"); ``` -------------------------------- ### Cronos Special Characters for Day of Month and Day of Week Source: https://github.com/hangfireio/cronos/blob/main/README.md Use special characters like L, W, and # to define complex scheduling rules for the last day of the month, nearest weekday, or specific occurrences of a weekday. ```cron 0 0 L * * ``` ```cron 0 0 L-1 * * ``` ```cron 0 0 3W * * ``` ```cron 0 0 LW * * ``` ```cron 0 0 * * 2L ``` ```cron 0 0 * * 6#3 ``` ```cron 0 0 ? 1 MON#1 ``` -------------------------------- ### Cronos Special Characters: L, W, # Source: https://context7.com/hangfireio/cronos/llms.txt Demonstrates the usage of special characters L (last day/weekday), W (nearest weekday), and # (nth day of week) in Cronos expressions. Use UTC DateTime for calculations. ```csharp using Cronos; // L - Last day of month CronExpression lastDay = CronExpression.Parse("0 0 L * *"); // Last day of month CronExpression lastMinus1 = CronExpression.Parse("0 0 L-1 * *"); // Day before last CronExpression lastFriday = CronExpression.Parse("0 0 * * 5L"); // Last Friday // W - Nearest weekday (Mon-Fri) CronExpression weekday15 = CronExpression.Parse("0 0 15W * *"); // Nearest weekday to 15th CronExpression weekday1 = CronExpression.Parse("0 0 1W * *"); // Nearest weekday to 1st // LW - Last weekday of month CronExpression lastWeekday = CronExpression.Parse("0 0 LW * *"); CronExpression lastWeekdayMinus3 = CronExpression.Parse("0 0 L-3W * *"); // 3 days before last, nearest weekday // # - Nth day of week CronExpression firstMonday = CronExpression.Parse("0 0 * * MON#1"); CronExpression secondFriday = CronExpression.Parse("0 0 * * 5#2"); CronExpression thirdSunday = CronExpression.Parse("0 0 * * SUN#3"); // Combined day-of-month AND day-of-week (both must match) CronExpression friday13th = CronExpression.Parse("0 0 13 * 5"); // Friday the 13th // Calculate examples DateTime now = DateTime.UtcNow; Console.WriteLine($"Last day: {lastDay.GetNextOccurrence(now)}"); Console.WriteLine($"Last Friday: {lastFriday.GetNextOccurrence(now)}"); Console.WriteLine($"First Monday: {firstMonday.GetNextOccurrence(now)}"); Console.WriteLine($"Friday 13th: {friday13th.GetNextOccurrence(now)}"); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.