Skip to content

Commit d18b5e8

Browse files
committed
Merge branch 'master' of https://github.com/jmrozanec/cron-utils
2 parents 00c26d7 + 5c2ad43 commit d18b5e8

14 files changed

Lines changed: 553 additions & 11 deletions

pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@
126126
<version>2.2.5</version>
127127
<scope>test</scope>
128128
</dependency>
129+
<dependency>
130+
<groupId>org.apache.commons</groupId>
131+
<artifactId>commons-lang3</artifactId>
132+
<version>3.9</version>
133+
</dependency>
134+
<dependency>
135+
<groupId>org.projectlombok</groupId>
136+
<artifactId>lombok</artifactId>
137+
<version>1.18.10</version>
138+
</dependency>
129139
</dependencies>
130140

131141
<build>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright 2019 fahmpeermoh
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.cronutils.converter;
15+
16+
import static org.apache.commons.lang3.StringUtils.isNumeric;
17+
18+
import java.util.Calendar;
19+
import java.util.Collections;
20+
import java.util.HashMap;
21+
import java.util.Map;
22+
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
public abstract class BaseCronTransformer {
27+
28+
protected static final Logger LOGGER = LoggerFactory
29+
.getLogger(BaseCronTransformer.class);
30+
31+
protected String[] cronParts;
32+
33+
protected Calendar calendarInstance;
34+
35+
protected Integer calendarField;
36+
37+
protected int cronFieldPosition;
38+
39+
protected Integer cronFieldValue;
40+
41+
Map<Integer, Integer> CRON_FIELDS_POSITION_MAP = Collections
42+
.unmodifiableMap(new HashMap<Integer, Integer>() {
43+
44+
private static final long serialVersionUID = 911848294809282617L;
45+
{
46+
put(0, Calendar.MINUTE);
47+
put(1, Calendar.HOUR_OF_DAY);
48+
put(2, Calendar.DAY_OF_MONTH);
49+
put(3, Calendar.MONTH);
50+
put(4, Calendar.DAY_OF_WEEK);
51+
}
52+
});
53+
54+
public void apply(String[] cronParts, Calendar calendarInstance) {
55+
this.cronParts = cronParts;
56+
this.calendarInstance = calendarInstance;
57+
for (int i = 0; i < cronParts.length; i++) {
58+
if (isNumeric(cronParts[i])) {
59+
calendarField = CRON_FIELDS_POSITION_MAP.get(i);
60+
cronFieldPosition = i;
61+
cronFieldValue = Integer.parseInt(cronParts[i]);
62+
transform();
63+
}
64+
}
65+
}
66+
67+
protected abstract void transform();
68+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2019 fahmpeermoh
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.cronutils.converter;
15+
16+
public class CalendarToCronTransformer extends BaseCronTransformer {
17+
18+
@Override
19+
protected void transform() {
20+
String updatedValue = String
21+
.valueOf(calendarInstance.get(calendarField));
22+
LOGGER.debug(
23+
"Updating cron field at position {} with {}, using calendar field {}",
24+
cronFieldPosition, updatedValue, calendarField);
25+
cronParts[cronFieldPosition] = updatedValue;
26+
}
27+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2019 fahmpeermoh
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.cronutils.converter;
15+
16+
import java.time.ZoneId;
17+
import java.util.Calendar;
18+
import java.util.TimeZone;
19+
20+
import org.apache.commons.lang3.StringUtils;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
24+
import lombok.Setter;
25+
26+
public class CronConverter {
27+
28+
private static final Logger LOGGER = LoggerFactory
29+
.getLogger(CronConverter.class);
30+
31+
private static final String CRON_FIELDS_SEPARATOR = " ";
32+
33+
private String[] cronParts;
34+
35+
private Calendar fromCalendar;
36+
37+
private String sourceCron;
38+
39+
private ZoneId sourceZoneId;
40+
41+
private ZoneId targetZoneId;
42+
43+
@Setter
44+
CronToCalendarTransformer toCalendarConverter = new CronToCalendarTransformer();
45+
46+
@Setter
47+
CalendarToCronTransformer toCronConverter = new CalendarToCronTransformer();
48+
49+
public CronConverter using(String cronExpression) {
50+
this.sourceCron = cronExpression;
51+
cronParts = cronExpression.split(CRON_FIELDS_SEPARATOR);
52+
LOGGER.debug("Cron '{}' split into {}", cronExpression, cronParts);
53+
return this;
54+
}
55+
56+
public CronConverter from(ZoneId zoneId) {
57+
sourceZoneId = zoneId;
58+
fromCalendar = getCalendar(zoneId);
59+
toCalendarConverter.apply(cronParts, fromCalendar);
60+
LOGGER.debug("Calendar object built using cron :{} and zoneID {} => {}",
61+
cronParts, zoneId, fromCalendar);
62+
return this;
63+
}
64+
65+
public CronConverter to(ZoneId zoneId) {
66+
targetZoneId = zoneId;
67+
Calendar toCalendar = getCalendar(zoneId);
68+
toCalendar.setTimeInMillis(fromCalendar.getTimeInMillis());
69+
LOGGER.debug(
70+
"Calendar object built from calendar {} and zoneID {} => {}",
71+
fromCalendar, zoneId, toCalendar);
72+
toCronConverter.apply(cronParts, toCalendar);
73+
LOGGER.debug("cron after applying calendar {} => {}", toCalendar,
74+
cronParts);
75+
return this;
76+
}
77+
78+
public String convert() {
79+
String targetCron = StringUtils.join(cronParts, CRON_FIELDS_SEPARATOR);
80+
LOGGER.info("Converted CRON -- {} :[{}] => {} :[{}]", sourceZoneId,
81+
sourceCron, targetZoneId, targetCron);
82+
return targetCron;
83+
}
84+
85+
private Calendar getCalendar(ZoneId id) {
86+
return Calendar.getInstance(TimeZone.getTimeZone(id));
87+
}
88+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2019 fahmpeermoh
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.cronutils.converter;
15+
16+
public class CronToCalendarTransformer extends BaseCronTransformer {
17+
18+
@Override
19+
protected void transform() {
20+
LOGGER.debug(
21+
"Setting field '{}' from cron found at position '{}' to calendar field '{}'",
22+
cronFieldValue, cronFieldPosition, calendarField);
23+
calendarInstance.set(calendarField, cronFieldValue);
24+
}
25+
}

src/main/java/com/cronutils/mapper/CronMapper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ public Cron map(final Cron cron) {
7777
final List<CronField> fields = new ArrayList<>();
7878
for (final CronFieldName name : CronFieldName.values()) {
7979
if (mappings.containsKey(name)) {
80-
fields.add(mappings.get(name).apply(cron.retrieve(name)));
80+
final CronField field = mappings.get(name).apply(cron.retrieve(name));
81+
if (field != null) {
82+
fields.add(field);
83+
}
8184
}
8285
}
8386
return cronRules.apply(new SingleCron(to, fields)).validate();

src/main/java/com/cronutils/model/field/expression/visitor/ValidationFieldExpressionVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ protected void isPeriodInRange(final FieldValue<?> fieldValue) {
167167
final int value = ((IntegerFieldValue) fieldValue).getValue();
168168
if (!constraints.isPeriodInRange(value)) {
169169
throw new IllegalArgumentException(
170-
String.format("Period %s not in range (%s, %s]", value, constraints.getStartRange(), constraints.getEndRange()));
170+
String.format("Period %s not in range [%s, %s)", value, constraints.getStartRange(), constraints.getEndRange()));
171171
}
172172
}
173173
}

src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313

1414
package com.cronutils.model.time.generator;
1515

16-
import java.util.ArrayList;
17-
import java.util.List;
18-
1916
import com.cronutils.model.field.CronField;
2017
import com.cronutils.model.field.expression.Between;
2118
import com.cronutils.model.field.expression.Every;
2219
import com.cronutils.model.field.expression.FieldExpression;
2320
import com.cronutils.model.field.expression.On;
2421
import com.cronutils.utils.VisibleForTesting;
2522

23+
import java.util.ArrayList;
24+
import java.util.List;
25+
2626
class EveryFieldValueGenerator extends FieldValueGenerator {
2727

2828
protected final int from;
@@ -52,11 +52,7 @@ public int generateNextValue(final int reference) throws NoSuchValueException {
5252
}
5353
final Every every = (Every) cronField.getExpression();
5454

55-
final int referenceWithoutOffset = reference - offset();
56-
final int period = every.getPeriod().getValue();
57-
final int remainder = referenceWithoutOffset % period;
58-
59-
final int next = reference + (period - remainder);
55+
final int next = getNext(reference, every);
6056
if (next < from) {
6157
return from;
6258
}
@@ -67,6 +63,19 @@ public int generateNextValue(final int reference) throws NoSuchValueException {
6763
return next;
6864
}
6965

66+
private int getNext(int reference, Every every) {
67+
final int offset = offset();
68+
if (reference >= offset) {
69+
final int referenceWithoutOffset = reference - offset;
70+
final int period = every.getPeriod().getValue();
71+
final int remainder = referenceWithoutOffset % period;
72+
73+
return reference + (period - remainder);
74+
} else {
75+
return offset;
76+
}
77+
}
78+
7079
@Override
7180
public int generatePreviousValue(final int reference) throws NoSuchValueException {
7281
final Every every = (Every) cronField.getExpression();
@@ -104,7 +113,7 @@ protected List<Integer> generateCandidatesNotIncludingIntervalExtremes(final int
104113
public boolean isMatch(final int value) {
105114
final Every every = (Every) cronField.getExpression();
106115
final int start = offset();
107-
return ((value - start) % every.getPeriod().getValue()) == 0 && value >= from && value <= to;
116+
return value >= start && ((value - start) % every.getPeriod().getValue()) == 0 && value >= from && value <= to;
108117
}
109118

110119
@Override

0 commit comments

Comments
 (0)