Repository: jmrozanec/cron-utils
Pull request #169 (2017-05-10 12:33:16)

fixed issue #148
added unit tests


Patch:
diff --git a/.gitignore b/.gitignore
index 59d1766..d9feab3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,14 +1,12 @@
-target/
-.settings/
-.classpath
-.project
-*.idea
-*.iml
-nbbuild
-nb-build.xml
-nbproject
-*.sh
-zrefactor
-.gradle/
-build/
-local.properties
\ No newline at end of file
+target/
+.settings/
+.classpath
+.project
+*.idea
+*.iml
+nbbuild
+nb-build.xml
+nbproject
+*.sh
+zrefactor
+bin/
diff --git a/.travis.yml b/.travis.yml
index 14c5318..d5331e3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,7 @@ jdk:
 
 before_install: "git clone -b travis `git config --get remote.origin.url` target/travis"
 
-script: "mvn deploy --settings target/travis/settings.xml -Dsettings.security=target/travis/settings-security.xml -Dmaven.javadoc.skip=true"
+script: "mvn deploy --settings target/travis/settings.xml -Dsettings.security=target/travis/settings-security.xml"
 
 after_success:
   - mvn cobertura:cobertura coveralls:cobertura
diff --git a/README.md b/README.md
index 76a3b88..0c40b65 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ cron-utils is available on [Maven central](http://search.maven.org/#search%7Cga%
     <dependency>
         <groupId>com.cronutils</groupId>
         <artifactId>cron-utils</artifactId>
-        <version>5.0.5</version>
+        <version>5.0.4</version>
     </dependency>
 
 
@@ -26,7 +26,7 @@ cron-utils is available on [Maven central](http://search.maven.org/#search%7Cga%
  * You can flag last field as optional!
  * Supports all cron special characters: * / , -
     * Non-standard characters L, W, LW, '?' and # are supported as well!
- * Print to locale specific human readable format (English, German, Korean, Spanish and Turkish are fully supported. Dutch, French, Italian, Portuguese and Russian have basic support).
+ * Print to locale specific human readable format (English, German, Korean and Spanish are fully supported. Dutch, French, Italian, Portuguese and Russian have basic support).
  * Parse and Description process are decoupled: parse once and operate with the result!
  * Build cron expressions using CronBuilder: 
     * no need to remember fields and constraints for each cron provider
@@ -166,23 +166,6 @@ String formattedDateTime = formatter.print(lastExecution);
 // formattedDateTime will be lastExecution in "dayOfWeek, Month day, Year" format
 ```
 
-***cron-utils CLI***
-
-We provide a simple CLI interface to use cron-utils right from console, without writing a new project!
-
-- Usage: `java -jar cron-utils.jar com.cronutils.cli.CronUtilsCLI --validate -f [CRON4J|QUARTZ|UNIX] -e '<cron expression>'`
-
-- Example: `java -jar cron-utils.jar com.cronutils.cli.CronUtilsCLI --validate -f UNIX -e '* 1 * * *'`
-
-If you want a standalone jar without requiring the 'cp', build an uber jar with :
-```bash
-mvn assembly:assembly -DdescriptorId=jar-with-dependencies
-```
-Then, launch cli-utils (built in the `target` directory) with :
-```bash
-java -jar cron-utils-<version>-jar-with-dependencies.jar com.cronutils.cli.CronUtilsCLI --validate -f [CRON4J|QUARTZ|UNIX] -e '<cron expression>'`
-```
-
 **Contribute & Support!**
 
 Contributions are welcome! You can contribute by
@@ -193,8 +176,7 @@ Contributions are welcome! You can contribute by
  * enhancing documentation
  * providing translations to support new locales
  * bringing suggestions and reporting bugs
- * spreading the word 
- * telling us how you use it! We look forward to [list you at our wiki](https://github.com/jmrozanec/cron-utils/wiki/Projects-using-cron-utils)!
+ * spreading the word / telling us how you use it!
 
 
 Check [our page](http://cronutils.com)! For stats about the project, you can visit our [OpenHUB profile](https://www.openhub.net/p/cron-utils).
diff --git a/pom.xml b/pom.xml
index ac6e84b..2feebaa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
 
     <groupId>com.cronutils</groupId>
     <artifactId>cron-utils</artifactId>
-    <version>5.0.6-SNAPSHOT</version>
+    <version>5.0.5</version>
 
     <name>cron-utils</name>
     <description>A Java library to parse, migrate and validate crons as well as describe them in human readable
@@ -65,7 +65,6 @@
         <mockito.version>1.10.19</mockito.version>
         <powermock.version>1.6.2</powermock.version>
         <guava.version>18.0</guava.version>
-        <commonscli.version>1.4</commonscli.version>
 
         <github.global.server>github</github.global.server>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -77,37 +76,11 @@
             <artifactId>slf4j-api</artifactId>
             <version>${slf4j.version}</version>
         </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-            <version>${slf4j.version}</version>
-        </dependency>
+
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <version>${guava.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-cli</groupId>
-            <artifactId>commons-cli</artifactId>
-            <version>${commonscli.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.jakewharton.threetenabp</groupId>
-            <artifactId>threetenabp</artifactId>
-            <version>1.0.5</version>
-	    <type>aar</type>
-        </dependency>
-        <dependency>
-            <groupId>org.threeten</groupId>
-            <artifactId>threetenbp</artifactId>
-            <version>1.3.2</version>
-	    <scope>compile</scope>
-        </dependency>
-        <dependency>
-            <groupId>eu.lp0.slf4j</groupId>
-            <artifactId>slf4j-android</artifactId>
-            <version>1.7.22-0</version>
             <scope>test</scope>
         </dependency>
         <dependency>
@@ -146,12 +119,6 @@
             <version>${powermock.version}</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.quartz-scheduler</groupId>
-            <artifactId>quartz</artifactId>
-            <version>2.2.3</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
 
     <build>
@@ -166,18 +133,6 @@
                 </configuration>
             </plugin>
             <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-assembly-plugin</artifactId>
-                <version>2.2-beta-5</version>
-                <configuration>
-                     <archive>
-                          <manifest>
-                               <mainClass>com.cronutils.cli.CronUtilsCLI</mainClass>
-                          </manifest>
-                     </archive>
-                </configuration>
-            </plugin>
-	    <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-source-plugin</artifactId>
                 <version>2.2.1</version>
@@ -204,14 +159,6 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
                 <version>2.4</version>
-                <configuration>
-                    <archive>
-                        <manifest>
-                            <addClasspath>true</addClasspath>
-                            <mainClass>com.cronutils.cli.CronUtilsCLI</mainClass>
-                        </manifest>
-                    </archive>
-                </configuration>
             </plugin>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -282,19 +229,6 @@
                     <format>xml</format>
                 </configuration>
             </plugin>
-	    <plugin>
-    		<groupId>net.orfjackal.retrolambda</groupId>
-    		<artifactId>retrolambda-maven-plugin</artifactId>
-    		<version>2.5.1</version>
-    		<executions>
-        		<execution>
-            			<goals>
-                			<goal>process-main</goal>
-                			<goal>process-test</goal>
-            			</goals>
-        		</execution>
-    		</executions>
-	    </plugin>
         </plugins>
 
         <extensions>
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
deleted file mode 100644
index cc915c1..0000000
--- a/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.cronutils">
-
-    <uses-permission android:name="android.permission.INTERNET" />
-
-    <application
-        android:label="cronutils">
-    </application>
-
-</manifest>
\ No newline at end of file
diff --git a/src/main/java/com/cronutils/Function.java b/src/main/java/com/cronutils/Function.java
deleted file mode 100644
index 7be27dd..0000000
--- a/src/main/java/com/cronutils/Function.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.cronutils;
-
-/**
- * Created by kiran on 19/3/17.
- */
-
-public interface Function<T, R> {
-    R apply(T t);
-}
diff --git a/src/main/java/com/cronutils/cli/CronUtilsCLI.java b/src/main/java/com/cronutils/cli/CronUtilsCLI.java
deleted file mode 100644
index 3edd957..0000000
--- a/src/main/java/com/cronutils/cli/CronUtilsCLI.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.cronutils.cli;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-
-import com.cronutils.model.Cron;
-import com.cronutils.model.CronType;
-import com.cronutils.model.definition.CronDefinition;
-import com.cronutils.model.definition.CronDefinitionBuilder;
-import com.cronutils.parser.CronParser;
-
-/*
- * Copyright 2017 bflorat, jmrozanec
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-public class CronUtilsCLI {
-	private static final String HELP = "help";
-
-	private CronUtilsCLI() {
-		super();
-	}
-
-	public static void main(String[] args) throws Exception {
-		cronValidation(args);
-	}
-
-	private static void cronValidation(String[] args) throws ParseException {
-		Options options = new Options();
-		options.addOption("v", "validate", false, "Action of validation (default)");
-		options.addOption("f", "format", true,
-				"Cron expression format to validate. Possible values are: CRON4J, QUARTZ, UNIX");
-		options.addOption("e", "expression", true, "Cron expression to validate. Example: '* 1 * * *'");
-		options.addOption("h", HELP, false, "Help");
-
-		String header = "Cron expressions validation by cron-utils\n\n";
-		String footer = "\nPlease report issues at https://github.com/jmrozanec/cron-utils/issues";
-
-		CommandLineParser parser = new DefaultParser();
-		CommandLine cmd = parser.parse(options, args);
-		if (cmd.hasOption(HELP) || cmd.getOptions().length == 0) {
-			showHelp(options, header, footer);
-			return;
-		}
-		if (!cmd.hasOption("validate")) {
-			showHelp(options, header, footer);
-			return;
-		}
-		if (cmd.hasOption('v')) {
-			String format = cmd.getOptionValue("f");
-			String expression = cmd.getOptionValue("e");
-
-			CronType cronType = CronType.valueOf(format);
-			CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(cronType);
-			CronParser cronParser = new CronParser(cronDefinition);
-			Cron quartzCron = cronParser.parse(expression);
-			quartzCron.validate();
-		}
-	}
-
-	private static void showHelp(Options options, String header, String footer) {
-		HelpFormatter formatter = new HelpFormatter();
-		formatter.printHelp("cron-validator", header, options, footer, true);
-	}
-}
diff --git a/src/main/java/com/cronutils/descriptor/CronDescriptor.java b/src/main/java/com/cronutils/descriptor/CronDescriptor.java
index cb2f7fd..6dacca0 100644
--- a/src/main/java/com/cronutils/descriptor/CronDescriptor.java
+++ b/src/main/java/com/cronutils/descriptor/CronDescriptor.java
@@ -3,7 +3,6 @@ package com.cronutils.descriptor;
 import com.cronutils.model.Cron;
 import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
-import com.cronutils.model.field.definition.FieldDefinition;
 import com.cronutils.utils.Preconditions;
 
 import java.util.Locale;
@@ -56,14 +55,12 @@ public class CronDescriptor {
     public String describe(Cron cron) {
         Preconditions.checkNotNull(cron, "Cron must not be null");
         Map<CronFieldName, CronField> expressions = cron.retrieveFieldsAsMap();
-        Map<CronFieldName, FieldDefinition> fieldDefinitions = cron.getCronDefinition().retrieveFieldDefinitionsAsMap();
-        
         return
                 new StringBuilder()
                         .append(describeHHmmss(expressions)).append(" ")
                         .append(describeDayOfMonth(expressions)).append(" ")
                         .append(describeMonth(expressions)).append(" ")
-                        .append(describeDayOfWeek(expressions, fieldDefinitions)).append(" ")
+                        .append(describeDayOfWeek(expressions)).append(" ")
                         .append(describeYear(expressions))
                         .toString().replaceAll("\\s+", " ").trim();
     }
@@ -120,12 +117,10 @@ public class CronDescriptor {
      * @param fields - fields to describe;
      * @return description - String
      */
-    private String describeDayOfWeek(Map<CronFieldName, CronField> fields, Map<CronFieldName, FieldDefinition> definitions) {
-    	
+    private String describeDayOfWeek(Map<CronFieldName, CronField> fields) {
         String description = DescriptionStrategyFactory.daysOfWeekInstance(
 		        bundle,
-		        fields.containsKey(CronFieldName.DAY_OF_WEEK) ? fields.get(CronFieldName.DAY_OF_WEEK).getExpression() : null,
-		        definitions.containsKey(CronFieldName.DAY_OF_WEEK) ? definitions.get(CronFieldName.DAY_OF_WEEK) : null 
+		        fields.containsKey(CronFieldName.DAY_OF_WEEK) ? fields.get(CronFieldName.DAY_OF_WEEK).getExpression() : null
 		).describe();
 		return this.addExpressions(description, bundle.getString("day"), bundle.getString("days"));
     }
diff --git a/src/main/java/com/cronutils/descriptor/DescriptionStrategy.java b/src/main/java/com/cronutils/descriptor/DescriptionStrategy.java
index e114ebc..defab66 100644
--- a/src/main/java/com/cronutils/descriptor/DescriptionStrategy.java
+++ b/src/main/java/com/cronutils/descriptor/DescriptionStrategy.java
@@ -9,7 +9,7 @@ import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.ResourceBundle;
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /*
  * Copyright 2014 jmrozanec
diff --git a/src/main/java/com/cronutils/descriptor/DescriptionStrategyFactory.java b/src/main/java/com/cronutils/descriptor/DescriptionStrategyFactory.java
index c1af197..ef87b7b 100644
--- a/src/main/java/com/cronutils/descriptor/DescriptionStrategyFactory.java
+++ b/src/main/java/com/cronutils/descriptor/DescriptionStrategyFactory.java
@@ -1,16 +1,13 @@
 package com.cronutils.descriptor;
 
-import com.cronutils.mapper.WeekDay;
-import com.cronutils.model.field.definition.DayOfWeekFieldDefinition;
-import com.cronutils.model.field.definition.FieldDefinition;
 import com.cronutils.model.field.expression.FieldExpression;
 import com.cronutils.model.field.expression.On;
 
-import org.threeten.bp.DayOfWeek;
-import org.threeten.bp.Month;
-import org.threeten.bp.format.TextStyle;
+import java.time.DayOfWeek;
+import java.time.Month;
+import java.time.format.TextStyle;
 import java.util.ResourceBundle;
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /*
 * Copyright 2014 jmrozanec
@@ -34,13 +31,9 @@ class DescriptionStrategyFactory {
      * @param expression - CronFieldExpression
      * @return - DescriptionStrategy instance, never null
      */
-    public static DescriptionStrategy daysOfWeekInstance(final ResourceBundle bundle, final FieldExpression expression, final FieldDefinition definition) {
-        
-    	final Function<Integer, String> nominal = integer -> {
-    		int diff = definition instanceof DayOfWeekFieldDefinition ? DayOfWeek.MONDAY.getValue() - ((DayOfWeekFieldDefinition) definition).getMondayDoWValue().getMondayDoWValue() : 0;
-        	return DayOfWeek.of(integer + diff < 1 ? 7 : integer + diff).getDisplayName(TextStyle.FULL, bundle.getLocale());
-        };
-        
+    public static DescriptionStrategy daysOfWeekInstance(final ResourceBundle bundle, final FieldExpression expression) {
+        final Function<Integer, String> nominal = integer -> DayOfWeek.of(integer).getDisplayName(TextStyle.FULL, bundle.getLocale());
+
         NominalDescriptionStrategy dow = new NominalDescriptionStrategy(bundle, nominal, expression);
 
         dow.addDescription(fieldExpression -> {
diff --git a/src/main/java/com/cronutils/descriptor/NominalDescriptionStrategy.java b/src/main/java/com/cronutils/descriptor/NominalDescriptionStrategy.java
index b129d62..dfc00f4 100644
--- a/src/main/java/com/cronutils/descriptor/NominalDescriptionStrategy.java
+++ b/src/main/java/com/cronutils/descriptor/NominalDescriptionStrategy.java
@@ -6,7 +6,7 @@ import com.cronutils.model.field.expression.FieldExpression;
 import java.util.HashSet;
 import java.util.ResourceBundle;
 import java.util.Set;
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /*
  * Copyright 2014 jmrozanec
diff --git a/src/main/java/com/cronutils/descriptor/TimeDescriptionStrategy.java b/src/main/java/com/cronutils/descriptor/TimeDescriptionStrategy.java
index 995d7d3..c70d170 100644
--- a/src/main/java/com/cronutils/descriptor/TimeDescriptionStrategy.java
+++ b/src/main/java/com/cronutils/descriptor/TimeDescriptionStrategy.java
@@ -7,7 +7,7 @@ import com.cronutils.utils.Preconditions;
 import java.util.HashSet;
 import java.util.ResourceBundle;
 import java.util.Set;
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /*
  * Copyright 2014 jmrozanec
diff --git a/src/main/java/com/cronutils/mapper/CronMapper.java b/src/main/java/com/cronutils/mapper/CronMapper.java
index 3aa34ff..648d11f 100644
--- a/src/main/java/com/cronutils/mapper/CronMapper.java
+++ b/src/main/java/com/cronutils/mapper/CronMapper.java
@@ -24,7 +24,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /*
  * Copyright 2014 jmrozanec
diff --git a/src/main/java/com/cronutils/mapper/WeekDay.java b/src/main/java/com/cronutils/mapper/WeekDay.java
index cc12728..d799b28 100644
--- a/src/main/java/com/cronutils/mapper/WeekDay.java
+++ b/src/main/java/com/cronutils/mapper/WeekDay.java
@@ -3,8 +3,7 @@ package com.cronutils.mapper;
 import com.cronutils.utils.Preconditions;
 import com.cronutils.utils.VisibleForTesting;
 
-import java.io.Serializable;
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /*
  * Copyright 2015 jmrozanec
@@ -19,7 +18,7 @@ import com.cronutils.Function;
  * limitations under the License.
  */
 @VisibleForTesting
-public class WeekDay implements Serializable {
+public class WeekDay {
     private int mondayDoWValue;
     private boolean firstDayZero;
 
diff --git a/src/main/java/com/cronutils/model/Cron.java b/src/main/java/com/cronutils/model/Cron.java
index 196f94d..4d50a60 100644
--- a/src/main/java/com/cronutils/model/Cron.java
+++ b/src/main/java/com/cronutils/model/Cron.java
@@ -21,13 +21,12 @@ import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.expression.visitor.ValidationFieldExpressionVisitor;
 import com.cronutils.utils.Preconditions;
 
-import java.io.Serializable;
 import java.util.*;
 
 /**
  * Represents a cron expression
  */
-public class Cron implements Serializable {
+public class Cron {
     private CronDefinition cronDefinition;
     private Map<CronFieldName, CronField> fields;
     private String asString;
@@ -76,12 +75,6 @@ public class Cron implements Serializable {
         return cronDefinition;
     }
 
-    /**
-     * Validates this Cron instance by validating its cron expression.
-     * 
-     * @return this Cron instance
-     * @throws IllegalArgumentException if the cron expression is invalid
-     */
     public Cron validate(){
         for(Map.Entry<CronFieldName, CronField> field : retrieveFieldsAsMap().entrySet()){
             CronFieldName fieldName = field.getKey();
diff --git a/src/main/java/com/cronutils/model/definition/CronConstraint.java b/src/main/java/com/cronutils/model/definition/CronConstraint.java
index 889ea5a..b776f46 100644
--- a/src/main/java/com/cronutils/model/definition/CronConstraint.java
+++ b/src/main/java/com/cronutils/model/definition/CronConstraint.java
@@ -14,9 +14,7 @@ package com.cronutils.model.definition;
 
 import com.cronutils.model.Cron;
 
-import java.io.Serializable;
-
-public abstract class CronConstraint implements Serializable {
+public abstract class CronConstraint {
     private String description;
 
     public CronConstraint(String description){
diff --git a/src/main/java/com/cronutils/model/definition/CronDefinition.java b/src/main/java/com/cronutils/model/definition/CronDefinition.java
index 1ec36d5..9efc725 100644
--- a/src/main/java/com/cronutils/model/definition/CronDefinition.java
+++ b/src/main/java/com/cronutils/model/definition/CronDefinition.java
@@ -1,17 +1,11 @@
 package com.cronutils.model.definition;
 
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.definition.FieldDefinition;
 import com.cronutils.utils.Preconditions;
 
+import java.util.*;
+
 /*
  * Copyright 2014 jmrozanec
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,7 +22,7 @@ import com.cronutils.utils.Preconditions;
 /**
  * Defines fields and conditions over each field for a cron
  */
-public class CronDefinition implements Serializable {
+public class CronDefinition {
     private Map<CronFieldName, FieldDefinition> fieldDefinitions;
     private Set<CronConstraint> cronConstraints;
     private boolean lastFieldOptional;
@@ -81,14 +75,6 @@ public class CronDefinition implements Serializable {
         return new HashSet<FieldDefinition>(fieldDefinitions.values());
     }
 
-    /**
-     * Retrieve all cron field definitions values as map
-     * @return unmodifiable Map with key CronFieldName and values FieldDefinition, never null
-     */
-    public Map<CronFieldName, FieldDefinition> retrieveFieldDefinitionsAsMap(){
-        return Collections.unmodifiableMap(this.fieldDefinitions);
-    }
-    
     /**
      * Returns field definition for field name of this cron
      * @param cronFieldName cron field name
diff --git a/src/main/java/com/cronutils/model/field/CronField.java b/src/main/java/com/cronutils/model/field/CronField.java
index e424657..baf58f3 100644
--- a/src/main/java/com/cronutils/model/field/CronField.java
+++ b/src/main/java/com/cronutils/model/field/CronField.java
@@ -4,7 +4,6 @@ import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.model.field.expression.FieldExpression;
 import com.cronutils.utils.Preconditions;
 
-import java.io.Serializable;
 import java.util.Comparator;
 
 /*
@@ -19,7 +18,7 @@ import java.util.Comparator;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-public class CronField implements Serializable {
+public class CronField {
     private CronFieldName field;
     private FieldExpression expression;
     private FieldConstraints constraints;
diff --git a/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java b/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java
index 368a8e1..138e2c5 100644
--- a/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java
+++ b/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java
@@ -1,88 +1,98 @@
-package com.cronutils.model.field.constraint;
-
-import com.cronutils.model.field.value.SpecialChar;
-import com.cronutils.utils.Preconditions;
-
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-/*
- * Copyright 2014 jmrozanec
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Holds information on valid values for a field and allows to perform mappings and validations. Example of information for valid field
- * values: int range, valid special characters, valid nominal values. Example for mappings: conversions from nominal values to integers and
- * integer-integer mappings if more than one integer represents the same concept.
- */
-public class FieldConstraints implements Serializable {
-
-	private final Map<String, Integer> stringMapping;
-	private final Map<Integer, Integer> intMapping;
-	private final Set<SpecialChar> specialChars;
-	private final Integer startRange;
-	private final Integer endRange;
-
-	/**
-	 * @param specialChars
-	 *            - allowed special chars
-	 * @param startRange
-	 *            - lowest possible value
-	 * @param endRange
-	 *            - highest possible value
-	 */
-	public FieldConstraints(Map<String, Integer> stringMapping, Map<Integer, Integer> intMapping, Set<SpecialChar> specialChars, int startRange,
-			int endRange) {
-		this.stringMapping = Collections.unmodifiableMap(Preconditions.checkNotNull(stringMapping, "String mapping must not be null"));
-		this.intMapping = Collections.unmodifiableMap(Preconditions.checkNotNull(intMapping, "Integer mapping must not be null"));
-		this.specialChars = Collections.unmodifiableSet(Preconditions.checkNotNull(specialChars, "Special (non-standard) chars set must not be null"));
-		this.startRange = startRange;
-		this.endRange = endRange;
-	}
-
-	public int getStartRange() {
-		return startRange;
-	}
-
-	public int getEndRange() {
-		return endRange;
-	}
-
-	public Set<SpecialChar> getSpecialChars() {
-		return specialChars;
-	}
-
-	/**
-	 * Check if given number is greater or equal to start range and minor or equal to end range
-	 * 
-	 * @param value
-	 *            - to be checked
-	 */
-	public boolean isInRange(int value) {
-		return value >= getStartRange() && value <= getEndRange();
-	}
-
-	public Set<String> getStringMappingKeySet() {
-		return stringMapping.keySet();
-	}
-
-	public Integer getStringMappingValue(String exp) {
-		return stringMapping.get(exp);
-	}
-
-	public Integer getIntMappingValue(Integer exp) {
-		return intMapping.get(exp);
-	}
-
-}
+package com.cronutils.model.field.constraint;
+
+import com.cronutils.model.field.value.SpecialChar;
+import com.cronutils.utils.Preconditions;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/*
+ * Copyright 2014 jmrozanec
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Holds information on valid values for a field and allows to perform mappings and validations. Example of information for valid field
+ * values: int range, valid special characters, valid nominal values. Example for mappings: conversions from nominal values to integers and
+ * integer-integer mappings if more than one integer represents the same concept.
+ */
+public class FieldConstraints {
+
+	private final Map<String, Integer> stringMapping;
+	private final Map<Integer, Integer> intMapping;
+	private final Set<SpecialChar> specialChars;
+	private final Integer startRange;
+	private final Integer endRange;
+
+	/**
+	 * @param specialChars
+	 *            - allowed special chars
+	 * @param startRange
+	 *            - lowest possible value
+	 * @param endRange
+	 *            - highest possible value
+	 */
+	public FieldConstraints(Map<String, Integer> stringMapping, Map<Integer, Integer> intMapping, Set<SpecialChar> specialChars, int startRange,
+			int endRange) {
+		this.stringMapping = Collections.unmodifiableMap(Preconditions.checkNotNull(stringMapping, "String mapping must not be null"));
+		this.intMapping = Collections.unmodifiableMap(Preconditions.checkNotNull(intMapping, "Integer mapping must not be null"));
+		this.specialChars = Collections.unmodifiableSet(Preconditions.checkNotNull(specialChars, "Special (non-standard) chars set must not be null"));
+		this.startRange = startRange;
+		this.endRange = endRange;
+	}
+
+	public int getStartRange() {
+		return startRange;
+	}
+
+	public int getEndRange() {
+		return endRange;
+	}
+
+	public Set<SpecialChar> getSpecialChars() {
+		return specialChars;
+	}
+
+	/**
+	 * Check if given number is greater or equal to start range and minor or equal to end range
+	 * 
+	 * @param value
+	 *            - to be checked
+	 */
+	public boolean isInRange(int value) {
+		return value >= getStartRange() && value <= getEndRange();
+	}
+	
+
+    /**
+     * Check if given period is compatible with the given range
+     * 
+     * @param period - to be checked
+     * @return {@code true} if period is compatible, {@code false} otherwise.
+     */
+    public boolean isPeriodInRange(int period) {
+        return period > 0 && period <= getEndRange() - getStartRange();
+    }
+
+	public Set<String> getStringMappingKeySet() {
+		return stringMapping.keySet();
+	}
+
+	public Integer getStringMappingValue(String exp) {
+		return stringMapping.get(exp);
+	}
+
+	public Integer getIntMappingValue(Integer exp) {
+		return intMapping.get(exp);
+	}
+
+}
diff --git a/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java b/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java
index 7cce141..777e97e 100644
--- a/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java
+++ b/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java
@@ -17,13 +17,12 @@ import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.utils.Preconditions;
 
-import java.io.Serializable;
 import java.util.Comparator;
 
 /**
  * Represents a definition of allowed values for a cron field.
  */
-public class FieldDefinition implements Serializable {
+public class FieldDefinition {
     private CronFieldName fieldName;
     private FieldConstraints constraints;
 
diff --git a/src/main/java/com/cronutils/model/field/expression/FieldExpression.java b/src/main/java/com/cronutils/model/field/expression/FieldExpression.java
index bde9f5b..9407206 100644
--- a/src/main/java/com/cronutils/model/field/expression/FieldExpression.java
+++ b/src/main/java/com/cronutils/model/field/expression/FieldExpression.java
@@ -1,7 +1,5 @@
 package com.cronutils.model.field.expression;
 
-import java.io.Serializable;
-
 import com.cronutils.model.field.expression.visitor.FieldExpressionVisitor;
 import com.cronutils.utils.Preconditions;
 
@@ -18,9 +16,9 @@ import com.cronutils.utils.Preconditions;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-public abstract class FieldExpression implements Serializable {
+public abstract class FieldExpression {
 
-    public And and(FieldExpression exp) {
+	public And and(FieldExpression exp) {
 		return new And().and(this).and(exp);
 	}
 
diff --git a/src/main/java/com/cronutils/model/field/expression/visitor/ValidationFieldExpressionVisitor.java b/src/main/java/com/cronutils/model/field/expression/visitor/ValidationFieldExpressionVisitor.java
index 2ca58e8..022ccd1 100644
--- a/src/main/java/com/cronutils/model/field/expression/visitor/ValidationFieldExpressionVisitor.java
+++ b/src/main/java/com/cronutils/model/field/expression/visitor/ValidationFieldExpressionVisitor.java
@@ -1,165 +1,183 @@
-/*
- * Copyright 2014 jmrozanec
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.cronutils.model.field.expression.visitor;
-
-import com.cronutils.StringValidations;
-import com.cronutils.model.field.constraint.FieldConstraints;
-import com.cronutils.model.field.expression.*;
-import com.cronutils.model.field.value.FieldValue;
-import com.cronutils.model.field.value.IntegerFieldValue;
-import com.cronutils.model.field.value.SpecialChar;
-import com.cronutils.model.field.value.SpecialCharFieldValue;
-import com.cronutils.utils.VisibleForTesting;
-
-public class ValidationFieldExpressionVisitor implements FieldExpressionVisitor {
-
-	private static final String OORANGE = "Value %s not in range [%s, %s]";
-	private static final String EMPTY_STRING = "";
-
-	private FieldConstraints constraints;
-	private StringValidations stringValidations;
-	private boolean strictRanges;
-
-	public ValidationFieldExpressionVisitor(FieldConstraints constraints, boolean strictRanges) {
-		this.constraints = constraints;
-		this.stringValidations = new StringValidations(constraints);
-		this.strictRanges = strictRanges;
-	}
-
-	protected ValidationFieldExpressionVisitor(FieldConstraints constraints, StringValidations stringValidation, boolean strictRanges) {
-        this.constraints = constraints;
-        this.stringValidations = stringValidation;
-        this.strictRanges = strictRanges;
-    }
-
-	
-	@Override
-	public FieldExpression visit(FieldExpression expression) {
-		String unsupportedChars = stringValidations.removeValidChars(expression.asString());
-		if (EMPTY_STRING.equals(unsupportedChars)) {
-			if (expression instanceof Always) {
-				return visit((Always) expression);
-			}
-			if (expression instanceof And) {
-				return visit((And) expression);
-			}
-			if (expression instanceof Between) {
-				return visit((Between) expression);
-			}
-			if (expression instanceof Every) {
-				return visit((Every) expression);
-			}
-			if (expression instanceof On) {
-				return visit((On) expression);
-			}
-			if (expression instanceof QuestionMark) {
-				return visit((QuestionMark) expression);
-			}
-		}
-		throw new IllegalArgumentException(
-				String.format("Invalid chars in expression! Expression: %s Invalid chars: %s",
-						expression.asString(), unsupportedChars)
-		);
-	}
-
-	@Override
-	public Always visit(Always always) {
-		return always;
-	}
-
-    @Override
-    public And visit(And and) {
-        for(FieldExpression expression: and.getExpressions()) {
-            visit(expression);
-        }
-        return and;
-    }
-
-	@Override
-	public Between visit(Between between) {
-		preConditions(between);
-
-		if (strictRanges && between.getFrom() instanceof IntegerFieldValue && between.getTo() instanceof IntegerFieldValue) {
-			int from = ((IntegerFieldValue) between.getFrom()).getValue();
-			int to = ((IntegerFieldValue) between.getTo()).getValue();
-			if (from > to) {
-				throw new IllegalArgumentException(String.format("Invalid range! [%s,%s]", from, to));
-			}
-		}
-
-		return between;
-	}
-
-	private void preConditions(Between between) {
-		isInRange(between.getFrom());
-		isInRange(between.getTo());
-		if (isSpecialCharNotL(between.getFrom()) || isSpecialCharNotL(between.getTo())) {
-			throw new IllegalArgumentException("No special characters allowed in range, except for 'L'");
-		}
-	}
-
-	@Override
-	public Every visit(Every every) {
-		if (every.getExpression() instanceof Between) {
-			visit((Between) every.getExpression());
-		}
-		if (every.getExpression() instanceof On) {
-			visit((On) every.getExpression());
-		}
-		isInRange(every.getPeriod());
-		return every;
-	}
-
-	@Override
-	public On visit(On on) {
-		if (!isDefault(on.getTime())) {
-			isInRange(on.getTime());
-		}
-		if (!isDefault(on.getNth())) {
-			isInRange(on.getNth());
-		}
-		return on;
-	}
-
-	@Override
-	public QuestionMark visit(QuestionMark questionMark) {
-		return questionMark;
-	}
-
-	/**
-	 * Check if given number is greater or equal to start range and minor or equal to end range
-	 * 
-	 * @param fieldValue
-	 *            - to be validated
-	 * @throws IllegalArgumentException
-	 *             - if not in range
-	 */
-	@VisibleForTesting
-	protected void isInRange(FieldValue<?> fieldValue) {
-		if (fieldValue instanceof IntegerFieldValue) {
-			int value = ((IntegerFieldValue) fieldValue).getValue();
-			if (!constraints.isInRange(value)) {
-				throw new IllegalArgumentException(String.format(OORANGE, value, constraints.getStartRange(), constraints.getEndRange()));
-			}
-		}
-	}
-
-	@VisibleForTesting
-	protected boolean isDefault(FieldValue<?> fieldValue) {
-		return fieldValue instanceof IntegerFieldValue && ((IntegerFieldValue) fieldValue).getValue() == -1;
-	}
-
-	protected boolean isSpecialCharNotL(FieldValue<?> fieldValue) {
-		return fieldValue instanceof SpecialCharFieldValue && !SpecialChar.L.equals(fieldValue.getValue());
-	}
-}
+/*
+ * Copyright 2014 jmrozanec
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cronutils.model.field.expression.visitor;
+
+import com.cronutils.StringValidations;
+import com.cronutils.model.field.constraint.FieldConstraints;
+import com.cronutils.model.field.expression.*;
+import com.cronutils.model.field.value.FieldValue;
+import com.cronutils.model.field.value.IntegerFieldValue;
+import com.cronutils.model.field.value.SpecialChar;
+import com.cronutils.model.field.value.SpecialCharFieldValue;
+import com.cronutils.utils.VisibleForTesting;
+
+public class ValidationFieldExpressionVisitor implements FieldExpressionVisitor {
+
+	private static final String OORANGE = "Value %s not in range [%s, %s]";
+	private static final String EMPTY_STRING = "";
+
+	private FieldConstraints constraints;
+	private StringValidations stringValidations;
+	private boolean strictRanges;
+
+	public ValidationFieldExpressionVisitor(FieldConstraints constraints, boolean strictRanges) {
+		this.constraints = constraints;
+		this.stringValidations = new StringValidations(constraints);
+		this.strictRanges = strictRanges;
+	}
+
+	protected ValidationFieldExpressionVisitor(FieldConstraints constraints, StringValidations stringValidation, boolean strictRanges) {
+        this.constraints = constraints;
+        this.stringValidations = stringValidation;
+        this.strictRanges = strictRanges;
+    }
+
+	
+	@Override
+	public FieldExpression visit(FieldExpression expression) {
+		String unsupportedChars = stringValidations.removeValidChars(expression.asString());
+		if (EMPTY_STRING.equals(unsupportedChars)) {
+			if (expression instanceof Always) {
+				return visit((Always) expression);
+			}
+			if (expression instanceof And) {
+				return visit((And) expression);
+			}
+			if (expression instanceof Between) {
+				return visit((Between) expression);
+			}
+			if (expression instanceof Every) {
+				return visit((Every) expression);
+			}
+			if (expression instanceof On) {
+				return visit((On) expression);
+			}
+			if (expression instanceof QuestionMark) {
+				return visit((QuestionMark) expression);
+			}
+		}
+		throw new IllegalArgumentException(
+				String.format("Invalid chars in expression! Expression: %s Invalid chars: %s",
+						expression.asString(), unsupportedChars)
+		);
+	}
+
+	@Override
+	public Always visit(Always always) {
+		return always;
+	}
+
+    @Override
+    public And visit(And and) {
+        for(FieldExpression expression: and.getExpressions()) {
+            visit(expression);
+        }
+        return and;
+    }
+
+	@Override
+	public Between visit(Between between) {
+		preConditions(between);
+
+		if (strictRanges && between.getFrom() instanceof IntegerFieldValue && between.getTo() instanceof IntegerFieldValue) {
+			int from = ((IntegerFieldValue) between.getFrom()).getValue();
+			int to = ((IntegerFieldValue) between.getTo()).getValue();
+			if (from > to) {
+				throw new IllegalArgumentException(String.format("Invalid range! [%s,%s]", from, to));
+			}
+		}
+
+		return between;
+	}
+
+	private void preConditions(Between between) {
+		isInRange(between.getFrom());
+		isInRange(between.getTo());
+		if (isSpecialCharNotL(between.getFrom()) || isSpecialCharNotL(between.getTo())) {
+			throw new IllegalArgumentException("No special characters allowed in range, except for 'L'");
+		}
+	}
+
+	@Override
+	public Every visit(Every every) {
+		if (every.getExpression() instanceof Between) {
+			visit((Between) every.getExpression());
+		}
+		if (every.getExpression() instanceof On) {
+			visit((On) every.getExpression());
+		}
+		isPeriodInRange(every.getPeriod());
+		return every;
+	}
+
+	@Override
+	public On visit(On on) {
+		if (!isDefault(on.getTime())) {
+			isInRange(on.getTime());
+		}
+		if (!isDefault(on.getNth())) {
+			isInRange(on.getNth());
+		}
+		return on;
+	}
+
+	@Override
+	public QuestionMark visit(QuestionMark questionMark) {
+		return questionMark;
+	}
+
+	/**
+	 * Check if given number is greater or equal to start range and minor or equal to end range
+	 * 
+	 * @param fieldValue
+	 *            - to be validated
+	 * @throws IllegalArgumentException
+	 *             - if not in range
+	 */
+	@VisibleForTesting
+	protected void isInRange(FieldValue<?> fieldValue) {
+		if (fieldValue instanceof IntegerFieldValue) {
+			int value = ((IntegerFieldValue) fieldValue).getValue();
+			if (!constraints.isInRange(value)) {
+				throw new IllegalArgumentException(String.format(OORANGE, value, constraints.getStartRange(), constraints.getEndRange()));
+			}
+		}
+	}
+	
+	/**
+     * Check if given period is compatible with range
+     * 
+     * @param fieldValue
+     *            - to be validated
+     * @throws IllegalArgumentException
+     *             - if not in range
+     */
+    @VisibleForTesting
+    protected void isPeriodInRange(FieldValue<?> fieldValue) {
+        if (fieldValue instanceof IntegerFieldValue) {
+            int value = ((IntegerFieldValue) fieldValue).getValue();
+            if (!constraints.isPeriodInRange(value)) {
+                throw new IllegalArgumentException(String.format("Period %s not in range (0, %s]", value, constraints.getEndRange()-constraints.getStartRange()));
+            }
+        }
+    }
+
+	@VisibleForTesting
+	protected boolean isDefault(FieldValue<?> fieldValue) {
+		return fieldValue instanceof IntegerFieldValue && ((IntegerFieldValue) fieldValue).getValue() == -1;
+	}
+
+	protected boolean isSpecialCharNotL(FieldValue<?> fieldValue) {
+		return fieldValue instanceof SpecialCharFieldValue && !SpecialChar.L.equals(fieldValue.getValue());
+	}
+}
diff --git a/src/main/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitor.java b/src/main/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitor.java
index dc76050..66bf302 100644
--- a/src/main/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitor.java
+++ b/src/main/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitor.java
@@ -16,7 +16,7 @@ import com.cronutils.model.field.expression.*;
 import com.cronutils.model.field.value.FieldValue;
 import com.cronutils.model.field.value.IntegerFieldValue;
 
-import com.cronutils.Function;
+import java.util.function.Function;
 
 /**
  * Performs a transformation on FieldExpression values.
diff --git a/src/main/java/com/cronutils/model/field/value/FieldValue.java b/src/main/java/com/cronutils/model/field/value/FieldValue.java
index 17829b3..9e071dc 100644
--- a/src/main/java/com/cronutils/model/field/value/FieldValue.java
+++ b/src/main/java/com/cronutils/model/field/value/FieldValue.java
@@ -1,7 +1,5 @@
 package com.cronutils.model.field.value;
 
-import java.io.Serializable;
-
 /*
  * Copyright 2015 jmrozanec
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +18,7 @@ import java.io.Serializable;
  * manipulate different types of values in a homogeneous way
  * @param <T>
  */
-public abstract class FieldValue<T extends Serializable>  implements Serializable {
-    
+public abstract class FieldValue<T> {
     /**
      * Allows to obtain the value
      * @return some value, never null
diff --git a/src/main/java/com/cronutils/model/time/ExecutionTime.java b/src/main/java/com/cronutils/model/time/ExecutionTime.java
index 1dc946c..48ea03d 100644
--- a/src/main/java/com/cronutils/model/time/ExecutionTime.java
+++ b/src/main/java/com/cronutils/model/time/ExecutionTime.java
@@ -9,23 +9,20 @@ import com.cronutils.model.field.definition.DayOfWeekFieldDefinition;
 import com.cronutils.model.field.expression.Always;
 import com.cronutils.model.field.expression.QuestionMark;
 import com.cronutils.model.time.generator.FieldValueGenerator;
-import com.cronutils.model.time.generator.NoDaysForMonthException;
 import com.cronutils.model.time.generator.NoSuchValueException;
 import com.cronutils.utils.Preconditions;
 import com.cronutils.utils.VisibleForTesting;
-import com.google.common.base.Optional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.threeten.bp.*;
+import java.time.*;
 import java.util.*;
-import com.cronutils.Function;
 
 import static com.cronutils.model.field.CronFieldName.*;
 import static com.cronutils.model.field.value.SpecialChar.QUESTION_MARK;
 import static com.cronutils.model.time.generator.FieldValueGeneratorFactory.createDayOfMonthValueGeneratorInstance;
 import static com.cronutils.model.time.generator.FieldValueGeneratorFactory.createDayOfWeekValueGeneratorInstance;
-import static org.threeten.bp.temporal.TemporalAdjusters.lastDayOfMonth;
+import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;
 
 /*
  * Copyright 2014 jmrozanec
@@ -113,18 +110,18 @@ public class ExecutionTime {
     /**
      * Provide nearest date for next execution.
      * @param date - ZonedDateTime instance. If null, a NullPointerException will be raised.
-     * @return Optional<ZonedDateTime> instance, never null. Contains next execution time or empty.
+     * @return ZonedDateTime instance, never null. Next execution time.
      */
-    public Optional<ZonedDateTime> nextExecution(ZonedDateTime date) {
+    public ZonedDateTime nextExecution(ZonedDateTime date) {
         Preconditions.checkNotNull(date);
         try {
             ZonedDateTime nextMatch = nextClosestMatch(date);
             if(nextMatch.equals(date)){
                 nextMatch = nextClosestMatch(date.plusSeconds(1));
             }
-            return Optional.of(nextMatch);
+            return nextMatch;
         } catch (NoSuchValueException e) {
-            return Optional.absent();
+            throw new IllegalArgumentException(e);
         }
     }
 
@@ -136,14 +133,6 @@ public class ExecutionTime {
      * @throws NoSuchValueException
      */
     private ZonedDateTime nextClosestMatch(ZonedDateTime date) throws NoSuchValueException {
-        ExecutionTimeResult newdate = new ExecutionTimeResult(date, false);
-        do {
-            newdate = potentialNextClosestMatch(newdate.getTime());
-        } while(!newdate.isMatch());
-        return newdate.getTime();
-    }
-
-    private ExecutionTimeResult potentialNextClosestMatch(ZonedDateTime date) throws NoSuchValueException {
         List<Integer> year = yearsValueGenerator.generateCandidates(date.getYear(), date.getYear());
         TimeNode days = null;
         int lowestMonth = months.getValues().get(0);
@@ -155,11 +144,7 @@ public class ExecutionTime {
         ZonedDateTime newDate;
         if(year.isEmpty()){
             int newYear = yearsValueGenerator.generateNextValue(date.getYear());
-            try {
-                days = generateDays(cronDefinition, ZonedDateTime.of(LocalDateTime.of(newYear, lowestMonth, 1, 0, 0), date.getZone()));
-            } catch (NoDaysForMonthException e) {
-                return new ExecutionTimeResult(date.plusMonths(1), false);
-            }
+            days = generateDays(cronDefinition, ZonedDateTime.of(LocalDateTime.of(newYear, lowestMonth, 1, 0, 0), date.getZone()));
             return initDateTime(yearsValueGenerator.generateNextValue(date.getYear()), lowestMonth, days.getValues().get(0), lowestHour, lowestMinute, lowestSecond, date.getZone());
         }
         if(!months.getValues().contains(date.getMonthValue())) {
@@ -168,33 +153,23 @@ public class ExecutionTime {
             if(nearestValue.getShifts()>0){
                 newDate =
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), 1, 1, 0, 0, 0), date.getZone()).plusYears(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return nextClosestMatch(newDate);
             }
             if (nearestValue.getValue() < date.getMonthValue()) {
-                date = date.plusYears(1);
-                return initDateTime(date.getYear(), nextMonths, days.getValues().get(0), lowestHour, lowestMinute, lowestSecond, date.getZone());
-            }
-            try {
-                days = generateDays(cronDefinition, ZonedDateTime.of(LocalDateTime.of(date.getYear(), nextMonths, 1, 0, 0), date.getZone()));
-            } catch (NoDaysForMonthException e) {
-                return new ExecutionTimeResult(date.plusMonths(1), false);
+            	date = date.plusYears(1);
             }
+            days = generateDays(cronDefinition, ZonedDateTime.of(LocalDateTime.of(date.getYear(), nextMonths, 1, 0, 0), date.getZone()));
             return initDateTime(date.getYear(), nextMonths, days.getValues().get(0), lowestHour, lowestMinute, lowestSecond, date.getZone());
         }
-        try {
-            days = generateDays(cronDefinition, date);
-        } catch (NoDaysForMonthException e) {
-            return new ExecutionTimeResult(date.plusMonths(1), false);
-        }
+        days = generateDays(cronDefinition, date);       
         if(!days.getValues().contains(date.getDayOfMonth())) {
             nearestValue = days.getNextValue(date.getDayOfMonth(), 0);
             if(nearestValue.getShifts()>0){
                 newDate = ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(), 1, 0, 0, 0), date.getZone()).plusMonths(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return nextClosestMatch(newDate);
             }
             if (nearestValue.getValue() < date.getDayOfMonth()) {
-                date = date.plusMonths(1);
-                return initDateTime(date.getYear(), date.getMonthValue(), nearestValue.getValue(), lowestHour, lowestMinute, lowestSecond, date.getZone());
+            	date = date.plusMonths(1);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), nearestValue.getValue(), lowestHour, lowestMinute, lowestSecond, date.getZone());
         }
@@ -205,11 +180,10 @@ public class ExecutionTime {
                 newDate =
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(),
                                 date.getDayOfMonth(), 0, 0, 0), date.getZone()).plusDays(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return nextClosestMatch(newDate);
             }
             if (nearestValue.getValue() < date.getHour()) {
-                date = date.plusDays(1);
-                return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), nextHours, lowestMinute, lowestSecond, date.getZone());
+            	date = date.plusDays(1);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), nextHours, lowestMinute, lowestSecond, date.getZone());
         }
@@ -220,11 +194,10 @@ public class ExecutionTime {
                 newDate =
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(),
                                 0, 0), date.getZone()).plusHours(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return nextClosestMatch(newDate);
             }
             if (nearestValue.getValue() < date.getMinute()) {
-                date = date.plusHours(1);
-                return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(), nextMinutes, lowestSecond, date.getZone());
+            	date = date.plusHours(1);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(), nextMinutes, lowestSecond, date.getZone());
         }
@@ -236,15 +209,14 @@ public class ExecutionTime {
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(),
                                 date.getDayOfMonth(), date.getHour(),
                                 date.getMinute(),0), date.getZone()).plusMinutes(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return nextClosestMatch(newDate);
             }
             if (nearestValue.getValue() < date.getSecond()) {
-                date = date.plusMinutes(1);
-                return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(), date.getMinute(), nextSeconds, date.getZone());
+            	date = date.plusMinutes(1);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(), date.getMinute(), nextSeconds, date.getZone());
         }
-        return new ExecutionTimeResult(date, true);
+        return date;
     }
 
     /**
@@ -255,21 +227,8 @@ public class ExecutionTime {
      * @throws NoSuchValueException
      */
     private ZonedDateTime previousClosestMatch(ZonedDateTime date) throws NoSuchValueException {
-        ExecutionTimeResult newdate = new ExecutionTimeResult(date, false);
-        do {
-            newdate = potentialPreviousClosestMatch(newdate.getTime());
-        } while(!newdate.isMatch());
-        return newdate.getTime();
-    }
-
-    private ExecutionTimeResult potentialPreviousClosestMatch(ZonedDateTime date) throws NoSuchValueException {
         List<Integer> year = yearsValueGenerator.generateCandidates(date.getYear(), date.getYear());
-        TimeNode days = null;
-        try {
-            days = generateDays(cronDefinition, date);
-        } catch (NoDaysForMonthException e) {
-            return new ExecutionTimeResult(date.minusMonths(1), false);
-        }
+        TimeNode days = generateDays(cronDefinition, date);
         int highestMonth = months.getValues().get(months.getValues().size()-1);
         int highestDay = days.getValues().get(days.getValues().size()-1);
         int highestHour = hours.getValues().get(hours.getValues().size()-1);
@@ -287,7 +246,7 @@ public class ExecutionTime {
                     if(nearestValue.getShifts()>0){
                         newDate = ZonedDateTime.of(LocalDateTime.of(previousYear, highestMonth, 1, 23, 59, 59), ZoneId.systemDefault())
                                 .minusMonths(nearestValue.getShifts()).with(lastDayOfMonth());
-                        return new ExecutionTimeResult(newDate, false);
+                        return previousClosestMatch(newDate);
                     }else{
                         highestDay = nearestValue.getValue();
                     }
@@ -301,7 +260,7 @@ public class ExecutionTime {
             if(nearestValue.getShifts()>0){
                 newDate =
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), 12, 31, 23, 59, 59), date.getZone()).minusYears(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return previousClosestMatch(newDate);
             }
             return initDateTime(date.getYear(), previousMonths, highestDay, highestHour, highestMinute, highestSecond, date.getZone());
         }
@@ -310,7 +269,7 @@ public class ExecutionTime {
             if(nearestValue.getShifts()>0){
                 newDate = ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(), 1, 23, 59, 59), date.getZone())
                         .minusMonths(nearestValue.getShifts()).with(lastDayOfMonth());
-                return new ExecutionTimeResult(newDate, false);
+                return previousClosestMatch(newDate);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), nearestValue.getValue(), highestHour, highestMinute, highestSecond, date.getZone());
         }
@@ -320,7 +279,7 @@ public class ExecutionTime {
                 newDate =
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(),
                                 date.getDayOfMonth(), 23, 59, 59), date.getZone()).minusDays(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return previousClosestMatch(newDate);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), nearestValue.getValue(), highestMinute, highestSecond, date.getZone());
         }
@@ -330,7 +289,7 @@ public class ExecutionTime {
                 newDate =
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(),
                                 date.getDayOfMonth(), date.getHour(), 59, 59), date.getZone()).minusHours(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return previousClosestMatch(newDate);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(), nearestValue.getValue(), highestSecond, date.getZone());
         }
@@ -342,14 +301,14 @@ public class ExecutionTime {
                         ZonedDateTime.of(LocalDateTime.of(date.getYear(), date.getMonthValue(),
                                 date.getDayOfMonth(), date.getHour(),
                                 date.getMinute(), 59), date.getZone()).minusMinutes(nearestValue.getShifts());
-                return new ExecutionTimeResult(newDate, false);
+                return previousClosestMatch(newDate);
             }
             return initDateTime(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), date.getHour(), date.getMinute(), previousSeconds, date.getZone());
         }
-        return new ExecutionTimeResult(date, true);
+        return date;
     }
 
-    private TimeNode generateDays(CronDefinition cronDefinition, ZonedDateTime date) throws NoDaysForMonthException {
+    private TimeNode generateDays(CronDefinition cronDefinition, ZonedDateTime date){
         //If DoW is not supported in custom definition, we just return an empty list.
         if(cronDefinition.getFieldDefinition(DAY_OF_WEEK)!=null && cronDefinition.getFieldDefinition(DAY_OF_MONTH)!=null){
             return generateDaysDoWAndDoMSupported(cronDefinition, date);
@@ -360,28 +319,27 @@ public class ExecutionTime {
         return generateDayCandidatesUsingDoW(date, ((DayOfWeekFieldDefinition)cronDefinition.getFieldDefinition(DAY_OF_WEEK)).getMondayDoWValue());
     }
 
-    private TimeNode generateDaysDoWAndDoMSupported(CronDefinition cronDefinition, ZonedDateTime date) throws NoDaysForMonthException {
+    private TimeNode generateDaysDoWAndDoMSupported(CronDefinition cronDefinition, ZonedDateTime date){
         boolean questionMarkSupported =
                 cronDefinition.getFieldDefinition(DAY_OF_WEEK).getConstraints().getSpecialChars().contains(QUESTION_MARK);
-        List<Integer> candidates = new ArrayList<>();
         if(questionMarkSupported){
-            candidates = generateDayCandidatesQuestionMarkSupportedUsingDoWAndDoM(
-                    date.getYear(),
-                    date.getMonthValue(),
-                    ((DayOfWeekFieldDefinition)cronDefinition.getFieldDefinition(DAY_OF_WEEK)).getMondayDoWValue()
+            return new TimeNode(
+                    generateDayCandidatesQuestionMarkSupportedUsingDoWAndDoM(
+                            date.getYear(),
+                            date.getMonthValue(),
+                            ((DayOfWeekFieldDefinition)cronDefinition.getFieldDefinition(DAY_OF_WEEK)).getMondayDoWValue()
+                    )
             );
         }else{
-            candidates = generateDayCandidatesQuestionMarkNotSupportedUsingDoWAndDoM(
-                    date.getYear(), date.getMonthValue(),
-                    ((DayOfWeekFieldDefinition)
-                            cronDefinition.getFieldDefinition(DAY_OF_WEEK)
-                    ).getMondayDoWValue()
+            return new TimeNode(
+                    generateDayCandidatesQuestionMarkNotSupportedUsingDoWAndDoM(
+                            date.getYear(), date.getMonthValue(),
+                            ((DayOfWeekFieldDefinition)
+                                    cronDefinition.getFieldDefinition(DAY_OF_WEEK)
+                            ).getMondayDoWValue()
+                    )
             );
         }
-        if(candidates.isEmpty()){
-            throw new NoDaysForMonthException();
-        }
-        return new TimeNode(candidates);
     }
 
     /**
@@ -389,29 +347,25 @@ public class ExecutionTime {
      * @param date - ZonedDateTime instance. If null, a NullPointerException will be raised.
      * @return Duration instance, never null. Time to next execution.
      */
-    public Optional<Duration> timeToNextExecution(ZonedDateTime date){
-        Optional<ZonedDateTime> next = nextExecution(date);
-        if(next.isPresent()){
-            return Optional.of(Duration.between(date, next.get()));
-        }
-        return Optional.absent();
+    public Duration timeToNextExecution(ZonedDateTime date){
+        return Duration.between(date, nextExecution(date));
     }
 
     /**
      * Provide nearest date for last execution.
      * @param date - ZonedDateTime instance. If null, a NullPointerException will be raised.
-     * @return Optional<ZonedDateTime> instance, never null. Last execution time or empty.
+     * @return ZonedDateTime instance, never null. Last execution time.
      */
-    public Optional<ZonedDateTime> lastExecution(ZonedDateTime date){
+    public ZonedDateTime lastExecution(ZonedDateTime date){
         Preconditions.checkNotNull(date);
         try {
             ZonedDateTime previousMatch = previousClosestMatch(date);
             if(previousMatch.equals(date)){
                 previousMatch = previousClosestMatch(date.minusSeconds(1));
             }
-            return Optional.of(previousMatch);
+            return previousMatch;
         } catch (NoSuchValueException e) {
-            return Optional.absent();
+            throw new IllegalArgumentException(e);
         }
     }
 
@@ -420,12 +374,8 @@ public class ExecutionTime {
      * @param date - ZonedDateTime instance. If null, a NullPointerException will be raised.
      * @return Duration instance, never null. Time from last execution.
      */
-    public Optional<Duration> timeFromLastExecution(ZonedDateTime date){
-        Optional<ZonedDateTime> last = lastExecution(date);
-        if(last.isPresent()){
-            return Optional.of(Duration.between(last.get(), date));
-        }
-        return Optional.absent();
+    public Duration timeFromLastExecution(ZonedDateTime date){
+        return Duration.between(lastExecution(date), date);
     }
 
     /**
@@ -434,23 +384,18 @@ public class ExecutionTime {
      * @return true if date matches cron expression requirements, false otherwise.
      */
     public boolean isMatch(ZonedDateTime date){
-        Optional<ZonedDateTime> last = lastExecution(date);
-        if(last.isPresent()){
-            Optional<ZonedDateTime> next = nextExecution(last.get());
-            if(next.isPresent()){
-                return next.get().equals(date);
-            }else{
-                boolean everythingInRange = false;
-                try {
-                    everythingInRange = dateValuesInExpectedRanges(nextClosestMatch(date), date);
-                } catch (NoSuchValueException ignored) {}
-                try {
-                    everythingInRange = dateValuesInExpectedRanges(previousClosestMatch(date), date);
-                } catch (NoSuchValueException ignored) {}
-                return everythingInRange;
-            }
+        try{
+            return nextExecution(lastExecution(date)).equals(date);
+        }catch (IllegalArgumentException e) {
+            boolean everythingInRange = false;
+            try {
+                everythingInRange = dateValuesInExpectedRanges(nextClosestMatch(date), date);
+            } catch (NoSuchValueException ignored) {}
+            try {
+                everythingInRange = dateValuesInExpectedRanges(previousClosestMatch(date), date);
+            } catch (NoSuchValueException ignored) {}
+            return everythingInRange;
         }
-        return false;
     }
 
     private boolean dateValuesInExpectedRanges(ZonedDateTime validCronDate, ZonedDateTime date){
@@ -544,8 +489,8 @@ public class ExecutionTime {
         return new TimeNode(candidatesList);
     }
 
-    private ExecutionTimeResult initDateTime(int years, int monthsOfYear, int dayOfMonth,
-                                  int hoursOfDay, int minutesOfHour, int secondsOfMinute, ZoneId timeZone) throws NoSuchValueException {
+    private ZonedDateTime initDateTime(int years, int monthsOfYear, int dayOfMonth,
+                                  int hoursOfDay, int minutesOfHour, int secondsOfMinute, ZoneId timeZone) {
         ZonedDateTime date =
                 ZonedDateTime.of(LocalDateTime.of(0, 1, 1, 0, 0, 0), timeZone)
                         .plusYears(years)
@@ -554,11 +499,8 @@ public class ExecutionTime {
                         .plusHours(hoursOfDay)
                         .plusMinutes(minutesOfHour)
                         .plusSeconds(secondsOfMinute);
-        ZonedDateTime result = ensureSameDate(date, years, monthsOfYear, dayOfMonth, hoursOfDay, minutesOfHour, secondsOfMinute);
-        if(isSameDate(result, years, monthsOfYear, dayOfMonth, hoursOfDay, minutesOfHour, secondsOfMinute)){
-            return new ExecutionTimeResult(result, true);
-        }
-        return new ExecutionTimeResult(result, false);
+        return ensureSameDate(date, years, monthsOfYear, dayOfMonth,
+                hoursOfDay, minutesOfHour, secondsOfMinute);
     }
 
     private ZonedDateTime ensureSameDate(ZonedDateTime date, int years, int monthsOfYear, int dayOfMonth,
@@ -571,10 +513,6 @@ public class ExecutionTime {
         }
         if(date.getHour()!=hoursOfDay){
             date = date.plusHours(hoursOfDay-date.getHour());
-            if(date.getHour()<hoursOfDay){
-                //we just switched more hours than required due to daylight savings - we need to move past this change seeking next match
-                date = date.plusHours(hoursOfDay-date.getHour());
-            }
         }
         if(date.getDayOfMonth()!=dayOfMonth){
             date = date.plusDays(dayOfMonth-date.getDayOfMonth());
@@ -587,29 +525,4 @@ public class ExecutionTime {
         }
         return date;
     }
-
-    private boolean isSameDate(ZonedDateTime date, int years, int monthsOfYear, int dayOfMonth,
-                                         int hoursOfDay, int minutesOfHour, int secondsOfMinute){
-        return date.getSecond()==secondsOfMinute && date.getMinute()==minutesOfHour &&
-                date.getHour()==hoursOfDay && date.getDayOfMonth()==dayOfMonth &&
-                date.getMonthValue()==monthsOfYear && date.getYear()==years;
-    }
-
-    private static class ExecutionTimeResult {
-        private ZonedDateTime time;
-        private boolean isMatch;
-
-        private ExecutionTimeResult(ZonedDateTime time, boolean isMatch) {
-            this.time = time;
-            this.isMatch = isMatch;
-        }
-
-        public ZonedDateTime getTime() {
-            return time;
-        }
-
-        public boolean isMatch() {
-            return isMatch;
-        }
-    }
 }
diff --git a/src/main/java/com/cronutils/model/time/generator/AndFieldValueGenerator.java b/src/main/java/com/cronutils/model/time/generator/AndFieldValueGenerator.java
index 5ee6212..7e99fc8 100644
--- a/src/main/java/com/cronutils/model/time/generator/AndFieldValueGenerator.java
+++ b/src/main/java/com/cronutils/model/time/generator/AndFieldValueGenerator.java
@@ -6,9 +6,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import com.cronutils.Function;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /*
@@ -103,12 +102,7 @@ class AndFieldValueGenerator extends FieldValueGenerator {
         for (FieldExpression expression : and.getExpressions()) {
             candidates.add(function.apply(createCandidateGeneratorInstance(new CronField(cronField.getField(), expression, cronField.getConstraints()))));
         }
-        List<Integer> filteredCandidates = new ArrayList<>();
-        for (Integer candidate : candidates) {
-            if(candidate >= 0)  filteredCandidates.add(candidate);
-        }
-        Collections.sort(filteredCandidates);
-        return filteredCandidates;
+        return candidates.parallelStream().filter(integer -> integer>=0).sorted().collect(Collectors.toList());
     }
 
     private FieldValueGenerator createCandidateGeneratorInstance(CronField cronField){
diff --git a/src/main/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGenerator.java b/src/main/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGenerator.java
index 8c50bc2..3997055 100644
--- a/src/main/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGenerator.java
+++ b/src/main/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGenerator.java
@@ -9,7 +9,7 @@ import com.cronutils.model.field.expression.FieldExpression;
 import com.cronutils.parser.CronParserField;
 import com.cronutils.utils.Preconditions;
 
-import org.threeten.bp.LocalDate;
+import java.time.LocalDate;
 import java.util.*;
 /*
  * Copyright 2015 jmrozanec
diff --git a/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java b/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java
index 2737cab..ea027d8 100644
--- a/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java
+++ b/src/main/java/com/cronutils/model/time/generator/EveryFieldValueGenerator.java
@@ -9,7 +9,7 @@ import com.cronutils.utils.VisibleForTesting;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.threeten.bp.ZonedDateTime;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.List;
 /*
diff --git a/src/main/java/com/cronutils/model/time/generator/NoDaysForMonthException.java b/src/main/java/com/cronutils/model/time/generator/NoDaysForMonthException.java
deleted file mode 100644
index 876d26e..0000000
--- a/src/main/java/com/cronutils/model/time/generator/NoDaysForMonthException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.cronutils.model.time.generator;
-/*
- * Copyright 2017 jmrozanec
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-public class NoDaysForMonthException extends Exception {
-}
diff --git a/src/main/java/com/cronutils/model/time/generator/OnDayOfMonthValueGenerator.java b/src/main/java/com/cronutils/model/time/generator/OnDayOfMonthValueGenerator.java
index b8a7aba..b4be272 100644
--- a/src/main/java/com/cronutils/model/time/generator/OnDayOfMonthValueGenerator.java
+++ b/src/main/java/com/cronutils/model/time/generator/OnDayOfMonthValueGenerator.java
@@ -6,8 +6,8 @@ import com.cronutils.model.field.expression.FieldExpression;
 import com.cronutils.model.field.expression.On;
 import com.cronutils.utils.Preconditions;
 
-import org.threeten.bp.DayOfWeek;
-import org.threeten.bp.LocalDate;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/src/main/java/com/cronutils/model/time/generator/OnDayOfWeekValueGenerator.java b/src/main/java/com/cronutils/model/time/generator/OnDayOfWeekValueGenerator.java
index 1f87645..6fce26c 100644
--- a/src/main/java/com/cronutils/model/time/generator/OnDayOfWeekValueGenerator.java
+++ b/src/main/java/com/cronutils/model/time/generator/OnDayOfWeekValueGenerator.java
@@ -8,8 +8,8 @@ import com.cronutils.model.field.expression.FieldExpression;
 import com.cronutils.model.field.expression.On;
 import com.cronutils.utils.Preconditions;
 
-import org.threeten.bp.DayOfWeek;
-import org.threeten.bp.LocalDate;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
 import java.util.ArrayList;
 import java.util.List;
 /*
diff --git a/src/main/java/com/cronutils/parser/FieldParser.java b/src/main/java/com/cronutils/parser/FieldParser.java
index 0dfbe98..4c2628f 100644
--- a/src/main/java/com/cronutils/parser/FieldParser.java
+++ b/src/main/java/com/cronutils/parser/FieldParser.java
@@ -60,9 +60,6 @@ public class FieldParser {
 	 */
 	public FieldExpression parse(String expression) {
 		if (!StringUtils.containsAny(expression, SPECIAL_CHARS_MINUS_STAR)) {
-			if(expression.contains(QUESTION_MARK_STRING) && !fieldConstraints.getSpecialChars().contains(QUESTION_MARK)){
-				throw new IllegalArgumentException("Invalid expression: " + expression);
-			}
 			return noSpecialCharsNorStar(expression);
 		} else {
 			String[] array = expression.split(",");
diff --git a/src/main/resources/CronUtilsI18N_tr.properties b/src/main/resources/CronUtilsI18N_tr.properties
deleted file mode 100644
index bbc8633..0000000
--- a/src/main/resources/CronUtilsI18N_tr.properties
+++ /dev/null
@@ -1,23 +0,0 @@
-between_x_and_y={0} ve {1} aras\u0131nda
-every=her
-and=ve
-at=\u015Fu zamanda :
-day=g\u00FCn
-days=g\u00FC
-hour=saat
-hours=saat
-minute=dakika
-minutes=dakika
-second=saniye
-seconds=saniye
-month=ay
-months=ay
-year=y\u0131l
-years=y\u0131l
-between=aras\u0131nda
-of_every_month=her ay\u0131n
-of_the_month=ay\u0131n
-last=son
-the_nearest_weekday_to_the=\u015Fu zamana en yak\u0131n hafta i\u00E7i g\u00FCn\u00FC
-last_day_of_month=ay\u0131n son g\u00FCn\u00FC
-last_weekday_of_month=ay\u0131n son hafta i\u00E7i g\u00FCn\u00FC


Test patch:
diff --git a/src/androidTest/java/com/cronutils/BaseAndroidTest.java b/src/androidTest/java/com/cronutils/BaseAndroidTest.java
deleted file mode 100644
index 55124a1..0000000
--- a/src/androidTest/java/com/cronutils/BaseAndroidTest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.cronutils;
-
-
-import android.app.Application;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.jakewharton.threetenabp.AndroidThreeTen;
-
-import org.junit.Before;
-import org.junit.runner.RunWith;
-
-public class BaseAndroidTest {
-    protected final Application application =
-            (Application) InstrumentationRegistry.getTargetContext().getApplicationContext();
-
-    @Before
-    public void setUp() throws Exception {
-        AndroidThreeTen.init(application);
-    }
-}
diff --git a/src/androidTest/java/com/cronutils/Issue143Test.java b/src/androidTest/java/com/cronutils/Issue143Test.java
deleted file mode 100644
index ae02734..0000000
--- a/src/androidTest/java/com/cronutils/Issue143Test.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.cronutils;
-
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.runner.RunWith;
-import org.threeten.bp.LocalDateTime;
-import org.threeten.bp.ZoneId;
-import org.threeten.bp.ZonedDateTime;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.cronutils.model.CronType;
-import com.cronutils.model.definition.CronDefinitionBuilder;
-import com.cronutils.model.time.ExecutionTime;
-import com.cronutils.parser.CronParser;
-
-@RunWith(AndroidJUnit4.class)
-public class Issue143Test extends BaseAndroidTest {
-
-    private CronParser    parser;
-    private ZonedDateTime currentDateTime;
-    
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        // Make sure that current date is before Dec-31
-        currentDateTime = ZonedDateTime.of(LocalDateTime.of(2016, 12, 20, 12, 00), 
-                                           ZoneId.systemDefault());
-
-        parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
-    }
-    
-    @Test
-    public void testCase1() {
-        ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 31 12 ? *"));
-        ZonedDateTime actual = et.lastExecution(currentDateTime).get();
-        
-        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2015, 12, 31, 12, 00), 
-                                                  ZoneId.systemDefault());
-        Assert.assertEquals(expected, actual);
-    }
-    
-//    @Test
-    public void testCase2() {
-        ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 ? 12 SAT#5 *"));
-        ZonedDateTime actual = et.lastExecution(currentDateTime).get();
-        
-        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2012, 12, 29, 12, 00), 
-                ZoneId.systemDefault());
-        Assert.assertEquals(expected, actual);
-    }
-    
-//    @Test
-    public void testCase3() {
-        ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 31 1/1 ? *"));
-        ZonedDateTime actual = et.lastExecution(currentDateTime).get();
-        
-        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2015, 12, 31, 12, 00), 
-                ZoneId.systemDefault());
-        Assert.assertEquals(expected, actual);
-    }
-    
-//    @Test
-    public void testCase4() {
-        ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 ? 1/1 SAT#5 *"));
-        ZonedDateTime actual = et.lastExecution(currentDateTime).get();
-        
-        ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2016, 10, 29, 12, 00), 
-                ZoneId.systemDefault());
-        Assert.assertEquals(expected, actual);
-    }
-    
-}
diff --git a/src/androidTest/java/com/cronutils/Issue55UnexpectedExecutionTimes.java b/src/test/java/com/cronutils/Issue55UnexpectedExecutionTimes.java
similarity index 90%
rename from src/androidTest/java/com/cronutils/Issue55UnexpectedExecutionTimes.java
rename to src/test/java/com/cronutils/Issue55UnexpectedExecutionTimes.java
index dd41baa..71143d3 100644
--- a/src/androidTest/java/com/cronutils/Issue55UnexpectedExecutionTimes.java
+++ b/src/test/java/com/cronutils/Issue55UnexpectedExecutionTimes.java
@@ -1,7 +1,5 @@
 package com.cronutils;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.model.Cron;
 import com.cronutils.model.definition.CronConstraint;
 import com.cronutils.model.definition.CronDefinition;
@@ -13,23 +11,20 @@ import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.Instant;
-import org.threeten.bp.ZoneOffset;
-import org.threeten.bp.ZonedDateTime;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
 
-@RunWith(AndroidJUnit4.class)
-public class Issue55UnexpectedExecutionTimes extends BaseAndroidTest {
+public class Issue55UnexpectedExecutionTimes {
     private CronDefinition cronDefinition;
 
     /** Setup. */
     @Before
-    public void setUp() throws Exception {
-        super.setUp();
+    public void setUp(){
         cronDefinition = CronDefinitionBuilder.defineCron()
                 .withMinutes().and()
                 .withHours().and()
@@ -90,10 +85,10 @@ public class Issue55UnexpectedExecutionTimes extends BaseAndroidTest {
 
     private List<Instant> getInstants(ExecutionTime executionTime, ZonedDateTime startTime, ZonedDateTime endTime){
         List<Instant> instantList = new ArrayList<>();
-        ZonedDateTime next = executionTime.nextExecution(startTime).get();
+        ZonedDateTime next = executionTime.nextExecution(startTime);
         while(next.isBefore(endTime)){
             instantList.add(next.toInstant());
-            next = executionTime.nextExecution(next).get();
+            next = executionTime.nextExecution(next);
         }
         return instantList;
     }
diff --git a/src/androidTest/java/com/cronutils/Issue58UnixCronAsStringIntegrationTest.java b/src/test/java/com/cronutils/Issue58UnixCronAsStringIntegrationTest.java
similarity index 93%
rename from src/androidTest/java/com/cronutils/Issue58UnixCronAsStringIntegrationTest.java
rename to src/test/java/com/cronutils/Issue58UnixCronAsStringIntegrationTest.java
index 5993018..51cdca7 100644
--- a/src/androidTest/java/com/cronutils/Issue58UnixCronAsStringIntegrationTest.java
+++ b/src/test/java/com/cronutils/Issue58UnixCronAsStringIntegrationTest.java
@@ -1,7 +1,5 @@
 package com.cronutils;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.model.Cron;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinition;
@@ -9,13 +7,11 @@ import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.hamcrest.core.AnyOf.anyOf;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
 
-@RunWith(AndroidJUnit4.class)
 public class Issue58UnixCronAsStringIntegrationTest {
     private CronParser cronParser;
 
diff --git a/src/androidTest/java/com/cronutils/OpenIssuesTest.java b/src/test/java/com/cronutils/OpenIssuesTest.java
similarity index 88%
rename from src/androidTest/java/com/cronutils/OpenIssuesTest.java
rename to src/test/java/com/cronutils/OpenIssuesTest.java
index 50a3a38..394a819 100644
--- a/src/androidTest/java/com/cronutils/OpenIssuesTest.java
+++ b/src/test/java/com/cronutils/OpenIssuesTest.java
@@ -1,7 +1,5 @@
 package com.cronutils;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.model.Cron;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinitionBuilder;
@@ -10,12 +8,9 @@ import com.cronutils.parser.CronParser;
 import org.junit.Test;
 
 import java.text.ParseException;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.ZonedDateTime;
-import org.threeten.bp.format.DateTimeFormatter;
-
-@RunWith(AndroidJUnit4.class)
 public class OpenIssuesTest {
     private DateTimeFormatter dfSimple = DateTimeFormatter.ofPattern("hh:mm:ss MM/dd/yyyy a X");
     private DateTimeFormatter df = DateTimeFormatter.ofPattern("hh:mm:ss EEE, MMM dd yyyy a X");
@@ -56,7 +51,7 @@ public class OpenIssuesTest {
 
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
 
-        return executionTime.nextExecution(lastExecution).get();
+        return executionTime.nextExecution(lastExecution);
     }
 }
 
diff --git a/src/androidTest/java/com/cronutils/mapper/ConstantsMapperTest.java b/src/test/java/com/cronutils/mapper/ConstantsMapperTest.java
similarity index 95%
rename from src/androidTest/java/com/cronutils/mapper/ConstantsMapperTest.java
rename to src/test/java/com/cronutils/mapper/ConstantsMapperTest.java
index c4b0b27..fc3ce2d 100644
--- a/src/androidTest/java/com/cronutils/mapper/ConstantsMapperTest.java
+++ b/src/test/java/com/cronutils/mapper/ConstantsMapperTest.java
@@ -1,11 +1,6 @@
 package com.cronutils.mapper;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
-
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -20,7 +15,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class ConstantsMapperTest {
 
     @Test
diff --git a/src/androidTest/java/com/cronutils/mapper/CronMapperIntegrationTest.java b/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java
similarity index 96%
rename from src/androidTest/java/com/cronutils/mapper/CronMapperIntegrationTest.java
rename to src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java
index 638ea4a..5d6cf56 100644
--- a/src/androidTest/java/com/cronutils/mapper/CronMapperIntegrationTest.java
+++ b/src/test/java/com/cronutils/mapper/CronMapperIntegrationTest.java
@@ -1,14 +1,10 @@
 package com.cronutils.mapper;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import com.google.common.collect.Sets;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -25,7 +21,6 @@ import static org.junit.Assert.assertTrue;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class CronMapperIntegrationTest {
 
     @Test
diff --git a/src/test/java/com/cronutils/mapper/CronMapperTest.java b/src/test/java/com/cronutils/mapper/CronMapperTest.java
index 09401fd..abd9e9d 100644
--- a/src/test/java/com/cronutils/mapper/CronMapperTest.java
+++ b/src/test/java/com/cronutils/mapper/CronMapperTest.java
@@ -11,7 +11,7 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import com.cronutils.Function;
+import java.util.function.Function;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
diff --git a/src/androidTest/java/com/cronutils/mapper/WeekDayTest.java b/src/test/java/com/cronutils/mapper/WeekDayTest.java
similarity index 93%
rename from src/androidTest/java/com/cronutils/mapper/WeekDayTest.java
rename to src/test/java/com/cronutils/mapper/WeekDayTest.java
index 9f518e5..ef3cdb9 100644
--- a/src/androidTest/java/com/cronutils/mapper/WeekDayTest.java
+++ b/src/test/java/com/cronutils/mapper/WeekDayTest.java
@@ -1,12 +1,7 @@
 package com.cronutils.mapper;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
-
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -21,7 +16,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class WeekDayTest {
     private WeekDay source;
     private int mondayDoWValue = 1;
diff --git a/src/test/java/com/cronutils/model/CronTest.java b/src/test/java/com/cronutils/model/CronTest.java
index e5f36ee..c5a5a0c 100644
--- a/src/test/java/com/cronutils/model/CronTest.java
+++ b/src/test/java/com/cronutils/model/CronTest.java
@@ -13,11 +13,6 @@ import org.junit.Test;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
 import java.util.List;
 
 import static org.junit.Assert.*;
@@ -105,40 +100,4 @@ public class CronTest {
         assertFalse(cron1.equivalent(CronMapper.sameCron(unixcd), cron3));
         assertTrue(cron1.equivalent(CronMapper.fromQuartzToCron4j(), cron4));
     }
-    
-    @Test
-    public void testSerialization() throws IOException, ClassNotFoundException {
-        CronDefinition cron4jcd = CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J);
-        CronDefinition unixcd = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
-        CronDefinition quartzcd = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
-        CronParser unix = new CronParser(unixcd);
-        CronParser quartz = new CronParser(quartzcd);
-        CronParser cron4j = new CronParser(cron4jcd);
-        
-        Cron[] toTest = new Cron[] {
-            unix.parse("* * * * MON"),
-            unix.parse("*/1 * * * 1"),
-            unix.parse("0 * * * *"),
-            unix.parse("*/2 * * * *"),
-            quartz.parse("0 * * ? * MON *"),
-            cron4j.parse("* 1 1,2 * 4"),
-            cron4j.parse("* 1 1-2 * 4"),
-            cron4j.parse("0 18 * * 1"),
-            cron4j.parse("0/15 * * * *"),
-            cron4j.parse("0 0/2 * * *"),
-            cron4j.parse("0 6 * * MON-FRI") 
-        };
-        
-        for ( Cron expected : toTest ) {
-            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
-            try ( ObjectOutputStream objOut = new ObjectOutputStream( byteOut ) ) {
-                objOut.writeObject( expected );
-            }
-            
-            try ( ObjectInputStream objIn = new ObjectInputStream( new ByteArrayInputStream( byteOut.toByteArray() ) ) ) {
-                Cron actual = (Cron) objIn.readObject();
-                assertEquals( expected.asString() , actual.asString() );
-            }
-        }
-    }       
 }
\ No newline at end of file
diff --git a/src/androidTest/java/com/cronutils/model/definition/CronDefinitionBuilderTest.java b/src/test/java/com/cronutils/model/definition/CronDefinitionBuilderTest.java
similarity index 90%
rename from src/androidTest/java/com/cronutils/model/definition/CronDefinitionBuilderTest.java
rename to src/test/java/com/cronutils/model/definition/CronDefinitionBuilderTest.java
index 65b660f..1db18aa 100644
--- a/src/androidTest/java/com/cronutils/model/definition/CronDefinitionBuilderTest.java
+++ b/src/test/java/com/cronutils/model/definition/CronDefinitionBuilderTest.java
@@ -1,20 +1,14 @@
 package com.cronutils.model.definition;
 
-import com.cronutils.model.Cron;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.CronType;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.model.field.definition.FieldDefinition;
 import com.cronutils.model.field.value.SpecialChar;
-import com.cronutils.parser.CronParser;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.Set;
 
@@ -31,7 +25,6 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class CronDefinitionBuilderTest {
 
     private CronDefinitionBuilder builder;
@@ -146,12 +139,4 @@ public class CronDefinitionBuilderTest {
     public void testInstanceDefinitionForUnknownValue() throws Exception {
         assertNotNull(CronDefinitionBuilder.instanceDefinitionFor(null));
     }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testCronDefinitionShouldNotAcceptQuestionmark() throws Exception {
-        CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX);
-        CronParser parser = new CronParser(cronDefinition);
-        Cron quartzCron = parser.parse("* * * * ?");
-        quartzCron.validate();
-    }
-}
+}
\ No newline at end of file
diff --git a/src/androidTest/java/com/cronutils/model/definition/CronDefinitionIssue25IntegrationTest.java b/src/test/java/com/cronutils/model/definition/CronDefinitionIssue25IntegrationTest.java
similarity index 93%
rename from src/androidTest/java/com/cronutils/model/definition/CronDefinitionIssue25IntegrationTest.java
rename to src/test/java/com/cronutils/model/definition/CronDefinitionIssue25IntegrationTest.java
index c555467..d346f1d 100644
--- a/src/androidTest/java/com/cronutils/model/definition/CronDefinitionIssue25IntegrationTest.java
+++ b/src/test/java/com/cronutils/model/definition/CronDefinitionIssue25IntegrationTest.java
@@ -1,15 +1,11 @@
 package com.cronutils.model.definition;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.Cron;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.time.ExecutionTime;
 import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 
@@ -25,7 +21,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class CronDefinitionIssue25IntegrationTest {
     private CronDefinition cronDefinition;
     final String CRON_EXPRESSION = "0 18 1";
diff --git a/src/androidTest/java/com/cronutils/model/field/FieldParserTest.java b/src/test/java/com/cronutils/model/field/FieldParserTest.java
similarity index 96%
rename from src/androidTest/java/com/cronutils/model/field/FieldParserTest.java
rename to src/test/java/com/cronutils/model/field/FieldParserTest.java
index 26ed1df..17d856c 100644
--- a/src/androidTest/java/com/cronutils/model/field/FieldParserTest.java
+++ b/src/test/java/com/cronutils/model/field/FieldParserTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.field;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.constraint.FieldConstraintsBuilder;
 import com.cronutils.model.field.expression.*;
 import com.cronutils.model.field.value.IntegerFieldValue;
@@ -10,7 +7,6 @@ import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.parser.FieldParser;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -27,7 +23,6 @@ import static org.junit.Assert.assertTrue;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class FieldParserTest {
     private FieldParser parser;
 
diff --git a/src/androidTest/java/com/cronutils/model/field/constraints/FieldConstraintsTest.java b/src/test/java/com/cronutils/model/field/constraints/FieldConstraintsTest.java
similarity index 92%
rename from src/androidTest/java/com/cronutils/model/field/constraints/FieldConstraintsTest.java
rename to src/test/java/com/cronutils/model/field/constraints/FieldConstraintsTest.java
index 988f92f..9a7380e 100644
--- a/src/androidTest/java/com/cronutils/model/field/constraints/FieldConstraintsTest.java
+++ b/src/test/java/com/cronutils/model/field/constraints/FieldConstraintsTest.java
@@ -1,15 +1,11 @@
 package com.cronutils.model.field.constraints;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.model.field.value.SpecialChar;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.Map;
 import java.util.Set;
@@ -25,7 +21,6 @@ import java.util.Set;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class FieldConstraintsTest {
 
     private Map<String, Integer> stringMapping;
diff --git a/src/test/java/com/cronutils/model/field/FieldDefinitionBuilderTest.java b/src/test/java/com/cronutils/model/field/definition/FieldDefinitionBuilderTest.java
similarity index 95%
rename from src/test/java/com/cronutils/model/field/FieldDefinitionBuilderTest.java
rename to src/test/java/com/cronutils/model/field/definition/FieldDefinitionBuilderTest.java
index b8f011d..e15b421 100644
--- a/src/test/java/com/cronutils/model/field/FieldDefinitionBuilderTest.java
+++ b/src/test/java/com/cronutils/model/field/definition/FieldDefinitionBuilderTest.java
@@ -1,12 +1,9 @@
-package com.cronutils.model.field;
+package com.cronutils.model.field.definition;
 
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.model.field.constraint.FieldConstraintsBuilder;
-import com.cronutils.model.field.definition.FieldDefinition;
-import com.cronutils.model.field.definition.FieldDefinitionBuilder;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/src/test/java/com/cronutils/model/definition/FieldDefinitionTest.java b/src/test/java/com/cronutils/model/field/definition/FieldDefinitionTest.java
similarity index 97%
rename from src/test/java/com/cronutils/model/definition/FieldDefinitionTest.java
rename to src/test/java/com/cronutils/model/field/definition/FieldDefinitionTest.java
index 28f6076..aacc856 100644
--- a/src/test/java/com/cronutils/model/definition/FieldDefinitionTest.java
+++ b/src/test/java/com/cronutils/model/field/definition/FieldDefinitionTest.java
@@ -1,9 +1,7 @@
-package com.cronutils.model.definition;
+package com.cronutils.model.field.definition;
 
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
-import com.cronutils.model.field.definition.FieldDefinition;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
diff --git a/src/androidTest/java/com/cronutils/model/field/expression/AlwaysTest.java b/src/test/java/com/cronutils/model/field/expression/AlwaysTest.java
similarity index 84%
rename from src/androidTest/java/com/cronutils/model/field/expression/AlwaysTest.java
rename to src/test/java/com/cronutils/model/field/expression/AlwaysTest.java
index deb13d6..78f25b2 100644
--- a/src/androidTest/java/com/cronutils/model/field/expression/AlwaysTest.java
+++ b/src/test/java/com/cronutils/model/field/expression/AlwaysTest.java
@@ -1,11 +1,6 @@
 package com.cronutils.model.field.expression;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
-
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -20,7 +15,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class AlwaysTest {
 
     @Test
diff --git a/src/androidTest/java/com/cronutils/model/field/expression/BetweenTest.java b/src/test/java/com/cronutils/model/field/expression/BetweenTest.java
similarity index 92%
rename from src/androidTest/java/com/cronutils/model/field/expression/BetweenTest.java
rename to src/test/java/com/cronutils/model/field/expression/BetweenTest.java
index 7f60a7e..28da0b4 100644
--- a/src/androidTest/java/com/cronutils/model/field/expression/BetweenTest.java
+++ b/src/test/java/com/cronutils/model/field/expression/BetweenTest.java
@@ -1,14 +1,10 @@
 package com.cronutils.model.field.expression;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.value.IntegerFieldValue;
 import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -23,7 +19,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class BetweenTest {
     private int from;
     private int to;
diff --git a/src/androidTest/java/com/cronutils/model/field/expression/EveryTest.java b/src/test/java/com/cronutils/model/field/expression/EveryTest.java
similarity index 87%
rename from src/androidTest/java/com/cronutils/model/field/expression/EveryTest.java
rename to src/test/java/com/cronutils/model/field/expression/EveryTest.java
index 7889d7b..c47d108 100644
--- a/src/androidTest/java/com/cronutils/model/field/expression/EveryTest.java
+++ b/src/test/java/com/cronutils/model/field/expression/EveryTest.java
@@ -1,11 +1,7 @@
 package com.cronutils.model.field.expression;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.value.IntegerFieldValue;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -20,7 +16,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class EveryTest {
     @Test
     public void testGetTime() throws Exception {
diff --git a/src/androidTest/java/com/cronutils/model/field/expression/OnTest.java b/src/test/java/com/cronutils/model/field/expression/OnTest.java
similarity index 94%
rename from src/androidTest/java/com/cronutils/model/field/expression/OnTest.java
rename to src/test/java/com/cronutils/model/field/expression/OnTest.java
index ff2072b..3cf06ec 100644
--- a/src/androidTest/java/com/cronutils/model/field/expression/OnTest.java
+++ b/src/test/java/com/cronutils/model/field/expression/OnTest.java
@@ -1,14 +1,10 @@
 package com.cronutils.model.field.expression;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.value.IntegerFieldValue;
 import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -23,7 +19,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class OnTest {
     private int time;
     private int nth;
diff --git a/src/androidTest/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitorTest.java b/src/test/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitorTest.java
similarity index 83%
rename from src/androidTest/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitorTest.java
rename to src/test/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitorTest.java
index a2d0d13..82c2d03 100644
--- a/src/androidTest/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitorTest.java
+++ b/src/test/java/com/cronutils/model/field/expression/visitor/ValueMappingFieldExpressionVisitorTest.java
@@ -1,19 +1,14 @@
 package com.cronutils.model.field.expression.visitor;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.expression.QuestionMark;
 import com.cronutils.model.field.value.FieldValue;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-import com.cronutils.Function;
+import java.util.function.Function;
 
 import static org.junit.Assert.assertTrue;
 
-@RunWith(AndroidJUnit4.class)
 public class ValueMappingFieldExpressionVisitorTest {
     private ValueMappingFieldExpressionVisitor valueMappingFieldExpressionVisitor;
 
diff --git a/src/androidTest/java/com/cronutils/model/time/ExecutionTimeCron4jIntegrationTest.java b/src/test/java/com/cronutils/model/time/ExecutionTimeCron4jIntegrationTest.java
similarity index 72%
rename from src/androidTest/java/com/cronutils/model/time/ExecutionTimeCron4jIntegrationTest.java
rename to src/test/java/com/cronutils/model/time/ExecutionTimeCron4jIntegrationTest.java
index cd842cd..e0d2dfb 100644
--- a/src/androidTest/java/com/cronutils/model/time/ExecutionTimeCron4jIntegrationTest.java
+++ b/src/test/java/com/cronutils/model/time/ExecutionTimeCron4jIntegrationTest.java
@@ -1,19 +1,14 @@
 package com.cronutils.model.time;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.threeten.bp.ZoneId;
-import org.threeten.bp.ZonedDateTime;
+import java.time.ZonedDateTime;
 
 import static org.junit.Assert.*;
 
@@ -29,8 +24,7 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
-public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
+public class ExecutionTimeCron4jIntegrationTest {
     private CronParser cron4jCronParser;
     private static final String EVERY_MONDAY_AT_18 = "0 18 * * 1";
     private static final String EVERY_15_MINUTES = "0/15 * * * *";
@@ -39,8 +33,7 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
 	private static final Logger log = LoggerFactory.getLogger(ExecutionTimeCron4jIntegrationTest.class);
 
     @Before
-    public void setUp() throws Exception {
-        super.setUp();
+    public void setUp(){
         cron4jCronParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.CRON4J));
     }
 
@@ -61,9 +54,9 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
         // and make sure the next run time is always in the future from the prior run time
 		for (int i = 0; i < 8; i++) {
 
-            ZonedDateTime nextRun = executionTime.nextExecution(lastRun).get();
-			log.info("LastRun = [{}]", lastRun);
-			log.info("NextRun = [{}]", nextRun);
+            ZonedDateTime nextRun = executionTime.nextExecution(lastRun);
+			log.debug("LastRun = [{}]", lastRun);
+			log.debug("NextRun = [{}]", nextRun);
 
 			assertNotEquals(6, nextRun.getDayOfWeek());
 			assertNotEquals(7, nextRun.getDayOfWeek());
@@ -84,37 +77,16 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
         // and make sure the next run time is always in the future from the prior run time
 		for (int i = 0; i < 36; i++) {
 
-            ZonedDateTime nextRun = executionTime.nextExecution(lastRun).get();
-			log.info("LastRun = [{}]", lastRun);
-			log.info("NextRun = [{}]", nextRun);
+            ZonedDateTime nextRun = executionTime.nextExecution(lastRun);
+			log.debug("LastRun = [{}]", lastRun);
+			log.debug("NextRun = [{}]", nextRun);
 
-			assertTrue(String.format("Hour is %s", nextRun.getHour()), nextRun.getHour() % 2 == 0);
-			assertTrue(String.format("Last run is before next one: %s", lastRun.isBefore(nextRun)), lastRun.isBefore(nextRun));
+			assertTrue(nextRun.getHour() % 2 == 0);
+			assertTrue(lastRun.isBefore(nextRun));
             lastRun = lastRun.plusHours(1);
 		}
     }
 
-    @Test
-    public void testQuick() throws Exception {
-        ZonedDateTime lastRun = ZonedDateTime.of(2017, 3, 12, 0, 55, 50, 630, ZoneId.of("America/Los_Angeles"));
-        ExecutionTime executionTime = ExecutionTime.forCron(cron4jCronParser.parse(EVERY_2_HOURS));
-
-        // iterate through the next 36 hours so we roll over the to the next day
-        // and make sure the next run time is always in the future from the prior run time
-        for (int i = 0; i < 1; i++) {
-
-            ZonedDateTime nextRun = executionTime.nextExecution(lastRun).get();
-            log.info("LastRun = [{}]", lastRun);
-            log.info("NextRun = [{}]", nextRun);
-
-            assertTrue(String.format("Hour is %s", nextRun.getHour()), nextRun.getHour() % 2 == 0);
-            assertTrue(String.format("Last run is before next one: %s", lastRun.isBefore(nextRun)), lastRun.isBefore(nextRun));
-            lastRun = lastRun.plusHours(1);
-        }
-    }
-
-
-
     /**
      * Issue #37:  nextExecution not calculating correct time
      */
@@ -127,7 +99,7 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
         // and make sure the next run time is always in the future from the prior run time
 		for (int i = 0; i < 75; i++) {
 
-            ZonedDateTime nextRun = executionTime.nextExecution(lastRun).get();
+            ZonedDateTime nextRun = executionTime.nextExecution(lastRun);
 			log.debug("LastRun = [{}]", lastRun);
 			log.debug("NextRun = [{}]", nextRun);
 
@@ -144,7 +116,7 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
     public void testDayOfWeekOverridesAlwaysAtDayOfMonth() throws Exception {
         ZonedDateTime now = ZonedDateTime.now();
         ExecutionTime executionTime = ExecutionTime.forCron(cron4jCronParser.parse(EVERY_MONDAY_AT_18));
-        ZonedDateTime next = executionTime.nextExecution(now).get();
+        ZonedDateTime next = executionTime.nextExecution(now);
         assertEquals(1, next.getDayOfWeek().getValue());
         assertTrue(now.isBefore(next));
     }
@@ -156,7 +128,7 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
     public void testDayOfMonthOverridesAlwaysAtDayOfWeek() throws Exception {
         ZonedDateTime now = ZonedDateTime.now();
         ExecutionTime executionTime = ExecutionTime.forCron(cron4jCronParser.parse("0 18 1 * *"));
-        ZonedDateTime next = executionTime.nextExecution(now).get();
+        ZonedDateTime next = executionTime.nextExecution(now);
         assertEquals(1, next.getDayOfMonth());
         assertTrue(now.isBefore(next));
     }
@@ -168,8 +140,8 @@ public class ExecutionTimeCron4jIntegrationTest extends BaseAndroidTest {
     public void testNextExecutionOverNextExecution() throws Exception {
         ZonedDateTime now = ZonedDateTime.now();
         ExecutionTime executionTime = ExecutionTime.forCron(cron4jCronParser.parse(EVERY_MONDAY_AT_18));
-        ZonedDateTime next = executionTime.nextExecution(now).get();
-        ZonedDateTime nextNext = executionTime.nextExecution(next).get();
+        ZonedDateTime next = executionTime.nextExecution(now);
+        ZonedDateTime nextNext = executionTime.nextExecution(next);
         assertTrue(now.isBefore(next));
         assertTrue(next.isBefore(nextNext));
     }
diff --git a/src/androidTest/java/com/cronutils/model/time/ExecutionTimeCustomDefinitionIntegrationTest.java b/src/test/java/com/cronutils/model/time/ExecutionTimeCustomDefinitionIntegrationTest.java
similarity index 90%
rename from src/androidTest/java/com/cronutils/model/time/ExecutionTimeCustomDefinitionIntegrationTest.java
rename to src/test/java/com/cronutils/model/time/ExecutionTimeCustomDefinitionIntegrationTest.java
index 02af852..01c9fc0 100644
--- a/src/androidTest/java/com/cronutils/model/time/ExecutionTimeCustomDefinitionIntegrationTest.java
+++ b/src/test/java/com/cronutils/model/time/ExecutionTimeCustomDefinitionIntegrationTest.java
@@ -1,30 +1,19 @@
 package com.cronutils.model.time;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.Cron;
 import com.cronutils.model.definition.CronDefinition;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
-
-import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.threeten.bp.ZoneId;
-import org.threeten.bp.ZonedDateTime;
 
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+import static java.time.ZoneOffset.UTC;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.threeten.bp.ZoneOffset.UTC;
 
-@RunWith(AndroidJUnit4.class)
-public class ExecutionTimeCustomDefinitionIntegrationTest extends BaseAndroidTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-    }
+public class ExecutionTimeCustomDefinitionIntegrationTest {
 
     @Test
     public void testCronExpressionAfterHalf() {
@@ -45,7 +34,7 @@ public class ExecutionTimeCustomDefinitionIntegrationTest extends BaseAndroidTes
 
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
 
-        ZonedDateTime nextExecutionDateTime = executionTime.nextExecution(startDateTime).get();
+        ZonedDateTime nextExecutionDateTime = executionTime.nextExecution(startDateTime);
         assertEquals(expectedDateTime, nextExecutionDateTime);
     }
 
@@ -70,7 +59,7 @@ public class ExecutionTimeCustomDefinitionIntegrationTest extends BaseAndroidTes
 
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
 
-        ZonedDateTime nextExecutionDateTime = executionTime.nextExecution(startDateTime).get();
+        ZonedDateTime nextExecutionDateTime = executionTime.nextExecution(startDateTime);
         assertEquals(expectedDateTime, nextExecutionDateTime);
     }
 
@@ -95,7 +84,7 @@ public class ExecutionTimeCustomDefinitionIntegrationTest extends BaseAndroidTes
         Cron cron = parser.parse("0 0 */2 * * *");
         ZonedDateTime startDateTime = ZonedDateTime.parse("2015-08-28T12:05:14.000-03:00");
 
-        assertTrue(ZonedDateTime.parse("2015-08-28T14:00:00.000-03:00").compareTo(ExecutionTime.forCron(cron).nextExecution(startDateTime).get()) == 0);
+        assertTrue(ZonedDateTime.parse("2015-08-28T14:00:00.000-03:00").compareTo(ExecutionTime.forCron(cron).nextExecution(startDateTime)) == 0);
     }
 
     /**
@@ -119,7 +108,7 @@ public class ExecutionTimeCustomDefinitionIntegrationTest extends BaseAndroidTes
         Cron cron = parser.parse("0 0 /2 * * *");
         ZonedDateTime startDateTime = ZonedDateTime.parse("2015-08-28T12:05:14.000-03:00");
 
-        assertTrue(ZonedDateTime.parse("2015-08-28T14:00:00.000-03:00").compareTo(ExecutionTime.forCron(cron).nextExecution(startDateTime).get()) == 0);
+        assertTrue(ZonedDateTime.parse("2015-08-28T14:00:00.000-03:00").compareTo(ExecutionTime.forCron(cron).nextExecution(startDateTime)) == 0);
     }
 
     /**
@@ -148,9 +137,9 @@ public class ExecutionTimeCustomDefinitionIntegrationTest extends BaseAndroidTes
         CronParser parser = new CronParser(cronDefinition);
         Cron cron = parser.parse("30 3 * * MON-FRI");
         ZonedDateTime sameDayBeforeEventStartDateTime = ZonedDateTime.parse("1970-01-01T00:00:00.000-03:00");
-        assertEquals(1, ExecutionTime.forCron(cron).nextExecution(sameDayBeforeEventStartDateTime).get().getDayOfMonth());
+        assertEquals(1, ExecutionTime.forCron(cron).nextExecution(sameDayBeforeEventStartDateTime).getDayOfMonth());
         ZonedDateTime sameDayAfterEventStartDateTime = ZonedDateTime.parse("1970-01-01T12:00:00.000-03:00");
-        assertEquals(2, ExecutionTime.forCron(cron).nextExecution(sameDayAfterEventStartDateTime).get().getDayOfMonth());
+        assertEquals(2, ExecutionTime.forCron(cron).nextExecution(sameDayAfterEventStartDateTime).getDayOfMonth());
     }
 
     /**
diff --git a/src/androidTest/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java b/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java
similarity index 78%
rename from src/androidTest/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java
rename to src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java
index 6328a81..8fc1ed2 100644
--- a/src/androidTest/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java
+++ b/src/test/java/com/cronutils/model/time/ExecutionTimeQuartzIntegrationTest.java
@@ -1,26 +1,20 @@
 package com.cronutils.model.time;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.descriptor.CronDescriptor;
 import com.cronutils.model.Cron;
 import com.cronutils.model.definition.CronDefinition;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
-import com.google.common.base.Optional;
-import org.junit.Assert;
+
 import org.junit.Before;
 import org.junit.Test;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.*;
-import org.threeten.bp.format.DateTimeFormatter;
-import org.threeten.bp.temporal.ChronoUnit;
-import java.util.*;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 
 import static com.cronutils.model.CronType.QUARTZ;
-import static org.threeten.bp.ZoneOffset.UTC;
+import static java.time.ZoneOffset.UTC;
 import static org.junit.Assert.*;
 
 /*
@@ -35,14 +29,12 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
-public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
+public class ExecutionTimeQuartzIntegrationTest {
     private CronParser parser;
     private static final String EVERY_SECOND = "* * * * * ? *";
 
     @Before
-    public void setUp() throws Exception {
-        super.setUp();
+    public void setUp(){
         parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(QUARTZ));
     }
 
@@ -56,7 +48,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         ZonedDateTime now = truncateToSeconds(ZonedDateTime.now());
         ZonedDateTime expected = truncateToSeconds(now.plusSeconds(1));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND));
-        assertEquals(expected, executionTime.nextExecution(now).get());
+        assertEquals(expected, executionTime.nextExecution(now));
     }
 
     @Test
@@ -64,7 +56,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         ZonedDateTime now = truncateToSeconds(ZonedDateTime.now());
         ZonedDateTime expected = truncateToSeconds(now.plusSeconds(1));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND));
-        assertEquals(Duration.between(now, expected), executionTime.timeToNextExecution(now).get());
+        assertEquals(Duration.between(now, expected), executionTime.timeToNextExecution(now));
     }
 
     @Test
@@ -72,7 +64,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         ZonedDateTime now = truncateToSeconds(ZonedDateTime.now());
         ZonedDateTime expected = truncateToSeconds(now.minusSeconds(1));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND));
-        assertEquals(expected, executionTime.lastExecution(now).get());
+        assertEquals(expected, executionTime.lastExecution(now));
     }
 
     @Test
@@ -80,7 +72,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         ZonedDateTime now = truncateToSeconds(ZonedDateTime.now());
         ZonedDateTime expected = truncateToSeconds(now.minusSeconds(1));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(EVERY_SECOND));
-        assertEquals(Duration.between(expected, now), executionTime.timeToNextExecution(now).get());
+        assertEquals(Duration.between(expected, now), executionTime.timeToNextExecution(now));
     }
 
     /**
@@ -94,7 +86,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         //seconds, minutes, hours, dayOfMonth, month, dayOfWeek
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 11 11 11 11 ?"));
         ZonedDateTime now = ZonedDateTime.of(2015, 4, 15, 0, 0, 0, 0, UTC);
-        ZonedDateTime whenToExecuteNext = executionTime.nextExecution(now).get();
+        ZonedDateTime whenToExecuteNext = executionTime.nextExecution(now);
         assertEquals(2015, whenToExecuteNext.getYear());
         assertEquals(11, whenToExecuteNext.getMonthValue());
         assertEquals(11, whenToExecuteNext.getDayOfMonth());
@@ -114,7 +106,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         String quartzCronExpression = String.format("0 0 %s * * ?", previousHour.getHour());
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(quartzCronExpression));
 
-        assertTrue(executionTime.timeFromLastExecution(now).get().toMinutes() <= 120);
+        assertTrue(executionTime.timeFromLastExecution(now).toMinutes() <= 120);
     }
 
     /**
@@ -130,7 +122,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
 
         ZonedDateTime now = ZonedDateTime.of(LocalDate.of(2016, 8, 5), LocalTime.of(23, 59, 59, 0), UTC);
         ZonedDateTime expected = now.plusSeconds(1);
-        ZonedDateTime nextExecution = executionTime.nextExecution(now).get();
+        ZonedDateTime nextExecution = executionTime.nextExecution(now);
 
         assertEquals(expected, nextExecution);
     }
@@ -148,7 +140,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
 
         ZonedDateTime now = ZonedDateTime.of(2015, 1, 31, 23, 59, 59, 0, UTC);
         ZonedDateTime expected = now.plusSeconds(1);
-        ZonedDateTime nextExecution = executionTime.nextExecution(now).get();
+        ZonedDateTime nextExecution = executionTime.nextExecution(now);
 
         assertEquals(expected, nextExecution);
     }
@@ -159,7 +151,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
     @Test
     public void testTimeShiftingProperlyDone() throws Exception {
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0/10 22 ? * *"));
-        ZonedDateTime nextExecution = executionTime.nextExecution(ZonedDateTime.now().withHour(15).withMinute(27)).get();
+        ZonedDateTime nextExecution = executionTime.nextExecution(ZonedDateTime.now().withHour(15).withMinute(27));
         assertEquals(22, nextExecution.getHour());
         assertEquals(0, nextExecution.getMinute());
     }
@@ -179,8 +171,8 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
     public void testSaturdayExecutionTime(){
         ZonedDateTime now = ZonedDateTime.now();
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 3 ? * 6"));
-        ZonedDateTime last = executionTime.lastExecution(now).get();
-        ZonedDateTime next = executionTime.nextExecution(now).get();
+        ZonedDateTime last = executionTime.lastExecution(now);
+        ZonedDateTime next = executionTime.nextExecution(now);
         assertNotEquals(last, next);
     }
 
@@ -191,8 +183,8 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
     public void testWeekdayExecutionTime(){
         ZonedDateTime now = ZonedDateTime.now();
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0 3 ? * *"));
-        ZonedDateTime last = executionTime.lastExecution(now).get();
-        ZonedDateTime next = executionTime.nextExecution(now).get();
+        ZonedDateTime last = executionTime.lastExecution(now);
+        ZonedDateTime next = executionTime.nextExecution(now);
         assertNotEquals(last, next);
     }
 
@@ -203,7 +195,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
     public void testExecutionTimeForRanges(){
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("* 10-20 * * * ? 2099"));
         ZonedDateTime scanTime = ZonedDateTime.parse("2016-02-29T11:00:00.000-06:00");
-        ZonedDateTime nextTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextTime = executionTime.nextExecution(scanTime);
         assertNotNull(nextTime);
         assertEquals(10, nextTime.getMinute());
     }
@@ -215,7 +207,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
     public void testLastExecutionTimeForFixedMonth(){
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 30 12 1 9 ? 2010"));
         ZonedDateTime scanTime = ZonedDateTime.parse("2016-01-08T11:00:00.000-06:00");
-        ZonedDateTime lastTime = executionTime.lastExecution(scanTime).get();
+        ZonedDateTime lastTime = executionTime.lastExecution(scanTime);
         assertNotNull(lastTime);
         assertEquals(9, lastTime.getMonthValue());
     }
@@ -228,7 +220,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         //cron format: s,m,H,DoM,M,DoW,Y
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 * * ? 5 1 *"));
         ZonedDateTime scanTime = ZonedDateTime.parse("2016-03-06T20:17:28.000-03:00");
-        ZonedDateTime nextTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextTime = executionTime.nextExecution(scanTime);
         assertNotNull(nextTime);
         assertEquals(DayOfWeek.SUNDAY, nextTime.getDayOfWeek());
     }
@@ -241,7 +233,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         //cron format: s,m,H,DoM,M,DoW,Y
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 * * ? * 1 2099"));
         ZonedDateTime scanTime = ZonedDateTime.parse("2016-03-06T20:17:28.000-03:00");
-        ZonedDateTime nextTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextTime = executionTime.nextExecution(scanTime);
         assertNotNull(nextTime);
         assertEquals(DayOfWeek.SUNDAY, nextTime.getDayOfWeek());
     }
@@ -275,8 +267,8 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         Cron cron = parser.parse(cronText);
         final ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime now = ZonedDateTime.parse("2016-03-18T19:02:51.424+09:00");
-        ZonedDateTime next = executionTime.nextExecution(now).get();
-        ZonedDateTime nextNext = executionTime.nextExecution(next).get();
+        ZonedDateTime next = executionTime.nextExecution(now);
+        ZonedDateTime nextNext = executionTime.nextExecution(next);
         assertEquals(DayOfWeek.MONDAY, next.getDayOfWeek());
         assertEquals(DayOfWeek.MONDAY, nextNext.getDayOfWeek());
         assertEquals(18, next.getHour());
@@ -295,10 +287,10 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         String expression = "* 8-10,23-25,38-40,53-55 * * * ? *"; // every second for intervals of minutes
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(expression));
 
-        assertEquals(301, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(3, 1, 0, 0), UTC)).get().getSeconds());
-        assertEquals(1, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(13, 8, 4, 0), UTC)).get().getSeconds());
-        assertEquals(1, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(13, 11, 0, 0), UTC)).get().getSeconds());
-        assertEquals(63, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(13, 12, 2, 0), UTC)).get().getSeconds());
+        assertEquals(301, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(3, 1, 0, 0), UTC)).getSeconds());
+        assertEquals(1, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(13, 8, 4, 0), UTC)).getSeconds());
+        assertEquals(1, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(13, 11, 0, 0), UTC)).getSeconds());
+        assertEquals(63, executionTime.timeFromLastExecution(ZonedDateTime.of(LocalDate.now(), LocalTime.of(13, 12, 2, 0), UTC)).getSeconds());
     }
 
     /**
@@ -319,7 +311,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
 
     @Test
     public void testDayLightSavingsSwitch() {
-        //every 2 minutes
+        // every 2 minutes
         String expression = "* 0/2 * * * ?";
         Cron cron = parser.parse(expression);
 
@@ -329,25 +321,29 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         ZonedDateTime prevRun = ZonedDateTime.parse("2016 03 13 01:59:59", formatter);
 
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        ZonedDateTime nextRun = executionTime.nextExecution(prevRun).get();
+        ZonedDateTime nextRun = executionTime.nextExecution(prevRun);
         // Assert we got 3:00am
         assertEquals("Incorrect Hour", 3, nextRun.getHour());
         assertEquals("Incorrect Minute", 0, nextRun.getMinute());
 
         // SIMULATE SCHEDULE POST DST - simulate a schedule after DST 3:01 with the same cron, expect 3:02
         nextRun = nextRun.plusMinutes(1);
-        nextRun = executionTime.nextExecution(nextRun).get();
+        nextRun = executionTime.nextExecution(nextRun);
         assertEquals("Incorrect Hour", 3, nextRun.getHour());
         assertEquals("Incorrect Minute", 2, nextRun.getMinute());
 
         // SIMULATE SCHEDULE NEXT DAY DST - verify after midnight on DST switch things still work as expected
         prevRun = ZonedDateTime.parse("2016-03-14T00:00:59Z");
-        nextRun = executionTime.nextExecution(prevRun).get();
+        nextRun = executionTime.nextExecution(prevRun);
         assertEquals("incorrect hour", nextRun.getHour(), 0);
         assertEquals("incorrect minute", nextRun.getMinute(), 2);
     }
 
-    @Test
+    /**
+     * nexExecution()
+     * throw exceptions when DAY-OF-MONTH field bigger than param month length
+     */
+    @Test(expected = java.lang.IllegalArgumentException.class)
     public void bigNumbersOnDayOfMonthField(){
         Cron cron = parser.parse("0 0 0 31 * ?");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
@@ -355,7 +351,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
 
         //nextRun expected to be  2016-12-31 00:00:00 000
         //quartz-2.2.3 return the right date
-        ZonedDateTime nextRun = executionTime.nextExecution(now).get();
+        ZonedDateTime nextRun = executionTime.nextExecution(now);
 
         assertEquals(ZonedDateTime.of(2016, 12, 31, 0, 0, 0, 0, ZoneId.of("UTC")), nextRun);
     }
@@ -365,7 +361,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         Cron cron = parser.parse("0 * * ? * *");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime now = ZonedDateTime.of(2016, 8, 31, 10, 10, 0,0,ZoneId.of("UTC"));
-        ZonedDateTime nextRun = executionTime.nextExecution(now).get();
+        ZonedDateTime nextRun = executionTime.nextExecution(now);
 
         assertEquals(ZonedDateTime.of(2016, 8, 31, 10, 11, 0, 0, ZoneId.of("UTC")), nextRun);
     }
@@ -380,7 +376,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         ZonedDateTime dt = ZonedDateTime.parse("2016-03-29T00:00:59Z");
 
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        ZonedDateTime nextRun = executionTime.nextExecution(dt).get();
+        ZonedDateTime nextRun = executionTime.nextExecution(dt);
         assertEquals("incorrect Day", nextRun.getDayOfMonth(), 1); // should be April 1st (Friday)
     }
 
@@ -472,7 +468,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         Cron cron = parser.parse("0 * * ? * *");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime now = ZonedDateTime.of(2016, 8, 30, 23, 59, 0,0,ZoneId.of("UTC"));
-        ZonedDateTime nextRun = executionTime.nextExecution(now).get();
+        ZonedDateTime nextRun = executionTime.nextExecution(now);
 
         assertEquals(ZonedDateTime.of(2016, 8, 31, 0, 0, 0,0, ZoneId.of("UTC")), nextRun);
     }
@@ -493,8 +489,8 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
 
         ZonedDateTime zonedDateTime = LocalDateTime.of(2016, 7, 30, 15, 0, 0, 527).atZone(ZoneOffset.UTC);
 
-        ZonedDateTime nextExecution = executionTime.nextExecution(zonedDateTime).get();
-        ZonedDateTime lastExecution = executionTime.lastExecution(zonedDateTime).get();
+        ZonedDateTime nextExecution = executionTime.nextExecution(zonedDateTime);
+        ZonedDateTime lastExecution = executionTime.lastExecution(zonedDateTime);
 
         assertEquals("2016-07-30T14:50Z", lastExecution.toString());
         assertEquals("2016-07-30T15:05Z", nextExecution.toString());
@@ -516,7 +512,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
 
         ZonedDateTime zonedDateTime = LocalDateTime.of(2016, 1, 1, 10, 0, 0, 0).atZone(ZoneOffset.UTC);
 
-        ZonedDateTime nextExecution = executionTime.nextExecution(zonedDateTime).get();
+        ZonedDateTime nextExecution = executionTime.nextExecution(zonedDateTime);
 
         assertEquals("2016-01-01T10:03Z", nextExecution.toString());
     }
@@ -549,117 +545,13 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         }
     }
 
-    /**
-     * Issue #140: https://github.com/jmrozanec/cron-utils/pull/140
-     * IllegalArgumentException: Values must not be empty
-     */
-    @Test
-    public void nextExecutionNotFail(){
-        CronDefinition cronDefinition = CronDefinitionBuilder.instanceDefinitionFor(QUARTZ);
-        CronParser parser = new CronParser(cronDefinition);
-        Cron parsed = parser.parse("0 0 10 ? * SAT-SUN");
-        ExecutionTime executionTime = ExecutionTime.forCron(parsed);
-        Optional<ZonedDateTime> next = executionTime.nextExecution(ZonedDateTime.now());
-    }
-
-    /**
-     * Issue #142: https://github.com/jmrozanec/cron-utils/pull/142
-     * Special Character L for day of week behaves differently in Quartz
-     */
-//    @Test //TODO
-    public void lastDayOfTheWeek() throws Exception {
-        Cron cron = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(QUARTZ)).parse("0 0 0 ? * L *");
-
-        ZoneId utc = ZoneId.of("UTC");
-        ZonedDateTime date = LocalDate.parse("2016-12-22").atStartOfDay(utc);
-
-        ZonedDateTime cronUtilsNextTime = ExecutionTime.forCron(cron).nextExecution(date).get();// 2016-12-30T00:00:00Z
-
-        org.quartz.CronExpression cronExpression = new org.quartz.CronExpression(cron.asString());
-        cronExpression.setTimeZone(DateTimeUtils.toTimeZone(utc));
-        Date quartzNextTime = cronExpression.getNextValidTimeAfter(DateTimeUtils.toDate(date.toInstant()));// 2016-12-24T00:00:00Z
-
-        assertEquals(DateTimeUtils.toInstant(quartzNextTime), cronUtilsNextTime.toInstant()); // false
-    }
-
-    /**
-     * Issue #143: https://github.com/jmrozanec/cron-utils/pull/143
-     * ExecutionTime.lastExecution() throws Exception when cron defines at 31 Dec
-     */
-    @Test
-    public void lastExecutionDec31NotFail(){
-        CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(QUARTZ));
-        ExecutionTime et = ExecutionTime.forCron(parser.parse("0 0 12 31 12 ? *"));
-        System.out.println(et.lastExecution(ZonedDateTime.now()));
-    }
-
-    /**
-     * Issue #144
-     * https://github.com/jmrozanec/cron-utils/issues/144
-     * Reported case: periodic incremental hours does not start and end
-     * at beginning and end of given period
-     */
-//    @Test//TODO
-    public void testPeriodicIncrementalHoursIgnorePeriodBounds() {
-        Cron cron = parser.parse("0 0 16-19/2 * * ?");
-        ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        ZonedDateTime start = ZonedDateTime.of(2016, 12, 27, 8, 15, 0, 0, ZoneId.of("UTC"));
-        ZonedDateTime[] expected = new ZonedDateTime[]{
-            ZonedDateTime.of(2016, 12, 27, 16, 0, 0, 0, ZoneId.of("UTC")),
-            ZonedDateTime.of(2016, 12, 27, 18, 0, 0, 0, ZoneId.of("UTC")),
-            ZonedDateTime.of(2016, 12, 28, 16, 0, 0, 0, ZoneId.of("UTC")),
-            ZonedDateTime.of(2016, 12, 28, 18, 0, 0, 0, ZoneId.of("UTC")),
-            ZonedDateTime.of(2016, 12, 29, 16, 0, 0, 0, ZoneId.of("UTC")),
-        };
-
-        List<ZonedDateTime> actualList = new ArrayList<>();
-        for (int i = 1; i <= 5; i++) {
-            ZonedDateTime next = executionTime.nextExecution(start).get();
-            start = next;
-            actualList.add(next);
-        }
-        Object[] actual = actualList.toArray();
-
-        assertArrayEquals(expected, actual);
-    }
-
-    /**
-     * Issue #153
-     * https://github.com/jmrozanec/cron-utils/issues/153
-     * Reported case: executionTime.nextExecution fails to find when current month does not have desired day
-     */
-    @Test
-    public void mustJumpToNextMonthIfCurrentMonthDoesNotHaveDesiredDay() {
-        CronParser parser = new CronParser( CronDefinitionBuilder.instanceDefinitionFor(QUARTZ));
-        ExecutionTime executionTime = ExecutionTime.forCron( parser.parse( "0 0 8 31 * ?" ) );//8:00 on every 31th of Month
-        ZonedDateTime start = ZonedDateTime.of(2017, 04, 10, 0, 0, 0, 0, ZoneId.systemDefault() );
-        ZonedDateTime next = executionTime.nextExecution(start).get();
-        ZonedDateTime expected = ZonedDateTime.of(2017, 05, 31, 8, 0, 0, 0, ZoneId.systemDefault() );
-        assertEquals( expected, next );
-    }
-
-    /**
-     * Issue #153
-     * https://github.com/jmrozanec/cron-utils/issues/153
-     * Reported case: executionTime.nextExecution fails to find when current month does not have desired day
-     */
-    @Test
-    public void mustJumpToEndOfMonthIfCurrentMonthHasDesiredDay() {
-        CronParser parser = new CronParser( CronDefinitionBuilder.instanceDefinitionFor(QUARTZ));
-        ExecutionTime executionTime = ExecutionTime.forCron( parser.parse( "0 0 8 31 * ?" ) );//8:00 on every 31th of Month
-        ZonedDateTime start = ZonedDateTime.of( 2017, 01, 10, 0, 0, 0, 0, ZoneId.systemDefault() );
-        ZonedDateTime next = executionTime.nextExecution(start).get();
-        ZonedDateTime expected = ZonedDateTime.of( 2017, 01, 31, 8, 0, 0, 0, ZoneId.systemDefault() );
-        assertEquals( expected, next );
-    }
-
     private Duration getMinimumInterval(String quartzPattern) {
         ExecutionTime et = ExecutionTime.forCron(parser.parse(quartzPattern));
         ZonedDateTime coolDay = ZonedDateTime.of(2016, 1, 1, 0, 0, 0, 0, UTC);
         // Find next execution time #1
-        ZonedDateTime t1 = et.nextExecution(coolDay).get();
+        ZonedDateTime t1 = et.nextExecution(coolDay);
         // Find next execution time #2 right after #1, the interval between them is minimum
-        return et.timeToNextExecution(t1).get();
+        return et.timeToNextExecution(t1);
     }
 
     private ZonedDateTime truncateToSeconds(ZonedDateTime dateTime){
@@ -676,7 +568,7 @@ public class ExecutionTimeQuartzIntegrationTest extends BaseAndroidTest {
         Cron cron = parser.parse(cronExpression);
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         try {
-            ZonedDateTime nextRun = executionTime.nextExecution(lastRun).get();
+            ZonedDateTime nextRun = executionTime.nextExecution(lastRun);
             assertEquals(testCaseDescription, expectedNextRun, nextRun);
         }
         catch(DateTimeException e) {
diff --git a/src/androidTest/java/com/cronutils/model/time/NearestValueTest.java b/src/test/java/com/cronutils/model/time/NearestValueTest.java
similarity index 91%
rename from src/androidTest/java/com/cronutils/model/time/NearestValueTest.java
rename to src/test/java/com/cronutils/model/time/NearestValueTest.java
index 4af1204..cf68d3f 100644
--- a/src/androidTest/java/com/cronutils/model/time/NearestValueTest.java
+++ b/src/test/java/com/cronutils/model/time/NearestValueTest.java
@@ -1,10 +1,7 @@
 package com.cronutils.model.time;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import static org.junit.Assert.assertEquals;
 /*
@@ -19,7 +16,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class NearestValueTest {
     private int value;
     private int shifts;
diff --git a/src/androidTest/java/com/cronutils/model/time/TimeNodeTest.java b/src/test/java/com/cronutils/model/time/TimeNodeTest.java
similarity index 97%
rename from src/androidTest/java/com/cronutils/model/time/TimeNodeTest.java
rename to src/test/java/com/cronutils/model/time/TimeNodeTest.java
index d2ca07a..8a9283a 100644
--- a/src/androidTest/java/com/cronutils/model/time/TimeNodeTest.java
+++ b/src/test/java/com/cronutils/model/time/TimeNodeTest.java
@@ -1,11 +1,8 @@
 package com.cronutils.model.time;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.google.common.collect.Lists;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -23,7 +20,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class TimeNodeTest {
     private static final int LIST_START_VALUE = 2;
     private static final int LIST_MEDIUM_VALUE = 4;
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGeneratorTest.java b/src/test/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGeneratorTest.java
similarity index 90%
rename from src/androidTest/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGeneratorTest.java
rename to src/test/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGeneratorTest.java
index 4403ab7..f376c78 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGeneratorTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/BetweenDayOfWeekValueGeneratorTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.mapper.WeekDay;
 import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
@@ -10,13 +7,11 @@ import com.cronutils.model.field.constraint.FieldConstraintsBuilder;
 import com.cronutils.model.field.expression.Between;
 import com.cronutils.model.field.value.IntegerFieldValue;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.List;
 
 import static org.junit.Assert.assertTrue;
 
-@RunWith(AndroidJUnit4.class)
 public class BetweenDayOfWeekValueGeneratorTest {
 
     @Test
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/ExecutionTimeUnixIntegrationTest.java b/src/test/java/com/cronutils/model/time/generator/ExecutionTimeUnixIntegrationTest.java
similarity index 83%
rename from src/androidTest/java/com/cronutils/model/time/generator/ExecutionTimeUnixIntegrationTest.java
rename to src/test/java/com/cronutils/model/time/generator/ExecutionTimeUnixIntegrationTest.java
index a9da43a..c24bb3c 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/ExecutionTimeUnixIntegrationTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/ExecutionTimeUnixIntegrationTest.java
@@ -1,34 +1,22 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.Cron;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinition;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.model.time.ExecutionTime;
 import com.cronutils.parser.CronParser;
-
-import org.junit.Before;
 import org.junit.Test;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.Duration;
-import org.threeten.bp.Instant;
-import org.threeten.bp.ZoneId;
-import org.threeten.bp.ZonedDateTime;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-@RunWith(AndroidJUnit4.class)
-public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-    }
+public class ExecutionTimeUnixIntegrationTest {
 
     @Test
     public void testIsMatchForUnix01(){
@@ -58,7 +46,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("*/10 * * * *"));
         ZonedDateTime time = ZonedDateTime.parse("2015-09-05T13:43:00.000-07:00");
-        assertEquals(ZonedDateTime.parse("2015-09-05T13:50:00.000-07:00"), executionTime.nextExecution(time).get());
+        assertEquals(ZonedDateTime.parse("2015-09-05T13:50:00.000-07:00"), executionTime.nextExecution(time));
     }
 
     /**
@@ -70,8 +58,8 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = new CronParser(cronDefinition).parse("*/2 * * * *");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime time = ZonedDateTime.parse("2015-09-05T13:56:00.000-07:00");
-        ZonedDateTime next = executionTime.nextExecution(time).get();
-        ZonedDateTime shouldBeInNextHour = executionTime.nextExecution(next).get();
+        ZonedDateTime next = executionTime.nextExecution(time);
+        ZonedDateTime shouldBeInNextHour = executionTime.nextExecution(next);
         assertEquals(next.plusMinutes(2), shouldBeInNextHour);
     }
 
@@ -84,7 +72,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         CronParser parser = new CronParser(cronDefinition);
         Cron myCron = parser.parse("0 3 * * 3");
         ZonedDateTime time = ZonedDateTime.parse("2015-09-17T00:00:00.000-07:00");
-        assertEquals(ZonedDateTime.parse("2015-09-23T03:00:00.000-07:00"), ExecutionTime.forCron(myCron).nextExecution(time).get());
+        assertEquals(ZonedDateTime.parse("2015-09-23T03:00:00.000-07:00"), ExecutionTime.forCron(myCron).nextExecution(time));
     }
 
     /**
@@ -96,7 +84,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         CronParser parser = new CronParser(cronDefinition);
         Cron myCron = parser.parse("0 3 * * 3");
         ZonedDateTime time = ZonedDateTime.parse("2015-09-17T00:00:00.000-07:00");
-        assertEquals(ZonedDateTime.parse("2015-09-16T03:00:00.000-07:00"), ExecutionTime.forCron(myCron).lastExecution(time).get());
+        assertEquals(ZonedDateTime.parse("2015-09-16T03:00:00.000-07:00"), ExecutionTime.forCron(myCron).lastExecution(time));
     }
 
     /**
@@ -110,7 +98,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ZonedDateTime date = ZonedDateTime.parse("2015-10-13T17:26:54.468-07:00");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        assertEquals(ZonedDateTime.parse("2015-10-12T23:59:00.000-07:00"), executionTime.lastExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2015-10-12T23:59:00.000-07:00"), executionTime.lastExecution(date));
     }
 
     /**
@@ -124,7 +112,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ZonedDateTime date = ZonedDateTime.parse("2015-10-13T17:26:54.468-07:00");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        assertEquals(ZonedDateTime.parse("2015-10-19T00:00:00.000-07:00"), executionTime.nextExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2015-10-19T00:00:00.000-07:00"), executionTime.nextExecution(date));
     }
 
     /**
@@ -138,7 +126,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ZonedDateTime date = ZonedDateTime.parse("2015-11-02T00:10:00Z");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        assertEquals(ZonedDateTime.parse("2015-10-26T11:00:00Z"), executionTime.lastExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2015-10-26T11:00:00Z"), executionTime.lastExecution(date));
     }
 
     /**
@@ -153,7 +141,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ZonedDateTime date = ZonedDateTime.parse("2015-11-10T17:01:00Z");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        assertEquals(ZonedDateTime.parse("2015-11-10T17:00:00Z"), executionTime.lastExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2015-11-10T17:00:00Z"), executionTime.lastExecution(date));
     }
 
     /**
@@ -168,7 +156,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ZonedDateTime date = ZonedDateTime.parse("2015-11-10T17:01:00Z");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        assertEquals(ZonedDateTime.parse("2015-11-10T17:00:00Z"), executionTime.lastExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2015-11-10T17:00:00Z"), executionTime.lastExecution(date));
     }
 
     /**
@@ -183,7 +171,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime scanTime = ZonedDateTime.parse("2015-12-10T16:32:56.586-08:00");
-        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime);
         //DoW: 0-6 -> 0, 5 (sunday, friday)
         //DoM: 1-31 -> 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31
         //M: 1-12 -> 1, 5, 9
@@ -202,7 +190,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime scanTime = ZonedDateTime.parse("2015-12-10T16:32:56.586-08:00");
-        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime);
         assertEquals(ZonedDateTime.parse("2015-12-13T00:00:00.000-08:00"), nextExecutionTime);
     }
 
@@ -219,7 +207,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
         ZonedDateTime scanTime = ZonedDateTime.parse("2016-01-28T16:32:56.586-08:00");
-        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime);
         assertEquals(ZonedDateTime.parse("2016-02-04T00:00:00.000-08:00"), nextExecutionTime);
     }
 
@@ -233,7 +221,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         //DoW: 0-6 -> 1, 2, 3, 4, 5 -> in this year:
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(crontab));
         ZonedDateTime scanTime = ZonedDateTime.parse("2016-02-29T11:00:00.000-06:00");
-        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime).get();
+        ZonedDateTime nextExecutionTime = executionTime.nextExecution(scanTime);
         assertEquals(ZonedDateTime.parse("2016-02-29T12:00:00.000-06:00"), nextExecutionTime);
     }
 
@@ -246,7 +234,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 17 * * *"));// daily at 17:00
         // Daylight savings for New York 2016 is Mar 13 at 2am
         ZonedDateTime last = ZonedDateTime.of(2016, 3, 12, 17, 0, 0, 0, ZoneId.of("America/New_York"));
-        ZonedDateTime next = executionTime.nextExecution(last).get();
+        ZonedDateTime next = executionTime.nextExecution(last);
         long millis = Duration.between(last, next).toMillis();
         assertEquals(23, (millis / 3600000));
         assertEquals(last.getZone(), next.getZone());
@@ -261,7 +249,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 17 * * *"));// daily at 17:00
         // Daylight savings for New York 2016 is Mar 13 at 2am
         ZonedDateTime now = ZonedDateTime.of(2016, 3, 12, 17, 0, 0, 0, ZoneId.of("America/Phoenix"));
-        ZonedDateTime last = executionTime.lastExecution(now).get();
+        ZonedDateTime last = executionTime.lastExecution(now);
         long millis = Duration.between(last, now).toMillis();
         assertEquals(24, (millis / 3600000));
         assertEquals(now.getZone(), last.getZone());
@@ -278,7 +266,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         Cron cron = parser.parse(crontab);
         ZonedDateTime date = ZonedDateTime.parse("2014-11-30T00:00:00Z");
         ExecutionTime executionTime = ExecutionTime.forCron(cron);
-        assertEquals(ZonedDateTime.parse("2014-12-01T08:00:00Z"), executionTime.nextExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2014-12-01T08:00:00Z"), executionTime.nextExecution(date));
     }
 
     /**
@@ -289,14 +277,14 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("1 0 * * tue"));
         ZonedDateTime date = ZonedDateTime.parse("2016-05-24T01:02:50Z");
-        assertEquals(ZonedDateTime.parse("2016-05-31T00:01:00Z"), executionTime.nextExecution(date).get());
+        assertEquals(ZonedDateTime.parse("2016-05-31T00:01:00Z"), executionTime.nextExecution(date));
     }
 
     /**
      * Issue #112: Calling nextExecution exactly on the first instant of the fallback hour (after the DST ends) makes it go back to DST.
      * https://github.com/jmrozanec/cron-utils/issues/112
      */
-//    @Test TODO
+    //TODO
     public void testWrongNextExecutionOnDSTEnd() throws Exception {
         ZoneId zone = ZoneId.of("America/Sao_Paulo");
 
@@ -306,7 +294,7 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
 
         CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("* * * * *"));
-        assertEquals(expected, executionTime.nextExecution(date).get());
+        assertEquals(expected, executionTime.nextExecution(date));
     }
 
     /**
@@ -319,32 +307,4 @@ public class ExecutionTimeUnixIntegrationTest extends BaseAndroidTest{
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("45 1,13 * * *"));
         executionTime.nextExecution(ZonedDateTime.parse("2016-05-24T01:02:50Z"));
     }
-
-    /**
-     * Issue #130: Wrong last execution time if schedule hit is less than one second ago
-     * https://github.com/jmrozanec/cron-utils/issues/130
-     */
-    @Test
-    public void exact_hit_returns_full_interval_duration() {
-        CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
-        Cron cron = parser.parse("0 12 * * *");
-        final ZonedDateTime time = ZonedDateTime.of(2016, 12, 2, 12, 0, 0, 0, ZoneId.of("Europe/Vienna"));
-        final Duration timeFromLastExecution = ExecutionTime.forCron(cron).timeFromLastExecution(time).get();
-        assertEquals(timeFromLastExecution, Duration.ofHours(24));
-    }
-
-    /**
-     * Issue #130: Wrong last execution time if schedule hit is less than one second ago
-     * https://github.com/jmrozanec/cron-utils/issues/130
-     */
-    @Test
-    public void fuzzy_hit_returns_very_small_interval_duration() {
-        CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX));
-        Cron cron = parser.parse("0 12 * * *");
-        ZonedDateTime time = ZonedDateTime.of(2016, 12, 2, 12, 0, 0, 0, ZoneId.of("Europe/Vienna"));
-        Duration diff = Duration.ofMillis(300);
-        time = time.plus(diff);
-        final Duration timeFromLastExecution = ExecutionTime.forCron(cron).timeFromLastExecution(time).get();
-        assertEquals(timeFromLastExecution, Duration.ofDays(1).plus(diff));
-    }
 }
diff --git a/src/test/java/com/cronutils/model/time/generator/FieldValueGeneratorTest.java b/src/test/java/com/cronutils/model/time/generator/FieldValueGeneratorTest.java
index 69ba763..ad583fd 100644
--- a/src/test/java/com/cronutils/model/time/generator/FieldValueGeneratorTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/FieldValueGeneratorTest.java
@@ -4,15 +4,12 @@ import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.model.field.expression.FieldExpression;
-
 import org.junit.Before;
 import org.junit.Test;
 
 import java.util.List;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 import static org.mockito.Mockito.mock;
 /*
  * Copyright 2015 jmrozanec
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLTest.java b/src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLTest.java
similarity index 93%
rename from src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLTest.java
rename to src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLTest.java
index ecedbb9..888151c 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
@@ -13,8 +10,7 @@ import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Before;
 import org.junit.Test;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.LocalDate;
+import java.time.LocalDate;
 import java.util.List;
 
 import static org.junit.Assert.*;
@@ -30,7 +26,6 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class OnDayOfMonthValueGeneratorLTest {
     private OnDayOfMonthValueGenerator fieldValueGenerator;
     private int year = 2015;
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLWTest.java b/src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLWTest.java
similarity index 97%
rename from src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLWTest.java
rename to src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLWTest.java
index 22d6c50..4056bb9 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLWTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorLWTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
@@ -12,7 +9,6 @@ import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.List;
 
@@ -30,7 +26,6 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class OnDayOfMonthValueGeneratorLWTest {
     private FieldConstraints constraints;
     private OnDayOfMonthValueGenerator fieldValueGenerator;
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorWTest.java b/src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorWTest.java
similarity index 97%
rename from src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorWTest.java
rename to src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorWTest.java
index e019e28..0b69b17 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorWTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/OnDayOfMonthValueGeneratorWTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
@@ -13,7 +10,6 @@ import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.List;
 
@@ -30,7 +26,6 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class OnDayOfMonthValueGeneratorWTest {
     private FieldConstraints constraints;
     private OnDayOfMonthValueGenerator fieldValueGenerator;
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorHashTest.java b/src/test/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorHashTest.java
similarity index 98%
rename from src/androidTest/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorHashTest.java
rename to src/test/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorHashTest.java
index f10201a..85330a1 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorHashTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorHashTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.mapper.ConstantsMapper;
 import com.cronutils.mapper.WeekDay;
 import com.cronutils.model.field.CronField;
@@ -14,7 +11,6 @@ import com.cronutils.model.field.value.IntegerFieldValue;
 import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.List;
 
@@ -31,7 +27,6 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class OnDayOfWeekValueGeneratorHashTest {
     FieldConstraints constraints = FieldConstraintsBuilder.instance().addHashSupport().createConstraintsInstance();
     private OnDayOfWeekValueGenerator fieldValueGenerator;
diff --git a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorLTest.java b/src/test/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorLTest.java
similarity index 98%
rename from src/androidTest/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorLTest.java
rename to src/test/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorLTest.java
index 23c9ba8..92edd99 100644
--- a/src/androidTest/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorLTest.java
+++ b/src/test/java/com/cronutils/model/time/generator/OnDayOfWeekValueGeneratorLTest.java
@@ -1,8 +1,5 @@
 package com.cronutils.model.time.generator;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
 import com.cronutils.mapper.ConstantsMapper;
 import com.cronutils.mapper.WeekDay;
 import com.cronutils.model.field.CronField;
@@ -15,7 +12,6 @@ import com.cronutils.model.field.value.SpecialChar;
 import com.cronutils.model.field.value.SpecialCharFieldValue;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.List;
 
@@ -32,7 +28,6 @@ import static org.junit.Assert.*;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class OnDayOfWeekValueGeneratorLTest {
     private FieldConstraints constraints = FieldConstraintsBuilder.instance().addLSupport().createConstraintsInstance();
     private OnDayOfWeekValueGenerator fieldValueGenerator;
diff --git a/src/androidTest/java/com/cronutils/parser/CronParserCron4JIntegrationTest.java b/src/test/java/com/cronutils/parser/CronParserCron4JIntegrationTest.java
similarity index 91%
rename from src/androidTest/java/com/cronutils/parser/CronParserCron4JIntegrationTest.java
rename to src/test/java/com/cronutils/parser/CronParserCron4JIntegrationTest.java
index 812105d..5f2b3b4 100644
--- a/src/androidTest/java/com/cronutils/parser/CronParserCron4JIntegrationTest.java
+++ b/src/test/java/com/cronutils/parser/CronParserCron4JIntegrationTest.java
@@ -1,15 +1,11 @@
 package com.cronutils.parser;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinition;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
-@RunWith(AndroidJUnit4.class)
 public class CronParserCron4JIntegrationTest {
     private CronParser cron4jParser;
 
diff --git a/src/androidTest/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java b/src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java
similarity index 72%
rename from src/androidTest/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java
rename to src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java
index 67e7dc1..d820d33 100644
--- a/src/androidTest/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java
+++ b/src/test/java/com/cronutils/parser/CronParserQuartzIntegrationTest.java
@@ -1,23 +1,17 @@
 package com.cronutils.parser;
 
-import android.support.test.runner.AndroidJUnit4;
-
-import com.cronutils.BaseAndroidTest;
-import com.cronutils.builder.CronBuilder;
 import com.cronutils.descriptor.CronDescriptor;
 import com.cronutils.model.Cron;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinition;
 import com.cronutils.model.definition.CronDefinitionBuilder;
-import com.cronutils.model.field.expression.FieldExpressionFactory;
 import com.cronutils.model.time.ExecutionTime;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.ZonedDateTime;
+import java.time.ZonedDateTime;
 import java.util.Locale;
 
 import static org.junit.Assert.assertEquals;
@@ -35,8 +29,7 @@ import static org.junit.Assert.assertNotNull;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
-public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
+public class CronParserQuartzIntegrationTest {
     private CronParser parser;
 
     @Rule
@@ -44,7 +37,6 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
         parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
     }
 
@@ -109,7 +101,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #27: month ranges string mapping
      */
     @Test
-    public void testMonthRangeStringMapping() {
+    public void testMonthRangeStringMapping(){
         parser.parse("0 0 0 * JUL-AUG ? *");
         parser.parse("0 0 0 * JAN-FEB ? *");
     }
@@ -118,7 +110,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #27: month string mapping
      */
     @Test
-    public void testSingleMonthStringMapping() {
+    public void testSingleMonthStringMapping(){
         parser.parse("0 0 0 * JAN ? *");
     }
 
@@ -126,7 +118,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #27: day of week string ranges mapping
      */
     @Test
-    public void testDoWRangeStringMapping() {
+    public void testDoWRangeStringMapping(){
         parser.parse("0 0 0 ? * MON-FRI *");
     }
 
@@ -134,7 +126,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #27: day of week string mapping
      */
     @Test
-    public void testSingleDoWStringMapping() {
+    public void testSingleDoWStringMapping(){
         parser.parse("0 0 0 ? * MON *");
     }
 
@@ -142,7 +134,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #27: July month as string is parsed as some special char occurrence
      */
     @Test
-    public void testJulyMonthAsStringConsideredSpecialChar() {
+    public void testJulyMonthAsStringConsideredSpecialChar(){
         assertNotNull(parser.parse("0 0 0 * JUL ? *"));
     }
 
@@ -151,7 +143,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      */
     @Test
     public void testSunToSat() {
-        // FAILS SUN-SAT: SUN = 7 and SAT = 6
+    // FAILS SUN-SAT: SUN = 7 and SAT = 6
         parser.parse("0 0 12 ? * SUN-SAT");
     }
 
@@ -159,7 +151,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #39: reported issue about exception being raised on parse.
      */
     @Test
-    public void testParseExpressionWithQuestionMarkAndWeekdays() {
+    public void testParseExpressionWithQuestionMarkAndWeekdays(){
         parser.parse("0 0 0 ? * MON,TUE *");
     }
 
@@ -167,7 +159,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #39: reported issue about exception being raised on parse.
      */
     @Test
-    public void testDescribeExpressionWithQuestionMarkAndWeekdays() {
+    public void testDescribeExpressionWithQuestionMarkAndWeekdays(){
         Cron quartzCron = parser.parse("0 0 0 ? * MON,TUE *");
         CronDescriptor descriptor = CronDescriptor.instance(Locale.ENGLISH);
         descriptor.describe(quartzCron);
@@ -177,7 +169,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #60: Parser exception when parsing cron:
      */
     @Test
-    public void testDescribeExpression() {
+    public void testDescribeExpression(){
         String expression = "0 * * ? * 1,5";
         CronDefinition definition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
         CronParser parser = new CronParser(definition);
@@ -189,7 +181,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #63: Parser exception when parsing cron:
      */
     @Test(expected = IllegalArgumentException.class)
-    public void testDoMAndDoWParametersInvalidForQuartz() {
+    public void testDoMAndDoWParametersInvalidForQuartz(){
         parser.parse("0 30 17 4 1 * 2016");
     }
 
@@ -200,7 +192,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
     public void testIntervalSeconds() {
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0/20 * * * * ?"));
         ZonedDateTime now = ZonedDateTime.parse("2005-08-09T18:32:42Z");
-        ZonedDateTime lastExecution = executionTime.lastExecution(now).get();
+        ZonedDateTime lastExecution = executionTime.lastExecution(now);
         ZonedDateTime assertDate = ZonedDateTime.parse("2005-08-09T18:32:40Z");
         assertEquals(assertDate, lastExecution);
     }
@@ -212,7 +204,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
     public void testIntervalMinutes() {
         ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 0/7 * * * ?"));
         ZonedDateTime now = ZonedDateTime.parse("2005-08-09T18:32:42Z");
-        ZonedDateTime lastExecution = executionTime.lastExecution(now).get();
+        ZonedDateTime lastExecution = executionTime.lastExecution(now);
         ZonedDateTime assertDate = ZonedDateTime.parse("2005-08-09T18:28:00Z");
         assertEquals(assertDate, lastExecution);
     }
@@ -221,7 +213,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #89: regression - NumberFormatException: For input string: "$"
      */
     @Test
-    public void testRegressionDifferentMessageForException() {
+    public void testRegressionDifferentMessageForException(){
         thrown.expect(IllegalArgumentException.class);
         thrown.expectMessage("Invalid chars in expression! Expression: $ Invalid chars: $");
         assertNotNull(ExecutionTime.forCron(parser.parse("* * * * $ ?")));
@@ -231,7 +223,7 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * Issue #90: Reported error contains other expression than the one provided
      */
     @Test
-    public void testReportedErrorContainsSameExpressionAsProvided() {
+    public void testReportedErrorContainsSameExpressionAsProvided(){
         thrown.expect(IllegalArgumentException.class);
         thrown.expectMessage(
                 "Invalid cron expression: 0 * * * * *. Both, a day-of-week AND a day-of-month parameter, are not supported.");
@@ -243,71 +235,25 @@ public class CronParserQuartzIntegrationTest extends BaseAndroidTest {
      * https://github.com/jmrozanec/cron-utils/issues/109
      */
     @Test
-    public void testMissingExpressionAndInvalidCharsInErrorMessage() {
+    public void testMissingExpressionAndInvalidCharsInErrorMessage(){
         thrown.expect(IllegalArgumentException.class);
         String cronexpression = "* * -1 * * ?";
         thrown.expectMessage(String.format("Failed to parse '%s'. Invalid expression! Expression: -1 does not describe a range. Negative numbers are not allowed.", cronexpression));
         assertNotNull(ExecutionTime.forCron(parser.parse(cronexpression)));
     }
 
-    /**
-     * Issue #148: Cron Builder/Parser fails on Every X years
-     */
-//    @Test //TODO
-    public void testEveryXYears(){
-        CronBuilder.cron(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)).withDoM(FieldExpressionFactory.on(1))
-                .withDoW(FieldExpressionFactory.questionMark())
-                .withYear(FieldExpressionFactory.every(FieldExpressionFactory.between(1970, 2099), 4))
-                .withMonth(FieldExpressionFactory.on(0))
-                .withHour(FieldExpressionFactory.on(0))
-                .withMinute(FieldExpressionFactory.on(0))
-                .withSecond(FieldExpressionFactory.on(0));
-    }
-
-    /**
-     * Issue #151: L-7 in day of month should work to find the day 7 days prior to the last day of the month.
-     */
-//    @Test TODO
-    public void testLSupportedInDoMRangeNextExecutionCalculation() {
-        ExecutionTime executionTime = ExecutionTime.forCron(parser.parse("0 15 10 L-7 * ?"));
-        ZonedDateTime now = ZonedDateTime.parse("2017-01-31T10:00:00Z");
-        ZonedDateTime nextExecution = executionTime.nextExecution(now).get();
-        ZonedDateTime assertDate = ZonedDateTime.parse("2017-02-21T10:15:00Z");
-        assertEquals(assertDate, nextExecution);
-    }
-
-    /**
-     * Issue #154: Quartz Cron Year Pattern is not fully supported - i.e. increments on years are not supported
-     * https://github.com/jmrozanec/cron-utils/issues/154
-     * Duplicate of #148
-     */
-//    @Test TODO
-    public void supportQuartzCronExpressionIncrementsOnYears() {
-        final String[] sampleCronExpressions = {
-                "0 0 0 1 * ? 2017/2",
-                "0 0 0 1 * ? 2017/3",
-                "0 0 0 1 * ? 2017/10",
-                "0 0 0 1 * ? 2017-2047/2",
-        };
-
-        final CronParser quartzCronParser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
-        for (final String cronExpression: sampleCronExpressions) {
-            final Cron quartzCron = quartzCronParser.parse(cronExpression);
-            quartzCron.validate();
-        }
-    }
-
     @Test
-    public void testErrorAbout2Parts() {
+    public void testErrorAbout2Parts(){
         thrown.expect(IllegalArgumentException.class);
         thrown.expectMessage("Cron expression contains 2 parts but we expect one of [6, 7]");
         assertNotNull(ExecutionTime.forCron(parser.parse("* *")));
     }
 
     @Test
-    public void testErrorAboutMissingSteps() {
+    public void testErrorAboutMissingSteps(){
         thrown.expect(IllegalArgumentException.class);
         thrown.expectMessage("Missing steps for expression: */");
         assertNotNull(ExecutionTime.forCron(parser.parse("*/ * * * * ?")));
     }
+
 }
diff --git a/src/test/java/com/cronutils/parser/CronParserTest.java b/src/test/java/com/cronutils/parser/CronParserTest.java
index 238535c..a1f53dc 100644
--- a/src/test/java/com/cronutils/parser/CronParserTest.java
+++ b/src/test/java/com/cronutils/parser/CronParserTest.java
@@ -1,110 +1,140 @@
-package com.cronutils.parser;
-
-import com.cronutils.model.definition.CronDefinition;
-import com.cronutils.model.field.CronFieldName;
-import com.cronutils.model.field.constraint.FieldConstraintsBuilder;
-import com.cronutils.model.field.definition.FieldDefinition;
-import com.google.common.collect.Sets;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.Set;
-/*
- * Copyright 2015 jmrozanec
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-public class CronParserTest {
-
-    @Rule
-    public ExpectedException expectedException = ExpectedException.none();
-
-    @Mock
-    private CronDefinition definition;
-
-    private CronParser parser;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testParseEmptyExpression() throws Exception {
-        Set<FieldDefinition> set = Sets.newHashSet();
-        Mockito.when(definition.getFieldDefinitions()).thenReturn(set);
-        parser = new CronParser(definition);
-
-        parser.parse("");
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testParseNoMatchingExpression() throws Exception {
-        Set<FieldDefinition> set = Sets.newHashSet();
-        set.add(new FieldDefinition(CronFieldName.SECOND, FieldConstraintsBuilder.instance().createConstraintsInstance()));
-        Mockito.when(definition.getFieldDefinitions()).thenReturn(set);
-        parser = new CronParser(definition);
-
-        parser.parse("* *");
-    }
-
-    @Test
-    public void testParseIncompleteEvery() throws Exception {
-        Set<FieldDefinition> set = Sets.newHashSet();
-        set.add(new FieldDefinition(CronFieldName.SECOND, FieldConstraintsBuilder.instance().createConstraintsInstance()));
-        Mockito.when(definition.getFieldDefinitions()).thenReturn(set);
-        parser = new CronParser(definition);
-
-        expectedException.expect(IllegalArgumentException.class);
-        expectedException.expectMessage("Missing steps for expression: */");
-
-        Assert.assertNotNull(parser.parse("*/"));
-    }
-
-
-    /**
-     * Corresponds to issue#11
-     * https://github.com/jmrozanec/cron-utils/issues/11
-     * Reported case:
-     * when parsing: "* *[triple space here]* * ?"
-     * we receive: NumberFormatException with message For input string: ""
-     * Expected: ignore multiple spaces, and parse the expression.
-     */
-    @Test
-    public void testMultipleSpacesDoNotHurtParsingExpression() throws Exception {
-        FieldDefinition minute = new FieldDefinition(CronFieldName.MINUTE, FieldConstraintsBuilder.instance().createConstraintsInstance());
-        FieldDefinition hour = new FieldDefinition(CronFieldName.HOUR, FieldConstraintsBuilder.instance().createConstraintsInstance());
-        FieldDefinition dom = new FieldDefinition(CronFieldName.DAY_OF_MONTH, FieldConstraintsBuilder.instance().createConstraintsInstance());
-        FieldDefinition month = new FieldDefinition(CronFieldName.MONTH, FieldConstraintsBuilder.instance().createConstraintsInstance());
-        FieldDefinition dow = new FieldDefinition(CronFieldName.DAY_OF_WEEK, FieldConstraintsBuilder.instance().createConstraintsInstance());
-        Set<FieldDefinition> set = Sets.newHashSet();
-        set.add(minute);
-        set.add(hour);
-        set.add(dom);
-        set.add(month);
-        set.add(dow);
-        Mockito.when(definition.getFieldDefinitions()).thenReturn(set);
-        Mockito.when(definition.getFieldDefinition(CronFieldName.MINUTE)).thenReturn(minute);
-        Mockito.when(definition.getFieldDefinition(CronFieldName.HOUR)).thenReturn(hour);
-        Mockito.when(definition.getFieldDefinition(CronFieldName.DAY_OF_MONTH)).thenReturn(dom);
-        Mockito.when(definition.getFieldDefinition(CronFieldName.MONTH)).thenReturn(month);
-        Mockito.when(definition.getFieldDefinition(CronFieldName.DAY_OF_WEEK)).thenReturn(dow);
-        parser = new CronParser(definition);
-
-        parser.parse("* *   * * *");
-    }
+package com.cronutils.parser;
+
+import com.cronutils.model.CronType;
+import com.cronutils.model.definition.CronDefinition;
+import com.cronutils.model.definition.CronDefinitionBuilder;
+import com.cronutils.model.field.CronFieldName;
+import com.cronutils.model.field.constraint.FieldConstraintsBuilder;
+import com.cronutils.model.field.definition.FieldDefinition;
+import com.google.common.collect.Sets;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Set;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.when;
+/*
+ * Copyright 2015 jmrozanec
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+public class CronParserTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Mock
+    private CronDefinition definition;
+
+    private CronParser parser;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseEmptyExpression() throws Exception {
+        Set<FieldDefinition> set = Sets.newHashSet();
+        when(definition.getFieldDefinitions()).thenReturn(set);
+        parser = new CronParser(definition);
+
+        parser.parse("");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseNoMatchingExpression() throws Exception {
+        Set<FieldDefinition> set = Sets.newHashSet();
+        set.add(new FieldDefinition(CronFieldName.SECOND, FieldConstraintsBuilder.instance().createConstraintsInstance()));
+        when(definition.getFieldDefinitions()).thenReturn(set);
+        parser = new CronParser(definition);
+
+        parser.parse("* *");
+    }
+
+    @Test
+    public void testParseIncompleteEvery() throws Exception {
+        Set<FieldDefinition> set = Sets.newHashSet();
+        set.add(new FieldDefinition(CronFieldName.SECOND, FieldConstraintsBuilder.instance().createConstraintsInstance()));
+        when(definition.getFieldDefinitions()).thenReturn(set);
+        parser = new CronParser(definition);
+
+        expectedException.expect(IllegalArgumentException.class);
+        expectedException.expectMessage("Missing steps for expression: */");
+
+        assertNotNull(parser.parse("*/"));
+    }
+
+
+    /**
+     * Corresponds to issue#11
+     * https://github.com/jmrozanec/cron-utils/issues/11
+     * Reported case:
+     * when parsing: "* *[triple space here]* * ?"
+     * we receive: NumberFormatException with message For input string: ""
+     * Expected: ignore multiple spaces, and parse the expression.
+     */
+    @Test
+    public void testMultipleSpacesDoNotHurtParsingExpression() throws Exception {
+        FieldDefinition minute = new FieldDefinition(CronFieldName.MINUTE, FieldConstraintsBuilder.instance().createConstraintsInstance());
+        FieldDefinition hour = new FieldDefinition(CronFieldName.HOUR, FieldConstraintsBuilder.instance().createConstraintsInstance());
+        FieldDefinition dom = new FieldDefinition(CronFieldName.DAY_OF_MONTH, FieldConstraintsBuilder.instance().createConstraintsInstance());
+        FieldDefinition month = new FieldDefinition(CronFieldName.MONTH, FieldConstraintsBuilder.instance().createConstraintsInstance());
+        FieldDefinition dow = new FieldDefinition(CronFieldName.DAY_OF_WEEK, FieldConstraintsBuilder.instance().createConstraintsInstance());
+        Set<FieldDefinition> set = Sets.newHashSet();
+        set.add(minute);
+        set.add(hour);
+        set.add(dom);
+        set.add(month);
+        set.add(dow);
+        when(definition.getFieldDefinitions()).thenReturn(set);
+        when(definition.getFieldDefinition(CronFieldName.MINUTE)).thenReturn(minute);
+        when(definition.getFieldDefinition(CronFieldName.HOUR)).thenReturn(hour);
+        when(definition.getFieldDefinition(CronFieldName.DAY_OF_MONTH)).thenReturn(dom);
+        when(definition.getFieldDefinition(CronFieldName.MONTH)).thenReturn(month);
+        when(definition.getFieldDefinition(CronFieldName.DAY_OF_WEEK)).thenReturn(dow);
+        parser = new CronParser(definition);
+
+        parser.parse("* *   * * *");
+    }
+    
+    /**
+     * Corresponds to issue#148
+     * https://github.com/jmrozanec/cron-utils/issues/148
+     */
+    @Test
+    public void testParseEveryXyears() {
+        CronDefinition quartzDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
+        parser = new CronParser(quartzDefinition);
+        
+        parser.parse("0/59 0/59 0/23 1/30 1/11 ? 2017/3");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testRejectionOfZeroPeriod() {
+        CronDefinition quartzDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
+        parser = new CronParser(quartzDefinition);
+        
+        parser.parse("0/0 0 0 1 1 ? 2017/3");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void testRejectionOfPeriodUpperLimitExceedance() {
+        CronDefinition quartzDefinition = CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ);
+        parser = new CronParser(quartzDefinition);
+        
+        parser.parse("0/60 0 0 1 1 ? 2017/3");
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/com/cronutils/parser/CronParserFieldTest.java b/src/test/java/com/cronutils/parser/field/CronParserFieldTest.java
similarity index 71%
rename from src/test/java/com/cronutils/parser/CronParserFieldTest.java
rename to src/test/java/com/cronutils/parser/field/CronParserFieldTest.java
index 804d3e3..a38a7ef 100644
--- a/src/test/java/com/cronutils/parser/CronParserFieldTest.java
+++ b/src/test/java/com/cronutils/parser/field/CronParserFieldTest.java
@@ -1,23 +1,27 @@
-package com.cronutils.parser;
+package com.cronutils.parser.field;
 
 import com.cronutils.model.field.CronField;
 import com.cronutils.model.field.CronFieldName;
 import com.cronutils.model.field.constraint.FieldConstraints;
 import com.cronutils.model.field.expression.FieldExpression;
-
-import org.junit.Assert;
+import com.cronutils.parser.CronParser;
+import com.cronutils.parser.CronParserField;
+import com.cronutils.parser.FieldParser;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Matchers;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.powermock.api.mockito.PowerMockito;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.powermock.modules.junit4.PowerMockRunner;
 
 import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.*;
 /*
  * Copyright 2015 jmrozanec
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -47,30 +51,30 @@ public class CronParserFieldTest {
         MockitoAnnotations.initMocks(this);
         testFieldName = CronFieldName.SECOND;
 
-        Mockito.when(mockParser.parse(Matchers.anyString())).thenReturn(mockParseResponse);
+        when(mockParser.parse(anyString())).thenReturn(mockParseResponse);
         PowerMockito.whenNew(FieldParser.class)
-                .withArguments(Matchers.any(FieldConstraints.class)).thenReturn(mockParser);
+                .withArguments(any(FieldConstraints.class)).thenReturn(mockParser);
 
-        cronParserField = new CronParserField(testFieldName, Mockito.mock(FieldConstraints.class));
+        cronParserField = new CronParserField(testFieldName, mock(FieldConstraints.class));
     }
 
     @Test
     public void testGetField() throws Exception {
-        Assert.assertEquals(testFieldName, cronParserField.getField());
+        assertEquals(testFieldName, cronParserField.getField());
     }
 
     @Test
     public void testParse() throws Exception {
         String cron = UUID.randomUUID().toString();
         CronField result = cronParserField.parse(cron);
-        Assert.assertEquals(mockParseResponse, result.getExpression());
-        Assert.assertEquals(testFieldName, result.getField());
-        Mockito.verify(mockParser).parse(cron);
+        assertEquals(mockParseResponse, result.getExpression());
+        assertEquals(testFieldName, result.getField());
+        verify(mockParser).parse(cron);
     }
 
     @Test(expected = NullPointerException.class)
     public void testConstructorNameNull() throws Exception {
-        new CronParserField(null, Mockito.mock(FieldConstraints.class));
+        new CronParserField(null, mock(FieldConstraints.class));
     }
 
     @Test(expected = NullPointerException.class)
diff --git a/src/androidTest/java/com/cronutils/utils/descriptor/CronDescriptorCron4jIntegrationTest.java b/src/test/java/com/cronutils/utils/descriptor/CronDescriptorCron4jIntegrationTest.java
similarity index 96%
rename from src/androidTest/java/com/cronutils/utils/descriptor/CronDescriptorCron4jIntegrationTest.java
rename to src/test/java/com/cronutils/utils/descriptor/CronDescriptorCron4jIntegrationTest.java
index d114de3..131a67f 100644
--- a/src/androidTest/java/com/cronutils/utils/descriptor/CronDescriptorCron4jIntegrationTest.java
+++ b/src/test/java/com/cronutils/utils/descriptor/CronDescriptorCron4jIntegrationTest.java
@@ -1,14 +1,11 @@
 package com.cronutils.utils.descriptor;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.descriptor.CronDescriptor;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.Locale;
 
@@ -25,7 +22,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class CronDescriptorCron4jIntegrationTest {
         private CronDescriptor descriptor;
         private CronParser parser;
diff --git a/src/androidTest/java/com/cronutils/utils/descriptor/CronDescriptorQuartzIntegrationTest.java b/src/test/java/com/cronutils/utils/descriptor/CronDescriptorQuartzIntegrationTest.java
similarity index 97%
rename from src/androidTest/java/com/cronutils/utils/descriptor/CronDescriptorQuartzIntegrationTest.java
rename to src/test/java/com/cronutils/utils/descriptor/CronDescriptorQuartzIntegrationTest.java
index ee83e4d..15285af 100644
--- a/src/androidTest/java/com/cronutils/utils/descriptor/CronDescriptorQuartzIntegrationTest.java
+++ b/src/test/java/com/cronutils/utils/descriptor/CronDescriptorQuartzIntegrationTest.java
@@ -1,14 +1,11 @@
 package com.cronutils.utils.descriptor;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.descriptor.CronDescriptor;
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.util.Locale;
 
@@ -25,7 +22,6 @@ import static org.junit.Assert.assertEquals;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class CronDescriptorQuartzIntegrationTest {
 
     private CronDescriptor descriptor;
diff --git a/src/androidTest/java/com/cronutils/validator/CronValidatorQuartzIntegrationTest.java b/src/test/java/com/cronutils/validator/CronValidatorQuartzIntegrationTest.java
similarity index 93%
rename from src/androidTest/java/com/cronutils/validator/CronValidatorQuartzIntegrationTest.java
rename to src/test/java/com/cronutils/validator/CronValidatorQuartzIntegrationTest.java
index a50bca1..c899a2a 100644
--- a/src/androidTest/java/com/cronutils/validator/CronValidatorQuartzIntegrationTest.java
+++ b/src/test/java/com/cronutils/validator/CronValidatorQuartzIntegrationTest.java
@@ -1,16 +1,13 @@
 package com.cronutils.validator;
 
-import android.support.test.runner.AndroidJUnit4;
-
 import com.cronutils.model.CronType;
 import com.cronutils.model.definition.CronDefinitionBuilder;
 import com.cronutils.parser.CronParser;
 import org.junit.Before;
 import org.junit.Test;
 
-import org.junit.runner.RunWith;
-import org.threeten.bp.LocalDate;
-import org.threeten.bp.format.DateTimeFormatter;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.Locale;
 
 import static org.junit.Assert.assertNotNull;
@@ -27,7 +24,6 @@ import static org.junit.Assert.assertNotNull;
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@RunWith(AndroidJUnit4.class)
 public class CronValidatorQuartzIntegrationTest {
     private CronParser parser;
     @Before