Generate cron expression from React Antd front end

Keywords: Javascript Front-end React cron

I wonder if you have found the following situations when playing the game:

(1) When playing some games, I found that his leaderboard is not updated from time to time, but updated every half an hour or an hour.

(2) Another example is the popular king glory mobile game. Its daily tasks are updated at 5 o'clock every day.

So, who controls these time controls so accurately? It turns out that these are the credit of the corn expression.

[1] What is a cron expression?

Before we know, let's give a few examples to see what the corn expression looks like
cron="0 */5 * * * ?"

cron="0 30 8,10,12,14,16 * * ?"

cron="0 0 */1 * * ?"

As you can see, corn expression is a set of strings composed of several numbers, spaces and symbols according to certain rules, so as to express the information of time.  

It seems to be a bit similar to regular expressions. They are all a string representing some information. But it is much simpler than regular expressions. When we first came into contact with regular expressions, we described them as ghost symbols ("ghosts know what you write"), and only Taoists can understand Taoist symbols. After reading the following contents, you will understand and write cron expressions in half an hour

[2] cron expression standard structure

So what exactly is this rule? Let's move on.

From the above example, we can see that the string is divided into six parts by five spaces.

Suppose we take ABCDEF as an example, and its standard format is "A B C D E F".

[3] Specific meaning of cron expression

What exactly does this ABCDEF mean? Next is the key point of the painting. Look carefully:

A represents seconds, B represents minutes, C represents hours, D represents days, E represents months, and F represents weeks

Therefore: "a B C D E F" - > "second minute hour day month week"

There are also years here. The week is followed by the year, but this year can be added or not. The addition is the format of "A B C D E F G".

Why not add years? What programs have you seen that specify which year to run in? Or every few years?

Therefore, the year is not practical. In addition, for the convenience of writing, the rules are simply omitted! Of course, that's right!

[4] Exemplar interpretation

cron="0 */5 * * * ?"

We can learn that:

Its second bit is 0, which means every 0 seconds, and the quantile is * / 5, which means every 5 minutes. So in general, it is executed every 5 minutes (every 5 minutes and 0 seconds);

cron="0 30 8,10,12,14,16 * * ?"

Its second bit is 0, its minute bit is 30, and its hour bit is a series of sets, which means that it is executed once every day at 8:30, 10:30, 12:30, 14:30 and 16:30;

cron="0 0 */1 * * ?"

I think you already know what it means. Yes, it is executed once every hour (0:00:00).

From the above three columns, I think you have understood the general meaning of orcn expression: the number represents the specific time, * represents any time, * / x represents every time, and you can also use the set to represent specific time points.

[5] More examples

(5.1) the time period is indicated by a dash (-):

For example, our working hours are 9:00 p.m. and 6:00 p.m. (from 9:00 a.m. to 6:00 p.m. from Monday to Friday), then the cron expression is: 0 09-18 * * Mon-Fri

Monday to Sunday: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday. Take the first three letters, and then capitalize to represent the week.

(5.2) use L for the Last, and l is the first letter of the word Last:

For example, assuming that the salary is paid at 2 p.m. on the last day of each day, the cron expression is: 0 0 14 L *?

Note: if the day of the week is not specified, it is usually replaced by a question mark.

Other functions #, which are not commonly used, will be introduced here. Friends who want to know can consult the information themselves, because they are rarely used in practical work.

The most commonly used method is to execute the program at a certain time point or at some time point, that is, the previous example explanation in [4].

[6] cron expression purpose

As shown in the preface, the main purpose of cron expression is to do some scheduled tasks in the program, such as the report data of some systems and the ranking list of some games. Because the real-time statistics of these data consume the program performance, it runs through automatic tasks every other period of time, which can greatly improve the user's browsing experience. If in the game, It can also add a sense of mystery.

In addition, for example, if you are engaged in platform docking and want to download your orders from some platforms, you must grab them every other time.

At present, there are two common Cron expressions, Linux   Java, there are no more extensions here. Interested students can learn by themselves. I have done a kind of Java generation here. Don't talk more nonsense, as shown in the figure above

 
First go to the index consolidation file

import React, { useState, useEffect } from 'react';
import { Tabs, Button } from 'antd';
import MinutePane from './MinutePane';
import HourPane from './HourPane';
import DayPane from './DayPane';
import MonthPane from './MonthPane';
import WeekPane from './WeekPane';
import YearPane from './YearPane';
import { minuteRegex, hourRegex, dayRegex, monthRegex, weekRegex, yearRegex } from './cron-regex';
import styles from './index.less';

const { TabPane } = Tabs;
const tabPaneStyle = { paddingLeft: 10, paddingBottom: 8, marginTop: -10 };
const getTabTitle = (text) => <div style={{ width: 50, textAlign: 'center' }}>{text}</div>;

function Cron(props) {
  const { style, footerStyle, value, onOk } = props;
  const [currentTab, setCurrentTab] = useState('2');
  const [second, setSecond] = useState('0');
  const [minute, setMinute] = useState('0');
  const [hour, setHour] = useState('0');
  const [day, setDay] = useState('*');
  const [month, setMonth] = useState('*');
  const [week, setWeek] = useState('?');
  const [year, setYear] = useState('*');

  const onParse = () => {
    if (value) {
      try {
        let [secondVal, minuteValue, hourVal, dayVal, monthVal, weekVal, yearVal] = value.split(' ');
        secondVal = 0;
        minuteValue = minuteRegex.test(minuteValue) ? minuteValue : '0';
        hourVal = hourRegex.test(hourVal) ? hourVal : '0';
        dayVal = dayRegex.test(dayVal) ? dayVal : '*';
        monthVal = monthRegex.test(monthVal) ? monthVal : '*';
        weekVal = weekRegex.test(weekVal) ? weekVal : '?';
        weekVal = dayVal !== '?' ? '?' : weekVal;
        yearVal = yearRegex.test(yearVal) ? yearVal : '*';
        setSecond(secondVal);
        setMinute(minuteValue);
        setHour(hourVal);
        setDay(dayVal);
        setMonth(monthVal);
        setWeek(weekVal);
        setYear(yearVal);
      } catch (error) {
        setSecond('0');
        setMinute('0');
        setHour('0');
        setDay('*');
        setMonth('*');
        setWeek('?');
        setYear('*');
      }
    }
  };

  useEffect(() => {
    onParse();
  }, [value]);

  const onGenerate = () => {
    if (onOk) {
      onOk([second, minute, hour, day, month, week, year].join(' '));
    }
  };

  const onChangeDay = (v) => {
    setDay(v);
    if (v !== '?') {
      setWeek('?');
    }
  };

  const onChangeWeek = (v) => {
    setWeek(v);
    if (v !== '?') {
      setDay('?');
    }
  };

  return (
    <div
      className={styles.root}
      style={{
        borderRadius: '4px',
        outline: 'none',
        boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
        ...style,
      }}
    >
      <Tabs tabBarGutter={0} animated destroyInactiveTabPane activeKey={currentTab} onChange={setCurrentTab}>
        <TabPane tab={getTabTitle('branch')} key="2" style={tabPaneStyle}>
          <MinutePane value={minute} onChange={setMinute} />
        </TabPane>
        <TabPane tab={getTabTitle('Time')} key="3" style={tabPaneStyle}>
          <HourPane value={hour} onChange={setHour} />
        </TabPane>
        <TabPane tab={getTabTitle('day')} key="4" style={tabPaneStyle}>
          <DayPane value={day} onChange={onChangeDay} />
        </TabPane>
        <TabPane tab={getTabTitle('month')} key="5" style={tabPaneStyle}>
          <MonthPane value={month} onChange={setMonth} />
        </TabPane>
        <TabPane tab={getTabTitle('week')} key="6" style={tabPaneStyle}>
          <WeekPane value={week} onChange={onChangeWeek} />
        </TabPane>
        <TabPane tab={getTabTitle('year')} key="7" style={tabPaneStyle}>
          <YearPane value={year} onChange={setYear} />
        </TabPane>
      </Tabs>
      <div style={{ borderTop: '1px solid #e8e8e8', padding: 10, textAlign: 'right', ...footerStyle }}>
        <Button type="primary" onClick={onGenerate}>
          generate
        </Button>
      </div>
    </div>
  );
}

export default Cron;

Regular value of cron regex cronvalue

/* eslint-disable max-len */
export const secondRegex = /^\*$|(^([0-9]|[1-5][0-9])-([0-9]|[1-5][0-9])$)|(^([0-9]|[1-5][0-9])\/\d+$)|(^(([0-9]|[1-5][0-9]),)*([0-9]|[1-5][0-9])$)/;
export const minuteRegex = /^\*$|(^([0-9]|[1-5][0-9])-([0-9]|[1-5][0-9])$)|(^([0-9]|[1-5][0-9])\/\d+$)|(^(([0-9]|[1-5][0-9]),)*([0-9]|[1-5][0-9])$)/;
export const hourRegex = /(^\*$)|(^([0-9]|(1[0-9])|(2[0-3]))-([0-9]|(1[0-9])|(2[0-3]))$)|(^([0-9]|(1[0-9])|(2[0-3]))\/\d+$)|(^(([0-9]|(1[0-9])|(2[0-3])),)*([0-9]|(1[0-9])|(2[0-3]))$)/;
export const dayRegex = /^\*$|^\?$|(^([1-9]|[1-2][0-9]|3[0-1])-([1-9]|[1-2][0-9]|3[0-1])$)|(^([1-9]|[1-2][0-9]|3[0-1])\/\d+$)|(^(([1-9]|[1-2][0-9]|3[0-1]),)*([1-9]|[1-2][0-9]|3[0-1])$)/;
export const monthRegex = /^\*$|(^([1-9]|1[0-2])-([1-9]|1[0-2])$)|(^([1-9]|1[0-2])\/\d+$)|(^(([1-9]|1[0-2]),)*([1-9]|1[0-2])$)/;
export const weekRegex = /^\*$|^\?$|(^(SUN|MON|TUE|WED|THU|FRI|SAT)-(SUN|MON|TUE|WED|THU|FRI|SAT)$)|(^(SUN|MON|TUE|WED|THU|FRI|SAT)#\d+$)|(^(SUN|MON|TUE|WED|THU|FRI|SAT)L$)|(^((SUN|MON|TUE|WED|THU|FRI|SAT),)*(SUN|MON|TUE|WED|THU|FRI|SAT)$)/;
export const yearRegex = /^\*$|^\?$|(^(2019|20[2-5][0-9]|206[0-6])-(2019|20[2-5][0-9]|206[0-6])$)|(^(2019|20[2-5][0-9]|206[0-6])\/\d+$)|(^((2019|20[2-5][0-9]|206[0-6]),)*(2019|20[2-5][0-9]|206[0-6])$)/;

Enter one of the modules (the second, minute, hour, day, month and anniversary are the same here, taking month as an example)

 

 

// index layout page
import { Radio } from 'antd';
import React from 'react';
import InputFromInterval from './InputFromInterval';
import InputFromTo from './InputFromTo';
import InputSpecified from './InputSpecified';

const radioStyle = { display: 'block', lineHeight: '32px' };

function MonthPane(props) {
    const { value, onChange } = props;
    let currentRadio = 0;
    if (value === '*') {
        currentRadio = 0;
    } else if (value.indexOf('-') > -1) {
        currentRadio = 1;
    } else if (value.indexOf('/') > -1) {
        currentRadio = 2;
    } else {
        currentRadio = 3;
    }

    const onChangeRadio = (e) => {
        const valueType = e.target.value;
        const defaultValues = ['*', '1-1', '1/1', '1'];
        onChange(defaultValues[valueType]);
    };

    return (
        <Radio.Group style={{ width: '100%' }} value={currentRadio} onChange={onChangeRadio}>
            <Radio style={radioStyle} value={0}>
                Every month
            </Radio>
            <Radio style={radioStyle} value={1}>
                <InputFromTo disabled={currentRadio !== 1} value={value} onChange={onChange} />
            </Radio>
            <Radio style={radioStyle} value={2}>
                <InputFromInterval disabled={currentRadio !== 2} value={value} onChange={onChange} />
            </Radio>
            <Radio style={radioStyle} value={3}>
                <InputSpecified disabled={currentRadio !== 3} value={value} onChange={onChange} />
            </Radio>
        </Radio.Group>
    );
}

export default MonthPane;

From month X to month Y, it is implemented once a month

import React from 'react';
import { InputNumber } from 'antd';

function InputFromTo(props) {
    const { disabled, value, onChange } = props;
    let from = 0;
    let to = 0;
    if (!disabled) {
        [from, to] = value.split('-').map((v) => parseInt(v, 10));
    }
    const onChangeFrom = (v) => onChange(`${v || 0}-${to}`);
    const onChangeTo = (v) => onChange(`${from}-${v || 0}`);

    return (
        <React.Fragment>
            from&nbsp;
            <InputNumber
                disabled={disabled}
                min={1}
                max={12}
                value={from}
                size="small"
                onChange={onChangeFrom}
                style={{ width: 100 }}
            />
            &nbsp;-&nbsp;
            <InputNumber
                disabled={disabled}
                min={1}
                max={12}
                value={to}
                size="small"
                onChange={onChangeTo}
                style={{ width: 100 }}
            />
            &nbsp;Monthly, once a month
        </React.Fragment>
    );
}

export default InputFromTo;

Every N months starting from month X
 

import React from 'react';
import { InputNumber } from 'antd';

function InputFromInterval(props) {
    const { disabled, value, onChange } = props;
    let from = 0;
    let interval = 0;
    if (!disabled) {
        [from, interval] = value.split('/').map((v) => parseInt(v, 10));
    }
    const onChangeFrom = (v) => onChange(`${v || 0}/${interval}`);
    const onChangeInterval = (v) => onChange(`${from}/${v || 0}`);

    return (
        <React.Fragment>
            from&nbsp;
            <InputNumber
                disabled={disabled}
                min={1}
                max={12}
                value={from}
                size="small"
                onChange={onChangeFrom}
                style={{ width: 100 }}
            />
            &nbsp;Every month&nbsp;
            <InputNumber
                disabled={disabled}
                min={1}
                max={12}
                value={interval}
                size="small"
                onChange={onChangeInterval}
                style={{ width: 100 }}
            />
            &nbsp;Once a month
        </React.Fragment>
    );
}

export default InputFromInterval;

Finally, specify a month to execute

import React, { useMemo } from 'react';
import { Checkbox, Row, Col } from 'antd';

function InputSpecified(props) {
    const { disabled, value, onChange } = props;
    let selected = [];
    if (!disabled) {
        selected = value.split(',').map((v) => parseInt(v, 10));
    }
    const onChangeSelected = (v) => onChange(v.length === 0 ? '1' : v.join(','));

    const checkList = useMemo(() => {
        const checks = [];
        for (let i = 1; i < 13; i++) {
            checks.push(
                <Col key={i} span={4}>
                    <Checkbox disabled={disabled} value={i}>
                        {i}
                    </Checkbox>
                </Col>,
            );
        }
        return checks;
    }, [disabled]);

    return (
        <React.Fragment>
            appoint
            <br />
            <Checkbox.Group style={{ width: '100%' }} value={selected} onChange={onChangeSelected}>
                <Row>{checkList}</Row>
            </Checkbox.Group>
        </React.Fragment>
    );
}

export default InputSpecified;

If there is anything wrong, please advise, thank you

Posted by PhpxZ on Mon, 22 Nov 2021 16:14:13 -0800