Giter Site home page Giter Site logo

bradymholt / cron-expression-descriptor Goto Github PK

View Code? Open in Web Editor NEW
975.0 28.0 186.0 77.46 MB

A .NET library that converts cron expressions into human readable descriptions.

Home Page: https://bradymholt.github.io/cron-expression-descriptor/

License: MIT License

C# 99.39% JavaScript 0.61%
cron cron-expression cron-libraries quartz human-readable-descriptions nuget c-sharp

cron-expression-descriptor's Introduction

Cron Expression Descriptor Build NuGet version


 Would you take a quick second and ⭐️ my repo?


A .NET library that converts cron expressions into human readable descriptions.

CronExpressionDescriptor.ExpressionDescriptor.GetDescription("* * * * *");
> "Every minute"

Author: Brady Holt (http://www.geekytidbits.com) License: MIT

Features

  • Supports all cron expression special characters including * / , - ? L W, #
  • Supports 5, 6 (w/ seconds or year), or 7 (w/ seconds and year) part cron expressions
  • Localization with support for 27 languages
  • Provides casing options (Sentence case, Title Case, lowercase, etc.)
  • Supports Quartz Enterprise Scheduler .NET cron expressions

Demo

https://bradymholt.github.io/cron-expression-descriptor

Download

Cron Expression Descriptor releases can be installed with NuGet.

Package Manager (Visual Studio)

Install-Package CronExpressionDescriptor

.NET CLI

dotnet add package CronExpressionDescriptor

Visit the NuGet Package page for more info.

View Releases for release version history.

Quick Start

CronExpressionDescriptor.ExpressionDescriptor.GetDescription("* * * * *");
> "Every minute"

Options

A CronExpressionDescriptor.Options object can be passed to GetDescription. The following options are available:

  • bool ThrowExceptionOnParseError - If exception occurs when trying to parse expression and generate description, whether to throw or catch and output the Exception message as the description. (Default: true)
  • bool Verbose - Whether to use a verbose description (Default: false)
  • bool DayOfWeekStartIndexZero - Whether to interpret cron expression DOW 1 as Sunday or Monday. (Default: true)
  • ?bool Use24HourTimeFormat - If true, descriptions will use a 24-hour clock (Default: false but some translations will default to true)
  • string Locale - The locale to use (Default: "en")

Example usage:

ExpressionDescriptor.GetDescription("0-10 11 * * *", new Options(){
    DayOfWeekStartIndexZero = false,
    Use24HourTimeFormat = true,
    Locale = "fr"
});

i18n

The following language translations are available.

To use one of these translations, pass in the Locale option to GetDescription. For example, to get the description of 0-10 11 * * * in German:

ExpressionDescriptor.GetDescription("0-10 11 * * *", new Options(){ Locale = "de" });
> "Jede Minute zwischen 11:00 und 11:10"

Alternatively, you can call ExpressionDescriptor.SetDefaultLocale("es"); first to set the default locale and then every usage will use this locale by default.

ExpressionDescriptor.SetDefaultLocale("es");

ExpressionDescriptor.GetDescription("*/45 * * * * *");
> "Cada 45 segundos"

ExpressionDescriptor.GetDescription("0-10 11 * * *");
> "Cada minuto entre las 11:00 AM y las 11:10 AM"

CurrentUICulture

If you are targeting a platform that supports .NET Standard >= 2.0, Thread.CurrentUICulture is supported for determining the default locale, without explicitly passing it in with the Locale option, so the following will work:

// .NET Standard >= 2.0 only
CultureInfo myCultureInfo = new CultureInfo("it-IT");
Thread.CurrentThread.CurrentUICulture = myCultureInfo;
ExpressionDescriptor.GetDescription("* * * * *");
> "Ogni minuto"

.NET Platform Support

Beginning with version 2.0.0, the NuGet package will contain a library targeting .NET Standard 1.1 and 2.0. This allows the library to be consumed by applications running on the following .NET platforms:

  • .NET Core >= 1.0
  • .NET Framework >= 4.5
  • Mono >= 4.6
  • (More)

If your application is targeting an earlier version of .NET Framework (i.e. 4.0 or 3.5), you can use version 1.21.2 as it has support back to .NET Framework 3.5. To install this version, run Install-Package CronExpressionDescriptor -Version 1.21.2.

Strong Name Signing

If you need an assembly that is signed with a strong name, you can use version 1.21.2 as it is currently the latest version signed with a strong name.

Ports

This library has been ported to several other languages.

Frequently Asked Questions

The cron expression I am passing in is not valid and this library is giving strange output. What should I do?

This library does not do full validation of cron expressions and assumes the expression passed in is valid. If you need to validate an expression consider using a library like Cronos.

Does this library support showing the "next" scheduled date?

No, this is not supported.

Examples

ExpressionDescriptor.GetDescription("* * * * *");

"Every minute"

ExpressionDescriptor.GetDescription("*/1 * * * *");

"Every minute"

ExpressionDescriptor.GetDescription("0 0/1 * * * ?");

"Every minute"

ExpressionDescriptor.GetDescription("0 0 * * * ?");

"Every hour"

ExpressionDescriptor.GetDescription("0 0 0/1 * * ?");

"Every hour"

ExpressionDescriptor.GetDescription("0 23 ? * MON-FRI");

"At 11:00 PM, Monday through Friday"

ExpressionDescriptor.GetDescription("* * * * * *");

"Every second"

ExpressionDescriptor.GetDescription("*/45 * * * * *");

"Every 45 seconds"

ExpressionDescriptor.GetDescription("*/5 * * * *");

"Every 5 minutes"

ExpressionDescriptor.GetDescription("0 0/10 * * * ?");

"Every 10 minutes"

ExpressionDescriptor.GetDescription("0 */5 * * * *");

"Every 5 minutes"

ExpressionDescriptor.GetDescription("30 11 * * 1-5");

"At 11:30 AM, Monday through Friday"

ExpressionDescriptor.GetDescription("30 11 * * *");

"At 11:30 AM"

ExpressionDescriptor.GetDescription("0-10 11 * * *");

"Every minute between 11:00 AM and 11:10 AM"

ExpressionDescriptor.GetDescription("* * * 3 *");

"Every minute, only in March"

ExpressionDescriptor.GetDescription("* * * 3,6 *");

"Every minute, only in March and June"

ExpressionDescriptor.GetDescription("30 14,16 * * *");

"At 02:30 PM and 04:30 PM"

ExpressionDescriptor.GetDescription("30 6,14,16 * * *");

"At 06:30 AM, 02:30 PM and 04:30 PM"

ExpressionDescriptor.GetDescription("46 9 * * 1");

"At 09:46 AM, only on Monday"

ExpressionDescriptor.GetDescription("23 12 15 * *");

"At 12:23 PM, on day 15 of the month"

ExpressionDescriptor.GetDescription("23 12 * JAN *");

"At 12:23 PM, only in January"

ExpressionDescriptor.GetDescription("23 12 ? JAN *");

"At 12:23 PM, only in January"

ExpressionDescriptor.GetDescription("23 12 * JAN-FEB *");

"At 12:23 PM, January through February"

ExpressionDescriptor.GetDescription("23 12 * JAN-MAR *");

"At 12:23 PM, January through March"

ExpressionDescriptor.GetDescription("23 12 * * SUN");

"At 12:23 PM, only on Sunday"

ExpressionDescriptor.GetDescription("*/5 15 * * MON-FRI");

"Every 5 minutes, between 03:00 PM and 03:59 PM, Monday through Friday"

ExpressionDescriptor.GetDescription("* * * * MON#3");

"Every minute, on the third Monday of the month"

ExpressionDescriptor.GetDescription("* * * * 4L");

"Every minute, on the last Thursday of the month"

ExpressionDescriptor.GetDescription("*/5 * L JAN *");

"Every 5 minutes, on the last day of the month, only in January"

ExpressionDescriptor.GetDescription("30 02 14 * * *");

"At 02:02:30 PM"

ExpressionDescriptor.GetDescription("5-10 * * * * *");

"Seconds 5 through 10 past the minute"

ExpressionDescriptor.GetDescription("5-10 30-35 10-12 * * *");

"Seconds 5 through 10 past the minute, minutes 30 through 35 past the hour, between 10:00 AM and 12:00 PM"

ExpressionDescriptor.GetDescription("30 */5 * * * *");

"At 30 seconds past the minute, every 05 minutes"

ExpressionDescriptor.GetDescription("0 30 10-13 ? * WED,FRI");

"At 30 minutes past the hour, between 10:00 AM and 01:00 PM, only on Wednesday and Friday"

ExpressionDescriptor.GetDescription("10 0/5 * * * ?");

"At 10 seconds past the minute, every 05 minutes"

ExpressionDescriptor.GetDescription("2-59/3 1,9,22 11-26 1-6 ?");

"Every 03 minutes, minutes 2 through 59 past the hour, at 01:00 AM, 09:00 AM, and 10:00 PM, between day 11 and 26 of the month, January through June"

ExpressionDescriptor.GetDescription("0 0 6 1/1 * ?");

"At 06:00 AM"

ExpressionDescriptor.GetDescription("0 5 0/1 * * ?");

"At 05 minutes past the hour"

ExpressionDescriptor.GetDescription("* * * * * * 2013");

"Every second, only in 2013"

ExpressionDescriptor.GetDescription("* * * * * 2013");

"Every minute, only in 2013"

ExpressionDescriptor.GetDescription("* * * * * 2013,2014");

"Every minute, only in 2013 and 2014"

ExpressionDescriptor.GetDescription("23 12 * JAN-FEB * 2013-2014");

"At 12:23 PM, January through February, 2013 through 2014"

ExpressionDescriptor.GetDescription("23 12 * JAN-MAR * 2013-2015");

"At 12:23 PM, January through March, 2013 through 2015"

cron-expression-descriptor's People

Contributors

alexandru-manea avatar ali33 avatar betacart avatar bradymholt avatar ellenhutchings avatar flyrmi avatar foka avatar illegitimis avatar ionmincu avatar ivansg avatar khalipskisiarhei avatar lnquy avatar marcfu avatar mdekok avatar metavige avatar micky2149 avatar mschuler avatar natenho avatar odinserj avatar panlatent avatar ptupitsyn avatar pzathief avatar rinaldihno avatar rmja avatar roobin avatar sadedil avatar serguzest avatar tbudurovych avatar tomasz-soltysik avatar totalmace avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cron-expression-descriptor's Issues

Bug

It cannot parse this:
58 13 2,18 1,3-5,7,9 *

problem happen when it try to convert 1,3 to int

Error on minutes combined with multiple hour-ranges

When specifying a specific minute, hour-ranges fail:

1 1,3-4 * * * //Expecting: At 1 minutes past the hour, at 01:00 AM and 03:00 AM through 04:59 AM

Results in:
An error occured when generating the expression description. Check the cron expression syntax.

What does work:

* 1,3-4 * * *     //Every minute, at 01:00 AM and 03:00 AM through 04:59 AM
*/15 1,3-4 * * *  //Every 15 minutes, at 01:00 AM and 03:00 AM through 04:59 AM
1 3,4,5 * * *     //At 03:01 AM, 04:01 AM and 05:01 AM

See also: http://cronexpressiondescriptor.azurewebsites.net/?Language=en-US&DayOfWeekStartIndexOne=false&Use24HourFormat=false&VerboseDescription=false&Expression=1+4%2C2-3+*+*+*

Start minute not shown in 0 5/30 * * * ?

The expression 0 5/30 * * * ? comes back as Every 30 minutes.

It should say something like Every 30 minutes starting on minute 5. The same is true for the seconds and hours.

Bug with weekday regex for days longer than 1 digit e.g. 13th

Hi there
Great project! However if you run these 2 unit tests you'll see your Regex is slightly incorrect.
[TestMethod]
public void TestParticularHighWeekdayOfTheMonth()
{
Assert.AreEqual("Every minute, on the weekday nearest day 13 of the month", ExpressionDescriptor.GetDescription("* * 13W * *"));
}

[TestMethod]
public void TestParticularHighWeekdayOfTheMonth2()
{
Assert.AreEqual("Every minute, on the weekday nearest day 13 of the month", ExpressionDescriptor.GetDescription("* * W13 * *"));
}

Documentation?

Is there any documentation on the classes? I can't find any - am I overlooking it somewhere?

Number formatting with initial zero

The cron expression 30 */2 * * * says At 30 minutes past the hour, every 02 hours.

Wouldn't it be better if it say At 30 minutes past the hour, every 2 hours?

Setting Options.DayOfWeekStatIndexZero to 'false' breaks DOW logic for some expressions with '#' in them.

To reproduce, set this.DayOfWeekStartIndexZero = false; in Options.cs and run tests.

Essentially when DayOfWeekStartIndexZero = set to false all occurrences of say value '1' in the expression (which in this scenario is Sunday instead of Monday) are replaced with the value '0'. If however the expression is '1#1' (first Sunday of the month) the replacement logic used now will change this expression into '0#0' which is wrong (it should be '0#1').

Note that the unit testing also does not test this option properly even if the logic bug is resolved.

Suggest using a ReplaceFirst() function like this :

static string ReplaceFirst(string text, string search, string replace)
{
    var pos = text.IndexOf(search, StringComparison.Ordinal);
    if (pos < 0)
    {
        return text;
    }
    return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}

and changing the line :

expressionParts[5] = expressionParts[5].Replace((i + 1).ToString(), i.ToString());

in ExpressionParser.cs to :

expressionParts[5] = ReplaceFirst(expressionParts[5], (i + 1).ToString(CultureInfo.InvariantCulture), i.ToString(CultureInfo.InvariantCulture));

Cheers,
Hans

Verbose description duplicates "Every day" token for day of month and day of week

Currently, there are no tests for the verbose description. Only for the Romanian language. Wherever "ComaEveryDay" is involved, that token gets duplicated for day of week and day of month.

Example for the English language:
expression: */1 * * * *
non-verbose: every minute
verbose: every minute, every hour, every day, every day

This could be avoided by separate resource entries for "ComaEveryDayOfWeek" and "ComaEveryDayOfMonth", or by merging duplicates for the verbose description.

Bug in: every X day of the week in range with sunday start one

var options = new Options { DayOfWeekStartIndexZero = false };
return ExpressionDescriptor.GetDescription("* * * ? * 2-6/2", options);

Actual result:
Every second, every 1 days of the week, Monday through Friday
Expected:
Every second, every 2 days of the week, Monday through Friday

Wrong description when there is a trailing space

When a CRON expression contains a trailing space, I'm getting wrong description. Please see the following example.

ExpressionDescriptor.GetDescription("0 7 * * * ");
// Returns "At 07 minutes past the hour" instead of "At 07:00 AM"

As a simple fix, we can trim the given expression string before the processing. I can make a PR, if you wish.

Assembly binding redirects required in v2.0.x in 4.6.1 project

Originally described in: #84 (comment)

After upgrading from 1.21.2 to 2.0.1 in my .Net 4.6.1 app, maybe due to the netstandard requirement, I received a bunch of warnings regarding assembly bindings.
The suggestion is that the 53 assembly bindings should be made to map
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.6.1\Facades....dll (some version)
to:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\ref....dll (some later version)

Effectively this will result in:

<dependentAssembly>
    <assemblyIdentity name="System.Reflection.Extensions" publicKeyToken="B03F5F7F11D50A3A" culture="neutral"/>
    <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0"/>
</dependentAssembly>
....

As my machine and my target machines are using .Net 4.6.1 I'm reluctant to use this assembly redirect, as I don't know if these new library versions are supported by my target environments.

Can't parse expression

The following does not work:
0 25 7-20/13 ? * *

but the following does work:
0 25 7-19/13 ? * *
or
0 25 7-21/13 ? * *

Using http://www.cronmaker.com/ all the above expressions work. I'm using the first expression with Quartz.Net and it is working as expected.

I'm using version 1.8.

NETCoreApp 1.0

Are there any plans to porting this to support framework NETCoreApp 1.0.0?

Schedule Example

Hi,
So if I were to do something like [T + 2 Month + 27 Days], how will the expression look in the descriptor?

Cannot describe "2,4-5 1 * * *"

ExpressionDescriptor.GetDescription("2,4-5 1 * * *", options) gives the following error:
"An error occured when generating the expression description. Check the cron expression syntax."

Descriptor shows "every day, every day"

When using the GetDescription, I get an unusual and unexpected result.

ExpressionDescriptor.GetDescription("30 4 1 * *", new Options {
    CasingType = CasingType.LowerCase,
    Verbose = true
});

Result:

at 04:30 am, on day 1 of the month, every day, every day.

I suppose this should only show "every day" once.

Problem with every X day of the week in range

Found issue (redundat comma) in parsing:
* * * ? * 1-5/2
Actual:
Every second, every 2 days of the week, , Monday through Friday
Expected:
Every second, every 2 days of the week, Monday through Friday

0 0 0/1 1/1 * ? * fails

User mausoma [email protected] sends the following message to the owners of Package 'CronExpressionDescriptor'.

Hi, when I generate a cron via http://www.cronmaker.com/ e.g .1x per hour, I can use it in quartz. It is: 0 0 0/1 1/1 * ? * Using this in your translator, I get an error message: "Error: Expression has too many parts (9). Expression must not have more than 7 parts."

Numbers in lieu of weekday names not supported

Using numbers (1-7) in lieu of weekday names (MON-FRI) is valid in cron expressions, as far as I can tell. At least, Quartz and Wikipedia say so. This library does not parse them and throws an error. As an example, "0 30 3 ? * 4,5,7" came directly from my Quartz database. When parsed an exception is thrown. If I change it to "0 30 3 ? * WED,THU,SAT" the output is correct.

Strong name signature could not be verified

Just updated from 1.21.2 to 2.0.0 using the NuGet Package Manager. When running the project I get the error:

Could not load file or assembly 'CronExpressionDescriptor' or one of its dependencies. Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key. (Exception from HRESULT: 0x80131045)

When downgrading to 1.21.2 the application works again.

Incorrect hour timing

I just check it on the sample, provided by QuartzNet, and it has failed.

The pattern is "0 0/30 8-9 5,20 * ?" (without quotes)

The response is:
Every 30 minutes, between 08:00 AM and 09:00 AM, on day 5 and 20 of the month

In QuartzNet tutorial:
"fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month"
(look here: http://quartznet.sourceforge.net/tutorial/lesson_6.html )

Description Problem [2,26-28 18 * * *]

Hi. I am trying to get description for the cron expression 2,26-28 18 * * *
The expression is valid but It returns an exception like that:
"An error occured when generating the expression description. Check the cron expression syntax."

Please help me :)
Thanks.

Difference in descriptor with Quartz

I've tested few CRON expression but they are not described as in Quratz website

0 * 14 * * ?    Fire every minute starting at 2pm and ending at 2:59pm, every day
0 0/5 14 * * ?  Fire every 5 minutes starting at 2pm and ending at 2:55pm, every day
0 0/5 14,18 * * ?   Fire every 5 minutes starting at 2pm and ending at 2:55pm, AND fire every 5 minutes starting at 6pm and ending at 6:55pm, every day
0 0-5 14 * * ?  Fire every minute starting at 2pm and ending at 2:05pm, every day
0 10,44 14 ? 3 WED  Fire at 2:10pm and at 2:44pm every Wednesday in the month of March.
0 15 10 ? * MON-FRI Fire at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday
0 15 10 15 * ?  Fire at 10:15am on the 15th day of every month
0 15 10 L * ?   Fire at 10:15am on the last day of every month
0 15 10 ? * 6L  Fire at 10:15am on the last Friday of every month
0 15 10 ? * 6L  Fire at 10:15am on the last Friday of every month

For example, when i test this 0 15 10 ? * 6L it says Saturday but the Quratz says Friday

0 15 10 ? * 6L Fire at 10:15am on the last Friday of every month (Ref)

cron

TimeZone Offset Support

It would be great if cron-expression-descriptor could support timezone offset.

For example one of options could be int TimeZone Offset and if it is setted during convertation it is be added to cron expression time.

Multiple intervals for minutes

The cronexpression "*/15,*/20 * * * *" is valid according to crontab.guru but the description generated is "every 15,* minutes". The description should be something like "every 15 and every 20 minutes".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.