Javascript cron-to-human-readable translatorGenerating readable text in a human language from machine-readable dataNode.js backup cron jobEfficient human readable timedeltaOutput human readable timeMilliseconds to Time string & Time string to MillisecondsCalculate attendance compliance based on attendance recordParsing cron expressionISO 8601 dates & times format into a more human readable formatPython library for calculating next and previous time of the cron-like scheduled taskAlgorithm to find the number of years, months, days, etc between two dates
How to prevent "they're falling in love" trope
What are some good books on Machine Learning and AI like Krugman, Wells and Graddy's "Essentials of Economics"
Determining Impedance With An Antenna Analyzer
Is it inappropriate for a student to attend their mentor's dissertation defense?
Probability that a draw from a normal distribution is some number greater than another draw from the same distribution
Madden-Julian Oscillation (MJO) - How to interpret the index?
iPad being using in wall mount battery swollen
How to add frame around section using titlesec?
What type of content (depth/breadth) is expected for a short presentation for Asst Professor interview in the UK?
Personal Teleportation: From Rags to Riches
What about the virus in 12 Monkeys?
How dangerous is XSS?
How much of data wrangling is a data scientist's job?
Can I run a new neutral wire to repair a broken circuit?
Are there any examples of a variable being normally distributed that is *not* due to the Central Limit Theorem?
What does the expression "A Mann!" means
Can the Meissner effect explain very large floating structures?
What do you call someone who asks many questions?
One verb to replace 'be a member of' a club
How could indestructible materials be used in power generation?
Why doesn't using multiple commands with a || or && conditional work?
Arrow those variables!
Forming a German sentence with/without the verb at the end
Is this a hacking script in function.php?
Javascript cron-to-human-readable translator
Generating readable text in a human language from machine-readable dataNode.js backup cron jobEfficient human readable timedeltaOutput human readable timeMilliseconds to Time string & Time string to MillisecondsCalculate attendance compliance based on attendance recordParsing cron expressionISO 8601 dates & times format into a more human readable formatPython library for calculating next and previous time of the cron-like scheduled taskAlgorithm to find the number of years, months, days, etc between two dates
$begingroup$
I'm developing a webpage displaying the scheduled pipelines from all projects of a GitLab instance. The scheduled time is expressed using CRON expressions, i.e. five digits as follows:

Because not all future users of my webpage are familiar with CRON expressions, I wrote a script for translating it into a human-readable time expression.
Some important information for understanding the logic behind the code:
"7" is not used as an alias for "Sunday" on my GitLab instance.
Timezones are not taken into account (...yet). I'm considering all CRON expressions as UTC times for now.- Times are expressed in the 24 hours format (so 11:23PM is 23h23)
- The pipelines that we launch take a lot of time to be fully executed, which is why we don't allow the first digit of the CRON expression to be
*.
Some examples of cron-to-string conversion:
0 4 * * * * → "Runs at 04h00 every day"
0 23 * * 0 → "Runs at 23h00 on Sundays"
0 4 1 * * → "Runs at 04h00 on the 1st day of every month"
The code
function convertCronToString(cronExpression)
var cron = cronExpression.split(" ");
var minutes = cron[0];
var hours = cron[1];
var dayOfMonth = cron[2];
var month = cron[3];
var dayOfWeek = cron[4];
var cronToString = "Runs at ";
// Formatting time if composed of zeros
if (minutes === "0") minutes = "00";
if (hours === "0") hours = "00";
// If it's not past noon add a zero before the hour to make it look like "04h00" instead of "4h00"
else if (hours.length === 1 && hours !== "*")
hours = "0" + hours;
// Our activities do not allow launching pipelines every minute. It won't be processed.
if (minutes === "*")
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
cronToString = cronToString + hours + "h" + minutes + " ";
if (dayOfWeek === "0,6") dayOfWeek = "on weekends";
else if (dayOfWeek === "1-5") dayOfWeek = "on weekdays";
else if (dayOfWeek.length === 1)
if (dayOfWeek === "*" && dayOfMonth === "*") dayOfWeek = "every day ";
else if (dayOfWeek === "*" && dayOfMonth !== "*")
cronToString = cronToString + "on the " + dayOfMonth;
if (
dayOfMonth === "1" else if (dayOfWeek !== "*" && dayOfMonth === "*")
switch (parseInt(dayOfWeek))
case 0:
dayOfWeek = "on Sundays";
break;
case 1:
dayOfWeek = "on Mondays";
break;
case 2:
dayOfWeek = "on Tuesdays";
break;
case 3:
dayOfWeek = "on Wednesdays";
break;
case 4:
dayOfWeek = "on Thursdays";
break;
case 5:
dayOfWeek = "on Fridays";
break;
case 6:
dayOfWeek = "on Saturdays";
break;
default:
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
return cronToString;
cronToString = cronToString + dayOfWeek + " ";
return cronToString;
Question
How could this code be optimized?
Additional information
- This method is part of a Vue.JS component so I apologize if I forgot to translate some of the Vue-specific into Vanilla Javascript.
- I have not implemented the code in case the pipeline is supposed to run on a given number of days of the week/month when provided as a suite of numbers separated by commas.
javascript parsing datetime
$endgroup$
add a comment |
$begingroup$
I'm developing a webpage displaying the scheduled pipelines from all projects of a GitLab instance. The scheduled time is expressed using CRON expressions, i.e. five digits as follows:

Because not all future users of my webpage are familiar with CRON expressions, I wrote a script for translating it into a human-readable time expression.
Some important information for understanding the logic behind the code:
"7" is not used as an alias for "Sunday" on my GitLab instance.
Timezones are not taken into account (...yet). I'm considering all CRON expressions as UTC times for now.- Times are expressed in the 24 hours format (so 11:23PM is 23h23)
- The pipelines that we launch take a lot of time to be fully executed, which is why we don't allow the first digit of the CRON expression to be
*.
Some examples of cron-to-string conversion:
0 4 * * * * → "Runs at 04h00 every day"
0 23 * * 0 → "Runs at 23h00 on Sundays"
0 4 1 * * → "Runs at 04h00 on the 1st day of every month"
The code
function convertCronToString(cronExpression)
var cron = cronExpression.split(" ");
var minutes = cron[0];
var hours = cron[1];
var dayOfMonth = cron[2];
var month = cron[3];
var dayOfWeek = cron[4];
var cronToString = "Runs at ";
// Formatting time if composed of zeros
if (minutes === "0") minutes = "00";
if (hours === "0") hours = "00";
// If it's not past noon add a zero before the hour to make it look like "04h00" instead of "4h00"
else if (hours.length === 1 && hours !== "*")
hours = "0" + hours;
// Our activities do not allow launching pipelines every minute. It won't be processed.
if (minutes === "*")
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
cronToString = cronToString + hours + "h" + minutes + " ";
if (dayOfWeek === "0,6") dayOfWeek = "on weekends";
else if (dayOfWeek === "1-5") dayOfWeek = "on weekdays";
else if (dayOfWeek.length === 1)
if (dayOfWeek === "*" && dayOfMonth === "*") dayOfWeek = "every day ";
else if (dayOfWeek === "*" && dayOfMonth !== "*")
cronToString = cronToString + "on the " + dayOfMonth;
if (
dayOfMonth === "1" else if (dayOfWeek !== "*" && dayOfMonth === "*")
switch (parseInt(dayOfWeek))
case 0:
dayOfWeek = "on Sundays";
break;
case 1:
dayOfWeek = "on Mondays";
break;
case 2:
dayOfWeek = "on Tuesdays";
break;
case 3:
dayOfWeek = "on Wednesdays";
break;
case 4:
dayOfWeek = "on Thursdays";
break;
case 5:
dayOfWeek = "on Fridays";
break;
case 6:
dayOfWeek = "on Saturdays";
break;
default:
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
return cronToString;
cronToString = cronToString + dayOfWeek + " ";
return cronToString;
Question
How could this code be optimized?
Additional information
- This method is part of a Vue.JS component so I apologize if I forgot to translate some of the Vue-specific into Vanilla Javascript.
- I have not implemented the code in case the pipeline is supposed to run on a given number of days of the week/month when provided as a suite of numbers separated by commas.
javascript parsing datetime
$endgroup$
$begingroup$
@422_unprocessable_entity Mmh, that's possible that it's one of the differences between Vue and Javascript. I'll edit to suit the JS syntax. Thanks for spotting this!
$endgroup$
– avazula
Feb 19 at 10:54
1
$begingroup$
Since you didn't say you could use,or-indayOfWeek, I looked up how these are formed. Does your code correctly handle0,30 0,12 1,8,15,22,29 1-12 *?
$endgroup$
– Peilonrayz
Feb 19 at 12:29
add a comment |
$begingroup$
I'm developing a webpage displaying the scheduled pipelines from all projects of a GitLab instance. The scheduled time is expressed using CRON expressions, i.e. five digits as follows:

Because not all future users of my webpage are familiar with CRON expressions, I wrote a script for translating it into a human-readable time expression.
Some important information for understanding the logic behind the code:
"7" is not used as an alias for "Sunday" on my GitLab instance.
Timezones are not taken into account (...yet). I'm considering all CRON expressions as UTC times for now.- Times are expressed in the 24 hours format (so 11:23PM is 23h23)
- The pipelines that we launch take a lot of time to be fully executed, which is why we don't allow the first digit of the CRON expression to be
*.
Some examples of cron-to-string conversion:
0 4 * * * * → "Runs at 04h00 every day"
0 23 * * 0 → "Runs at 23h00 on Sundays"
0 4 1 * * → "Runs at 04h00 on the 1st day of every month"
The code
function convertCronToString(cronExpression)
var cron = cronExpression.split(" ");
var minutes = cron[0];
var hours = cron[1];
var dayOfMonth = cron[2];
var month = cron[3];
var dayOfWeek = cron[4];
var cronToString = "Runs at ";
// Formatting time if composed of zeros
if (minutes === "0") minutes = "00";
if (hours === "0") hours = "00";
// If it's not past noon add a zero before the hour to make it look like "04h00" instead of "4h00"
else if (hours.length === 1 && hours !== "*")
hours = "0" + hours;
// Our activities do not allow launching pipelines every minute. It won't be processed.
if (minutes === "*")
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
cronToString = cronToString + hours + "h" + minutes + " ";
if (dayOfWeek === "0,6") dayOfWeek = "on weekends";
else if (dayOfWeek === "1-5") dayOfWeek = "on weekdays";
else if (dayOfWeek.length === 1)
if (dayOfWeek === "*" && dayOfMonth === "*") dayOfWeek = "every day ";
else if (dayOfWeek === "*" && dayOfMonth !== "*")
cronToString = cronToString + "on the " + dayOfMonth;
if (
dayOfMonth === "1" else if (dayOfWeek !== "*" && dayOfMonth === "*")
switch (parseInt(dayOfWeek))
case 0:
dayOfWeek = "on Sundays";
break;
case 1:
dayOfWeek = "on Mondays";
break;
case 2:
dayOfWeek = "on Tuesdays";
break;
case 3:
dayOfWeek = "on Wednesdays";
break;
case 4:
dayOfWeek = "on Thursdays";
break;
case 5:
dayOfWeek = "on Fridays";
break;
case 6:
dayOfWeek = "on Saturdays";
break;
default:
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
return cronToString;
cronToString = cronToString + dayOfWeek + " ";
return cronToString;
Question
How could this code be optimized?
Additional information
- This method is part of a Vue.JS component so I apologize if I forgot to translate some of the Vue-specific into Vanilla Javascript.
- I have not implemented the code in case the pipeline is supposed to run on a given number of days of the week/month when provided as a suite of numbers separated by commas.
javascript parsing datetime
$endgroup$
I'm developing a webpage displaying the scheduled pipelines from all projects of a GitLab instance. The scheduled time is expressed using CRON expressions, i.e. five digits as follows:

Because not all future users of my webpage are familiar with CRON expressions, I wrote a script for translating it into a human-readable time expression.
Some important information for understanding the logic behind the code:
"7" is not used as an alias for "Sunday" on my GitLab instance.
Timezones are not taken into account (...yet). I'm considering all CRON expressions as UTC times for now.- Times are expressed in the 24 hours format (so 11:23PM is 23h23)
- The pipelines that we launch take a lot of time to be fully executed, which is why we don't allow the first digit of the CRON expression to be
*.
Some examples of cron-to-string conversion:
0 4 * * * * → "Runs at 04h00 every day"
0 23 * * 0 → "Runs at 23h00 on Sundays"
0 4 1 * * → "Runs at 04h00 on the 1st day of every month"
The code
function convertCronToString(cronExpression)
var cron = cronExpression.split(" ");
var minutes = cron[0];
var hours = cron[1];
var dayOfMonth = cron[2];
var month = cron[3];
var dayOfWeek = cron[4];
var cronToString = "Runs at ";
// Formatting time if composed of zeros
if (minutes === "0") minutes = "00";
if (hours === "0") hours = "00";
// If it's not past noon add a zero before the hour to make it look like "04h00" instead of "4h00"
else if (hours.length === 1 && hours !== "*")
hours = "0" + hours;
// Our activities do not allow launching pipelines every minute. It won't be processed.
if (minutes === "*")
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
cronToString = cronToString + hours + "h" + minutes + " ";
if (dayOfWeek === "0,6") dayOfWeek = "on weekends";
else if (dayOfWeek === "1-5") dayOfWeek = "on weekdays";
else if (dayOfWeek.length === 1)
if (dayOfWeek === "*" && dayOfMonth === "*") dayOfWeek = "every day ";
else if (dayOfWeek === "*" && dayOfMonth !== "*")
cronToString = cronToString + "on the " + dayOfMonth;
if (
dayOfMonth === "1" else if (dayOfWeek !== "*" && dayOfMonth === "*")
switch (parseInt(dayOfWeek))
case 0:
dayOfWeek = "on Sundays";
break;
case 1:
dayOfWeek = "on Mondays";
break;
case 2:
dayOfWeek = "on Tuesdays";
break;
case 3:
dayOfWeek = "on Wednesdays";
break;
case 4:
dayOfWeek = "on Thursdays";
break;
case 5:
dayOfWeek = "on Fridays";
break;
case 6:
dayOfWeek = "on Saturdays";
break;
default:
cronToString =
"Unreadable cron format. Cron will be displayed in its raw form: " +
cronExpression;
return cronToString;
cronToString = cronToString + dayOfWeek + " ";
return cronToString;
Question
How could this code be optimized?
Additional information
- This method is part of a Vue.JS component so I apologize if I forgot to translate some of the Vue-specific into Vanilla Javascript.
- I have not implemented the code in case the pipeline is supposed to run on a given number of days of the week/month when provided as a suite of numbers separated by commas.
javascript parsing datetime
javascript parsing datetime
edited 1 min ago
Sᴀᴍ Onᴇᴌᴀ
10.1k62167
10.1k62167
asked Feb 19 at 9:55
avazulaavazula
1868
1868
$begingroup$
@422_unprocessable_entity Mmh, that's possible that it's one of the differences between Vue and Javascript. I'll edit to suit the JS syntax. Thanks for spotting this!
$endgroup$
– avazula
Feb 19 at 10:54
1
$begingroup$
Since you didn't say you could use,or-indayOfWeek, I looked up how these are formed. Does your code correctly handle0,30 0,12 1,8,15,22,29 1-12 *?
$endgroup$
– Peilonrayz
Feb 19 at 12:29
add a comment |
$begingroup$
@422_unprocessable_entity Mmh, that's possible that it's one of the differences between Vue and Javascript. I'll edit to suit the JS syntax. Thanks for spotting this!
$endgroup$
– avazula
Feb 19 at 10:54
1
$begingroup$
Since you didn't say you could use,or-indayOfWeek, I looked up how these are formed. Does your code correctly handle0,30 0,12 1,8,15,22,29 1-12 *?
$endgroup$
– Peilonrayz
Feb 19 at 12:29
$begingroup$
@422_unprocessable_entity Mmh, that's possible that it's one of the differences between Vue and Javascript. I'll edit to suit the JS syntax. Thanks for spotting this!
$endgroup$
– avazula
Feb 19 at 10:54
$begingroup$
@422_unprocessable_entity Mmh, that's possible that it's one of the differences between Vue and Javascript. I'll edit to suit the JS syntax. Thanks for spotting this!
$endgroup$
– avazula
Feb 19 at 10:54
1
1
$begingroup$
Since you didn't say you could use
, or - in dayOfWeek, I looked up how these are formed. Does your code correctly handle 0,30 0,12 1,8,15,22,29 1-12 *?$endgroup$
– Peilonrayz
Feb 19 at 12:29
$begingroup$
Since you didn't say you could use
, or - in dayOfWeek, I looked up how these are formed. Does your code correctly handle 0,30 0,12 1,8,15,22,29 1-12 *?$endgroup$
– Peilonrayz
Feb 19 at 12:29
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
You do a lot of tests. It would be simplier if you implement a few objects containing your different values and you just display these values.
You'd have to do enough objects to cover all cases but you limit the tests to the minimum this way.
Example :
// I won't print every cases but you got the idea
let dayOfWeekWhenNoMonthIsSpecified =
'*' : 'every day', '0' : 'on Sundays', '1' : 'on Mondays',
'0,6' : 'on weekends', '1-5' : 'on weekdays'
;
cronToString = "Runs " + dayOfWeekWhenNoMonthIsSpecified[cron[4]];
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213790%2fjavascript-cron-to-human-readable-translator%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
You do a lot of tests. It would be simplier if you implement a few objects containing your different values and you just display these values.
You'd have to do enough objects to cover all cases but you limit the tests to the minimum this way.
Example :
// I won't print every cases but you got the idea
let dayOfWeekWhenNoMonthIsSpecified =
'*' : 'every day', '0' : 'on Sundays', '1' : 'on Mondays',
'0,6' : 'on weekends', '1-5' : 'on weekdays'
;
cronToString = "Runs " + dayOfWeekWhenNoMonthIsSpecified[cron[4]];
$endgroup$
add a comment |
$begingroup$
You do a lot of tests. It would be simplier if you implement a few objects containing your different values and you just display these values.
You'd have to do enough objects to cover all cases but you limit the tests to the minimum this way.
Example :
// I won't print every cases but you got the idea
let dayOfWeekWhenNoMonthIsSpecified =
'*' : 'every day', '0' : 'on Sundays', '1' : 'on Mondays',
'0,6' : 'on weekends', '1-5' : 'on weekdays'
;
cronToString = "Runs " + dayOfWeekWhenNoMonthIsSpecified[cron[4]];
$endgroup$
add a comment |
$begingroup$
You do a lot of tests. It would be simplier if you implement a few objects containing your different values and you just display these values.
You'd have to do enough objects to cover all cases but you limit the tests to the minimum this way.
Example :
// I won't print every cases but you got the idea
let dayOfWeekWhenNoMonthIsSpecified =
'*' : 'every day', '0' : 'on Sundays', '1' : 'on Mondays',
'0,6' : 'on weekends', '1-5' : 'on weekdays'
;
cronToString = "Runs " + dayOfWeekWhenNoMonthIsSpecified[cron[4]];
$endgroup$
You do a lot of tests. It would be simplier if you implement a few objects containing your different values and you just display these values.
You'd have to do enough objects to cover all cases but you limit the tests to the minimum this way.
Example :
// I won't print every cases but you got the idea
let dayOfWeekWhenNoMonthIsSpecified =
'*' : 'every day', '0' : 'on Sundays', '1' : 'on Mondays',
'0,6' : 'on weekends', '1-5' : 'on weekdays'
;
cronToString = "Runs " + dayOfWeekWhenNoMonthIsSpecified[cron[4]];
answered Feb 19 at 12:06
AweuzegagaAweuzegaga
1566
1566
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213790%2fjavascript-cron-to-human-readable-translator%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
$begingroup$
@422_unprocessable_entity Mmh, that's possible that it's one of the differences between Vue and Javascript. I'll edit to suit the JS syntax. Thanks for spotting this!
$endgroup$
– avazula
Feb 19 at 10:54
1
$begingroup$
Since you didn't say you could use
,or-indayOfWeek, I looked up how these are formed. Does your code correctly handle0,30 0,12 1,8,15,22,29 1-12 *?$endgroup$
– Peilonrayz
Feb 19 at 12:29