# All about CRON

## What about a CRON?

CRON strings are a concise way of telling the application when to schedule or run something. Perigee uses CRON string data throughout for advanced process scheduling and events.&#x20;

### CRON Data Explanation

Most CRON strings contain five bits. Perigee's CRON can contain 6 if you use the optional seconds bit.

```
Second   Minute      Hour      Day      Month      Day-Of-Week
   *        *         *         *         *            *
```

* The **ASTERISK** character means "All Available Values"
  * For hour, this is 0-23
  * For Minute, this is 0-59
  * For Day this is 1-31
  * For Month this is 1-12
  * For Day-Of-Week this is 0-6 (Sunday being 0)
* The **COMMA** character is a list of values
  * If the Month bit is **`0,1,2`** - Then the CRON is only run in Jan, Feb and March.
* The **DASH** character means a range from a-z.
  * If the day bit is **`0-6`** - Then the CRON is only run the first 7 days of the month
* The **SLASH** character is a divider of all available values.
  * If the second bit is **`*/5`** - Then the CRON is executed on every fifth second.
* There are several special characters that can only be used in certain situations.&#x20;
  * The **F** character is for FIRST OF:
    * This can be used in the Day or Day-Of-Week bits
    * In the day bit, **`F`** - The CRON would run the first day of the month
  * The **L** character is for LAST OF:
    * This can be used in the Day or Day-Of-Week bits
    * In the day bit, **`L-2`** - The CRON would run the second from last day of the month
  * The **#** is for day-of-week selector
    * This is only used in the Day-Of-Week bit:
    * **`0#2`** would be the second Sunday (0 Sunday #2)
    * **`1#3`** would be the third Monday (1 Monday #3)

## Examples

### How would I run a CRON every morning at 5AM ?

* Let's leave out the seconds since we don't need that here.&#x20;
* If we don't specify 0 in the minute bit the CRON it will run every minute of 5AM.
* 5AM is 5 in the hour bit.
* The key request is "every day", so let's set the day bit to an asterisk.
* Every other

```
0 5 * * *
```

### How would I run a CRON at 1AM on the last Friday of every month?

* This is where that special L character comes into play.
  * Day-Of-Week starts as 0 Sunday, so Friday would be 5.
  * Asking for the last friday of the month would be L5 in day-of-week bit.
* If we don't specify 0 in the minute bit the CRON it will run every minute of 1AM.
* 1AM in the hour bit is 1
* Asterisks for the other fields

```
0 1 * * L5
```

### How would I run a CRON at 1AM on the second to last day of the month?

* This is where that special L character comes into play again.
  * Asking for the second to last day of of the month would be L-2 in day bit.
* If we don't specify 0 in the minute bit the CRON it will run every minute of 1AM.
* 1AM is the hour bit is 1
* Asterisks for the other bits&#x20;

```
0 1 L-2 * *
```

## The SDK

#### Parse

Call Parse on any CRON string. It will detect if seconds are present.

```csharp
var cparsed = Cron.Parse("0 1 * * 0#1");
```

#### Occurrence

Get the next occurrence from a given date or supply a different time zone to find the next occurrence in that time zone.

```csharp
var nOcc = cparsed.GetNextOccurrence(DateTimeOffset.Now);

//You can also supply a timezone:
var nOcc = cparsed.GetNextOccurrence(DateTimeOffset.Now, TimeZoneInfo.Utc);
```

#### Print info

You can use that parsed CRON to display info about it.

```csharp
Console.WriteLine(cparsed.ToString());
//Prints: on minute 0 on hour 1 on the 1st Sunday
```

#### Inverse Period

The only other method you may care about is the **`InversePeriod`**. **`InversePeriod`** is interesting as it takes the CRON string and determines how consecutively it runs.

```csharp
var inv = Cron.Parse("* 1-2 * * *").GetInversePeriod(DateTimeOffset.Now);
Console.WriteLine($"From {inv.Item1:G} to {inv.Item2:G}");

//Prints: From 1/1/2023 1:00:00 AM to 1/1/2023 2:59:00 AM
```

Notice how this CRON would run from 1AM consistently at every interval (minute) inclusively to 2:59AM? This method is an interesting way to use CRON data to specify ranges of time.

## CRON in Perigee

There are bunch of ways to use CRON strings in Perigee. Let's take a look at a few:

#### Agents

[SyncAgents](https://docs.perigee.software/core-modules/event-sources/scheduled-logic/sync-agent) use CRON strings to determine when to run, and even when to create blackout periods. You can see more in the linked section. Here's a quick preview!

{% code lineNumbers="true" %}

```csharp
taskConfig.AddAgent("DailySync", "DailySync", "DailyDB", 
new SyncAgentSourceMemory("SA.json"), AgentRunCondition.RunIfPastDue,

(configAgent) => configAgent.SetSyncLimitPerDay(2).SetSync(null, "55 6 * * *"),

(ct, l, executeHandler) => 
    DailySync.sync(taskConfig, taskConfig.CTS.Token, log, executeHandler, "DailyDB"),

(ct, l, treeHandler) => { },

TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(10), false)
    .LinkToConfig("Agents:DailySyncEnabled");
```

{% endcode %}

#### BlockUntil&#x20;

This is a handy way of creating an awaitable task, or thread blocking mechanism using a CRON string.

```csharp
//Async wait until the 0th second of every 5th minute
await PerigeeUtil.BlockUntil("0 */5 * * * *");

//Or for non async methods
PerigeeUtil.BlockUntil("0 */5 * * * *").GetAwaiter().GetResult();
```

#### Methods using CRON

As part of the core set of events in Perigee, you can easily add CRON methods.

```csharp
PerigeeApplication.ApplicationNoInit("Crons", (c) =>
{
    c.AddCRON("CronMethod", "0 */5 * * * *", (ct, l) => {
        //Run's every 5 minutes at second 0
    });

});
```

## CRON Testing Resources

#### A method to parse and print

A handy little method to print the definition of a CRON string, as well as print the next occurrence:

```csharp
void PrintCRON(string inputStr)
{
    Console.WriteLine(inputStr);
    var cparsed = Cron.Parse(inputStr);
    Console.WriteLine(cparsed.ToString());
    var nOcc = cparsed.GetNextOccurrence(DateTimeOffset.Now);
    Console.WriteLine(nOcc.Value.ToString("G") + Environment.NewLine);
}
```

#### A site to test CRON data

This is an amazing site to visually and instantly see the results of a CRON.&#x20;

{% hint style="warning" %}
FYI, They don't supports seconds or the special character options :thumbsup:
{% endhint %}

{% embed url="<https://crontab.guru>" %}
