I'm just wondering if there is a way (maybe with regex) to validate that an input on a Java desktop app is exactly a string formatted as: "YYYY-MM-DD".
Use the following regular expression:
^\d{4}-\d{2}-\d{2}$
as in
if (str.matches("\\d{4}-\\d{2}-\\d{2}")) {
...
}
With the matches method, the anchors ^ and $ (beginning and end of string, respectively) are present implicitly.
The pattern above checks conformance with the general “shape” of a date, but it will accept more invalid than valid dates. You may be surprised to learn that checking for valid dates — including leap years! — is possible using a regular expression, but not advisable. Borrowing from an answer elsewhere by Kuldeep, we can all find amusement and admiration for persistence in
((18|19|20)[0-9]{2}[\-.](0[13578]|1[02])[\-.](0[1-9]|[12][0-9]|3[01]))|(18|19|20)[0-9]{2}[\-.](0[469]|11)[\-.](0[1-9]|[12][0-9]|30)|(18|19|20)[0-9]{2}[\-.](02)[\-.](0[1-9]|1[0-9]|2[0-8])|(((18|19|20)(04|08|[2468][048]|[13579][26]))|2000)[\-.](02)[\-.]29
In a production context, your colleagues will appreciate a more straightforward implementation. Remember, the first rule of optimization is Don’t!
You need more than a regex, for example "9999-99-00" isn't a valid date. There's a SimpleDateFormat class that's built to do this. More heavyweight, but more comprehensive.
e.g.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
boolean isValidDate(string input) {
try {
format.parse(input);
return true;
}
catch(ParseException e){
return false;
}
}
Unfortunately, SimpleDateFormat is both heavyweight and not thread-safe.
Putting it all together:
REGEX doesn't validate values (like "2010-19-19")
SimpleDateFormat does not check format ("2010-1-2", "1-0002-003" are accepted)
it's necessary to use both to validate format and value:
public static boolean isValid(String text) {
if (text == null || !text.matches("\\d{4}-[01]\\d-[0-3]\\d"))
return false;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
try {
df.parse(text);
return true;
} catch (ParseException ex) {
return false;
}
}
A ThreadLocal can be used to avoid the creation of a new SimpleDateFormat for each call.
It is needed in a multithread context since the SimpleDateFormat is not thread safe:
private static final ThreadLocal<SimpleDateFormat> format = new ThreadLocal<SimpleDateFormat>() {
#Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
df.setLenient(false);
System.out.println("created");
return df;
}
};
public static boolean isValid(String text) {
if (text == null || !text.matches("\\d{4}-[01]\\d-[0-3]\\d"))
return false;
try {
format.get().parse(text);
return true;
} catch (ParseException ex) {
return false;
}
}
(same can be done for a Matcher, that also is not thread safe)
This will do it regex: "^((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$"
This will take care of valid formats and valid dates. It will not validate the correct days of the month i.e. leap year.
String regex = "^((19|20)\\d\\d)-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])$";
Assert.assertTrue("Date: matched.", Pattern.matches(regex, "2011-1-1"));
Assert.assertFalse("Date (month): not matched.", Pattern.matches(regex, "2011-13-1"));
Good luck!
I would go with a simple regex which will check that days doesn't have more than 31 days and months no more than 12. Something like:
(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-((18|19|20|21)\\d\\d)
This is the format "dd-MM-yyyy". You can tweak it to your needs (for example take off the ? to make the leading 0 required - now its optional), and then use a custom logic to cut down to the specific rules like leap years February number of days case, and other months number of days cases. See the DateChecker code below.
I am choosing this approach since I tested that this is the best one when performance is taken into account. I checked this (1st) approach versus 2nd approach of validating a date against a regex that takes care of the other use cases, and 3rd approach of using the same simple regex above in combination with SimpleDateFormat.parse(date).
The 1st approach was 4 times faster than the 2nd approach, and 8 times faster than the 3rd approach. See the self contained date checker and performance tester main class at the bottom.
One thing that I left unchecked is the joda time approach(s). (The more efficient date/time library).
Date checker code:
class DateChecker {
private Matcher matcher;
private Pattern pattern;
public DateChecker(String regex) {
pattern = Pattern.compile(regex);
}
/**
* Checks if the date format is a valid.
* Uses the regex pattern to match the date first.
* Than additionally checks are performed on the boundaries of the days taken the month into account (leap years are covered).
*
* #param date the date that needs to be checked.
* #return if the date is of an valid format or not.
*/
public boolean check(final String date) {
matcher = pattern.matcher(date);
if (matcher.matches()) {
matcher.reset();
if (matcher.find()) {
int day = Integer.parseInt(matcher.group(1));
int month = Integer.parseInt(matcher.group(2));
int year = Integer.parseInt(matcher.group(3));
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: return day < 32;
case 4:
case 6:
case 9:
case 11: return day < 31;
case 2:
int modulo100 = year % 100;
//http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm
if ((modulo100 == 0 && year % 400 == 0) || (modulo100 != 0 && year % LEAP_STEP == 0)) {
//its a leap year
return day < 30;
} else {
return day < 29;
}
default:
break;
}
}
}
return false;
}
public String getRegex() {
return pattern.pattern();
}
}
Date checking/testing and performance testing:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Tester {
private static final String[] validDateStrings = new String[]{
"1-1-2000", //leading 0s for day and month optional
"01-1-2000", //leading 0 for month only optional
"1-01-2000", //leading 0 for day only optional
"01-01-1800", //first accepted date
"31-12-2199", //last accepted date
"31-01-2000", //January has 31 days
"31-03-2000", //March has 31 days
"31-05-2000", //May has 31 days
"31-07-2000", //July has 31 days
"31-08-2000", //August has 31 days
"31-10-2000", //October has 31 days
"31-12-2000", //December has 31 days
"30-04-2000", //April has 30 days
"30-06-2000", //June has 30 days
"30-09-2000", //September has 30 days
"30-11-2000", //November has 30 days
};
private static final String[] invalidDateStrings = new String[]{
"00-01-2000", //there is no 0-th day
"01-00-2000", //there is no 0-th month
"31-12-1799", //out of lower boundary date
"01-01-2200", //out of high boundary date
"32-01-2000", //January doesn't have 32 days
"32-03-2000", //March doesn't have 32 days
"32-05-2000", //May doesn't have 32 days
"32-07-2000", //July doesn't have 32 days
"32-08-2000", //August doesn't have 32 days
"32-10-2000", //October doesn't have 32 days
"32-12-2000", //December doesn't have 32 days
"31-04-2000", //April doesn't have 31 days
"31-06-2000", //June doesn't have 31 days
"31-09-2000", //September doesn't have 31 days
"31-11-2000", //November doesn't have 31 days
"001-02-2000", //SimpleDateFormat valid date (day with leading 0s) even with lenient set to false
"1-0002-2000", //SimpleDateFormat valid date (month with leading 0s) even with lenient set to false
"01-02-0003", //SimpleDateFormat valid date (year with leading 0s) even with lenient set to false
"01.01-2000", //. invalid separator between day and month
"01-01.2000", //. invalid separator between month and year
"01/01-2000", /// invalid separator between day and month
"01-01/2000", /// invalid separator between month and year
"01_01-2000", //_ invalid separator between day and month
"01-01_2000", //_ invalid separator between month and year
"01-01-2000-12345", //only whole string should be matched
"01-13-2000", //month bigger than 13
};
/**
* These constants will be used to generate the valid and invalid boundary dates for the leap years. (For no leap year, Feb. 28 valid and Feb. 29 invalid; for a leap year Feb. 29 valid and Feb. 30 invalid)
*/
private static final int LEAP_STEP = 4;
private static final int YEAR_START = 1800;
private static final int YEAR_END = 2199;
/**
* This date regex will find matches for valid dates between 1800 and 2199 in the format of "dd-MM-yyyy".
* The leading 0 is optional.
*/
private static final String DATE_REGEX = "((0?[1-9]|[12][0-9]|3[01])-(0?[13578]|1[02])-(18|19|20|21)[0-9]{2})|((0?[1-9]|[12][0-9]|30)-(0?[469]|11)-(18|19|20|21)[0-9]{2})|((0?[1-9]|1[0-9]|2[0-8])-(0?2)-(18|19|20|21)[0-9]{2})|(29-(0?2)-(((18|19|20|21)(04|08|[2468][048]|[13579][26]))|2000))";
/**
* This date regex is similar to the first one, but with the difference of matching only the whole string. So "01-01-2000-12345" won't pass with a match.
* Keep in mind that String.matches tries to match only the whole string.
*/
private static final String DATE_REGEX_ONLY_WHOLE_STRING = "^" + DATE_REGEX + "$";
/**
* The simple regex (without checking for 31 day months and leap years):
*/
private static final String DATE_REGEX_SIMPLE = "(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-((18|19|20|21)\\d\\d)";
/**
* This date regex is similar to the first one, but with the difference of matching only the whole string. So "01-01-2000-12345" won't pass with a match.
*/
private static final String DATE_REGEX_SIMPLE_ONLY_WHOLE_STRING = "^" + DATE_REGEX_SIMPLE + "$";
private static final SimpleDateFormat SDF = new SimpleDateFormat("dd-MM-yyyy");
static {
SDF.setLenient(false);
}
private static final DateChecker dateValidatorSimple = new DateChecker(DATE_REGEX_SIMPLE);
private static final DateChecker dateValidatorSimpleOnlyWholeString = new DateChecker(DATE_REGEX_SIMPLE_ONLY_WHOLE_STRING);
/**
* #param args
*/
public static void main(String[] args) {
DateTimeStatistics dateTimeStatistics = new DateTimeStatistics();
boolean shouldMatch = true;
for (int i = 0; i < validDateStrings.length; i++) {
String validDate = validDateStrings[i];
matchAssertAndPopulateTimes(
dateTimeStatistics,
shouldMatch, validDate);
}
shouldMatch = false;
for (int i = 0; i < invalidDateStrings.length; i++) {
String invalidDate = invalidDateStrings[i];
matchAssertAndPopulateTimes(dateTimeStatistics,
shouldMatch, invalidDate);
}
for (int year = YEAR_START; year < (YEAR_END + 1); year++) {
FebruaryBoundaryDates februaryBoundaryDates = createValidAndInvalidFebruaryBoundaryDateStringsFromYear(year);
shouldMatch = true;
matchAssertAndPopulateTimes(dateTimeStatistics,
shouldMatch, februaryBoundaryDates.getValidFebruaryBoundaryDateString());
shouldMatch = false;
matchAssertAndPopulateTimes(dateTimeStatistics,
shouldMatch, februaryBoundaryDates.getInvalidFebruaryBoundaryDateString());
}
dateTimeStatistics.calculateAvarageTimesAndPrint();
}
private static void matchAssertAndPopulateTimes(
DateTimeStatistics dateTimeStatistics,
boolean shouldMatch, String date) {
dateTimeStatistics.addDate(date);
matchAndPopulateTimeToMatch(date, DATE_REGEX, shouldMatch, dateTimeStatistics.getTimesTakenWithDateRegex());
matchAndPopulateTimeToMatch(date, DATE_REGEX_ONLY_WHOLE_STRING, shouldMatch, dateTimeStatistics.getTimesTakenWithDateRegexOnlyWholeString());
boolean matchesSimpleDateFormat = matchWithSimpleDateFormatAndPopulateTimeToMatchAndReturnMatches(date, dateTimeStatistics.getTimesTakenWithSimpleDateFormatParse());
matchAndPopulateTimeToMatchAndReturnMatchesAndCheck(
dateTimeStatistics.getTimesTakenWithDateRegexSimple(), shouldMatch,
date, matchesSimpleDateFormat, DATE_REGEX_SIMPLE);
matchAndPopulateTimeToMatchAndReturnMatchesAndCheck(
dateTimeStatistics.getTimesTakenWithDateRegexSimpleOnlyWholeString(), shouldMatch,
date, matchesSimpleDateFormat, DATE_REGEX_SIMPLE_ONLY_WHOLE_STRING);
matchAndPopulateTimeToMatch(date, dateValidatorSimple, shouldMatch, dateTimeStatistics.getTimesTakenWithdateValidatorSimple());
matchAndPopulateTimeToMatch(date, dateValidatorSimpleOnlyWholeString, shouldMatch, dateTimeStatistics.getTimesTakenWithdateValidatorSimpleOnlyWholeString());
}
private static void matchAndPopulateTimeToMatchAndReturnMatchesAndCheck(
List<Long> times,
boolean shouldMatch, String date, boolean matchesSimpleDateFormat, String regex) {
boolean matchesFromRegex = matchAndPopulateTimeToMatchAndReturnMatches(date, regex, times);
assert !((matchesSimpleDateFormat && matchesFromRegex) ^ shouldMatch) : "Parsing with SimpleDateFormat and date:" + date + "\nregex:" + regex + "\nshouldMatch:" + shouldMatch;
}
private static void matchAndPopulateTimeToMatch(String date, String regex, boolean shouldMatch, List<Long> times) {
boolean matches = matchAndPopulateTimeToMatchAndReturnMatches(date, regex, times);
assert !(matches ^ shouldMatch) : "date:" + date + "\nregex:" + regex + "\nshouldMatch:" + shouldMatch;
}
private static void matchAndPopulateTimeToMatch(String date, DateChecker dateValidator, boolean shouldMatch, List<Long> times) {
long timestampStart;
long timestampEnd;
boolean matches;
timestampStart = System.nanoTime();
matches = dateValidator.check(date);
timestampEnd = System.nanoTime();
times.add(timestampEnd - timestampStart);
assert !(matches ^ shouldMatch) : "date:" + date + "\ndateValidator with regex:" + dateValidator.getRegex() + "\nshouldMatch:" + shouldMatch;
}
private static boolean matchAndPopulateTimeToMatchAndReturnMatches(String date, String regex, List<Long> times) {
long timestampStart;
long timestampEnd;
boolean matches;
timestampStart = System.nanoTime();
matches = date.matches(regex);
timestampEnd = System.nanoTime();
times.add(timestampEnd - timestampStart);
return matches;
}
private static boolean matchWithSimpleDateFormatAndPopulateTimeToMatchAndReturnMatches(String date, List<Long> times) {
long timestampStart;
long timestampEnd;
boolean matches = true;
timestampStart = System.nanoTime();
try {
SDF.parse(date);
} catch (ParseException e) {
matches = false;
} finally {
timestampEnd = System.nanoTime();
times.add(timestampEnd - timestampStart);
}
return matches;
}
private static FebruaryBoundaryDates createValidAndInvalidFebruaryBoundaryDateStringsFromYear(int year) {
FebruaryBoundaryDates februaryBoundaryDates;
int modulo100 = year % 100;
//http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm
if ((modulo100 == 0 && year % 400 == 0) || (modulo100 != 0 && year % LEAP_STEP == 0)) {
februaryBoundaryDates = new FebruaryBoundaryDates(
createFebruaryDateFromDayAndYear(29, year),
createFebruaryDateFromDayAndYear(30, year)
);
} else {
februaryBoundaryDates = new FebruaryBoundaryDates(
createFebruaryDateFromDayAndYear(28, year),
createFebruaryDateFromDayAndYear(29, year)
);
}
return februaryBoundaryDates;
}
private static String createFebruaryDateFromDayAndYear(int day, int year) {
return String.format("%d-02-%d", day, year);
}
static class FebruaryBoundaryDates {
private String validFebruaryBoundaryDateString;
String invalidFebruaryBoundaryDateString;
public FebruaryBoundaryDates(String validFebruaryBoundaryDateString,
String invalidFebruaryBoundaryDateString) {
super();
this.validFebruaryBoundaryDateString = validFebruaryBoundaryDateString;
this.invalidFebruaryBoundaryDateString = invalidFebruaryBoundaryDateString;
}
public String getValidFebruaryBoundaryDateString() {
return validFebruaryBoundaryDateString;
}
public void setValidFebruaryBoundaryDateString(
String validFebruaryBoundaryDateString) {
this.validFebruaryBoundaryDateString = validFebruaryBoundaryDateString;
}
public String getInvalidFebruaryBoundaryDateString() {
return invalidFebruaryBoundaryDateString;
}
public void setInvalidFebruaryBoundaryDateString(
String invalidFebruaryBoundaryDateString) {
this.invalidFebruaryBoundaryDateString = invalidFebruaryBoundaryDateString;
}
}
static class DateTimeStatistics {
private List<String> dates = new ArrayList<String>();
private List<Long> timesTakenWithDateRegex = new ArrayList<Long>();
private List<Long> timesTakenWithDateRegexOnlyWholeString = new ArrayList<Long>();
private List<Long> timesTakenWithDateRegexSimple = new ArrayList<Long>();
private List<Long> timesTakenWithDateRegexSimpleOnlyWholeString = new ArrayList<Long>();
private List<Long> timesTakenWithSimpleDateFormatParse = new ArrayList<Long>();
private List<Long> timesTakenWithdateValidatorSimple = new ArrayList<Long>();
private List<Long> timesTakenWithdateValidatorSimpleOnlyWholeString = new ArrayList<Long>();
public List<String> getDates() {
return dates;
}
public List<Long> getTimesTakenWithDateRegex() {
return timesTakenWithDateRegex;
}
public List<Long> getTimesTakenWithDateRegexOnlyWholeString() {
return timesTakenWithDateRegexOnlyWholeString;
}
public List<Long> getTimesTakenWithDateRegexSimple() {
return timesTakenWithDateRegexSimple;
}
public List<Long> getTimesTakenWithDateRegexSimpleOnlyWholeString() {
return timesTakenWithDateRegexSimpleOnlyWholeString;
}
public List<Long> getTimesTakenWithSimpleDateFormatParse() {
return timesTakenWithSimpleDateFormatParse;
}
public List<Long> getTimesTakenWithdateValidatorSimple() {
return timesTakenWithdateValidatorSimple;
}
public List<Long> getTimesTakenWithdateValidatorSimpleOnlyWholeString() {
return timesTakenWithdateValidatorSimpleOnlyWholeString;
}
public void addDate(String date) {
dates.add(date);
}
public void addTimesTakenWithDateRegex(long time) {
timesTakenWithDateRegex.add(time);
}
public void addTimesTakenWithDateRegexOnlyWholeString(long time) {
timesTakenWithDateRegexOnlyWholeString.add(time);
}
public void addTimesTakenWithDateRegexSimple(long time) {
timesTakenWithDateRegexSimple.add(time);
}
public void addTimesTakenWithDateRegexSimpleOnlyWholeString(long time) {
timesTakenWithDateRegexSimpleOnlyWholeString.add(time);
}
public void addTimesTakenWithSimpleDateFormatParse(long time) {
timesTakenWithSimpleDateFormatParse.add(time);
}
public void addTimesTakenWithdateValidatorSimple(long time) {
timesTakenWithdateValidatorSimple.add(time);
}
public void addTimesTakenWithdateValidatorSimpleOnlyWholeString(long time) {
timesTakenWithdateValidatorSimpleOnlyWholeString.add(time);
}
private void calculateAvarageTimesAndPrint() {
long[] sumOfTimes = new long[7];
int timesSize = timesTakenWithDateRegex.size();
for (int i = 0; i < timesSize; i++) {
sumOfTimes[0] += timesTakenWithDateRegex.get(i);
sumOfTimes[1] += timesTakenWithDateRegexOnlyWholeString.get(i);
sumOfTimes[2] += timesTakenWithDateRegexSimple.get(i);
sumOfTimes[3] += timesTakenWithDateRegexSimpleOnlyWholeString.get(i);
sumOfTimes[4] += timesTakenWithSimpleDateFormatParse.get(i);
sumOfTimes[5] += timesTakenWithdateValidatorSimple.get(i);
sumOfTimes[6] += timesTakenWithdateValidatorSimpleOnlyWholeString.get(i);
}
System.out.println("AVG from timesTakenWithDateRegex (in nanoseconds):" + (double) sumOfTimes[0] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexOnlyWholeString (in nanoseconds):" + (double) sumOfTimes[1] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimple (in nanoseconds):" + (double) sumOfTimes[2] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimpleOnlyWholeString (in nanoseconds):" + (double) sumOfTimes[3] / timesSize);
System.out.println("AVG from timesTakenWithSimpleDateFormatParse (in nanoseconds):" + (double) sumOfTimes[4] / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimple + timesTakenWithSimpleDateFormatParse (in nanoseconds):" + (double) (sumOfTimes[2] + sumOfTimes[4]) / timesSize);
System.out.println("AVG from timesTakenWithDateRegexSimpleOnlyWholeString + timesTakenWithSimpleDateFormatParse (in nanoseconds):" + (double) (sumOfTimes[3] + sumOfTimes[4]) / timesSize);
System.out.println("AVG from timesTakenWithdateValidatorSimple (in nanoseconds):" + (double) sumOfTimes[5] / timesSize);
System.out.println("AVG from timesTakenWithdateValidatorSimpleOnlyWholeString (in nanoseconds):" + (double) sumOfTimes[6] / timesSize);
}
}
static class DateChecker {
private Matcher matcher;
private Pattern pattern;
public DateChecker(String regex) {
pattern = Pattern.compile(regex);
}
/**
* Checks if the date format is a valid.
* Uses the regex pattern to match the date first.
* Than additionally checks are performed on the boundaries of the days taken the month into account (leap years are covered).
*
* #param date the date that needs to be checked.
* #return if the date is of an valid format or not.
*/
public boolean check(final String date) {
matcher = pattern.matcher(date);
if (matcher.matches()) {
matcher.reset();
if (matcher.find()) {
int day = Integer.parseInt(matcher.group(1));
int month = Integer.parseInt(matcher.group(2));
int year = Integer.parseInt(matcher.group(3));
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12: return day < 32;
case 4:
case 6:
case 9:
case 11: return day < 31;
case 2:
int modulo100 = year % 100;
//http://science.howstuffworks.com/science-vs-myth/everyday-myths/question50.htm
if ((modulo100 == 0 && year % 400 == 0) || (modulo100 != 0 && year % LEAP_STEP == 0)) {
//its a leap year
return day < 30;
} else {
return day < 29;
}
default:
break;
}
}
}
return false;
}
public String getRegex() {
return pattern.pattern();
}
}
}
Some useful notes:
- to enable the assertions (assert checks) you need to use -ea argument when running the tester. (In eclipse this is done by editing the Run/Debug configuration -> Arguments tab -> VM Arguments -> insert "-ea"
- the regex above is bounded to years 1800 to 2199
- you don't need to use ^ at the beginning and $ at the end to match only the whole date string. The String.matches takes care of that.
- make sure u check the valid and invalid cases and change them according the rules that you have.
- the "only whole string" version of each regex gives the same speed as the "normal" version (the one without ^ and $). If you see performance differences this is because java "gets used" to processing the same instructions so the time lowers. If you switch the lines where the "normal" and the "only whole string" version execute, you will see this proven.
Hope this helps someone!
Cheers,
Despot
java.time
The proper (and easy) way to do date/time validation using Java 8+ is to use the java.time.format.DateTimeFormatter class. Using a regex for validation isn't really ideal for dates. For the example case in this question:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try {
LocalDate date = formatter.parse(text, LocalDate::from);
} catch (DateTimeParseException e) {
// Thrown if text could not be parsed in the specified format
}
This code will parse the text, validate that it is a valid date, and also return the date as a LocalDate object. Note that the DateTimeFormatter class has a number of static predefined date formats matching ISO standards if your use case matches any of them.
The following regex will accept YYYY-MM-DD (within the range 1600-2999 year) formatted dates taking into consideration leap years:
^((?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:(?:0[13578]|1[02])(-)31)|((0[1,3-9]|1[0-2])(-)(29|30))))$|^(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(-)02(-)29)$|^(?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:0[1-9])|(?:1[0-2]))(-)(?:0[1-9]|1\d|2[0-8])$
Examples:
You can test it here.
Note: if you want to accept one digit as month or day you can use:
^((?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:(?:0?[13578]|1[02])(-)31)|((0?[1,3-9]|1[0-2])(-)(29|30))))$|^(?:(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(-)0?2(-)29)$|^(?:(?:1[6-9]|2[0-9])\d{2})(-)(?:(?:0?[1-9])|(?:1[0-2]))(-)(?:0?[1-9]|1\d|2[0-8])$
I have created the above regex starting from this solution
The pattern yyyy-MM-dd is the default pattern used by LocalDate#parse. Therefore, all you need to do is to pass your date string to this method and check if it is successfully parsed or some exception has occurred.
Demo:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
String[] arr = { "2022-11-29", "0000-00-00", "2022-1-2", "2022-02-29" };
for (String s : arr) {
try {
System.out.println("================================");
System.out.println(LocalDate.parse(s) + " is a valid date ");
} catch (DateTimeParseException e) {
System.out.println(e.getMessage());
// Recommended; so that the caller can handle it appropriately
// throw new IllegalArgumentException("Invalid date");
}
}
}
}
Output:
================================
2022-11-29 is a valid date
================================
Text '0000-00-00' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 0
================================
Text '2022-1-2' could not be parsed at index 5
================================
Text '2022-02-29' could not be parsed: Invalid date 'February 29' as '2022' is not a leap year
Some important notes:
java.time types follow ISO 8601 standards and therefore you do need to specify a DateTimeFormatter to parse a date-time string which is in ISO 8601 format.
The java.time API, released with Java-8 in March 2014, supplanted the error-prone legacy date-time API. Since then, it has been strongly recommended to use this modern date-time API. Learn more about the modern Date-Time API from Trail: Date Time.
Construct a SimpleDateFormat with the mask, and then call:
SimpleDateFormat.parse(String s, ParsePosition p)
For fine control, consider an InputVerifier using the SimpleDateFormat("YYYY-MM-dd") suggested by Steve B.
Below added code is working for me if you are using pattern
dd-MM-yyyy.
public boolean isValidDate(String date) {
boolean check;
String date1 = "^(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-([12][0-9]{3})$";
check = date.matches(date1);
return check;
}
If you want a simple regex then it won't be accurate.
https://www.freeformatter.com/java-regex-tester.html#ad-output offers a tool to test your Java regex. Also, at the bottom you can find some suggested regexes for validating a date.
ISO date format (yyyy-mm-dd):
^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$
ISO date format (yyyy-mm-dd) with separators '-' or '/' or '.' or ' '. Forces usage of same separator accross date.
^[0-9]{4}([- /.])(((0[13578]|(10|12))\1(0[1-9]|[1-2][0-9]|3[0-1]))|(02\1(0[1-9]|[1-2][0-9]))|((0[469]|11)\1(0[1-9]|[1-2][0-9]|30)))$
United States date format (mm/dd/yyyy)
^(((0[13578]|(10|12))/(0[1-9]|[1-2][0-9]|3[0-1]))|(02/(0[1-9]|[1-2][0-9]))|((0[469]|11)/(0[1-9]|[1-2][0-9]|30)))/[0-9]{4}$
Hours and minutes, 24 hours format (HH:MM):
^(20|21|22|23|[01]\d|\d)((:[0-5]\d){1,2})$
Good luck
Related
import java.util.Arrays;
public class PalindromeDates {
static final int STARTINGYEAR = 0000;
static final int ENDINGYEAR = 9999;
public static void main(String[] args) {
int year, month, date;
int dateArray[];
boolean flag;
System.out.println(" Date --> Array Format\n");
for (year = STARTINGYEAR; year <= ENDINGYEAR; year++) {
for (month = 01; month <= 12; month++) {
for (date = 1; date <= 31; date++) {
if (checkValidDate(year, date, month)) {
dateArray = createDateArray(date, month, year);
flag = checkPalindrome(dateArray);
if (flag) {
System.out.print(year + "." + month + "." + date + " --> ");
System.out.println(Arrays.toString(dateArray));
}
}
}
}
}
}
public static int[] createDateArray(int date, int month, int year) { //Inserting the whole date to an array
int dateArray[] = new int[8];
dateArray[0] = year / 1000;
year = year % 1000;
dateArray[1] = year / 100;
year = year % 100;
dateArray[2] = year / 10;
dateArray[3] = year % 10;
dateArray[4] = month / 10;
dateArray[5] = month % 10;
dateArray[6] = date / 10;
dateArray[7] = date % 10;
return dateArray;
}
public static boolean checkPalindrome(int dateArray[]) {
for (int i = 0; i <= 3; i++) {
if (dateArray[i] == dateArray[7 - i]) {
} else {
return false;
}
}
return true;
}
public static boolean checkValidDate(int year, int month, int date) {
if (month == 2 && date == 30)
return false;
if ((month == 2 || month == 4 || month == 6 || month == 9 || month == 11) && (date == 31)) {
return false;
}
if ((month == 2) && (date == 29))
return (checkLeapYear(year));
return true;
}
public static boolean checkLeapYear(int year) {
if (year % 4 == 0) {
if (year % 100 == 0) {
if (year % 400 == 0)
return true;
else
return false;
} else
return true;
} else {
return false;
}
}
}
This program is written by me to find the palindrome dates since 0000 to 9999. Is their any simplifies program to do this?. What are the modifications for this code? And I want to know whether my leap year finding code is correct.
There is a method called createDateArray(). It is used to put the integer digits in year, month, date to an array. Is there any simple method to do that?
I am inferring from your code that a palindrome date is a date that formatted into yyyyMMdd format is a palindrome string. For example the day before yesterday, February 2, 2020, was a palindrome date because it’s formatted into 20200202, a palindrome.
Is their any simplifies program to do this? …
Yes there is. See below.
… And I want to know whether my leap year finding code is correct.
Yes, it is correct. I have tested its result against the result of Year.of(y).isLeap() for y ranging from 0 through 9999.
And the issue you didn’t ask about: as jrook hinted in a comment, beware of octal numbers.
static final int STARTINGYEAR = 0000;
While this works in this case, it works for reasons that I am afraid that you don’t fully understand. You will get surprises if some day you try 0500 for year 500 and get 320, or you use 0008 for year 8 and get a compile time error. When a Java integer literal begins with 0 (and has more digits following it), it is an octal number, not a number in the decimal number system. So in your code you should use 0 for the year that you want printed as 0000:
static final int STARTINGYEAR = 0;
java.time
On one side Andreas is correct in the other answer that this goes a lot more smoothly when using the date classes that are built into Java. On the other side the Calendar class used in that answer is poorly designed and long outdated. So I recommend we don’t use it and instead present a solution using java.time, the modern Java date and time API.
List<LocalDate> palindromeDates = Arrays.stream(Month.values())
.flatMap(m -> IntStream.rangeClosed(1, m.length(true)).mapToObj(d -> MonthDay.of(m, d)))
.map(md -> md.atYear(reverseStringToInt(md.format(monthDayFormatter))))
.sorted()
.collect(Collectors.toList());
palindromeDates.forEach(ld -> System.out.println(ld.format(dateFormatter)));
This code uses a few auxiliaries:
private static DateTimeFormatter monthDayFormatter = DateTimeFormatter.ofPattern("MMdd");
private static DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuuMMdd");
private static int reverseStringToInt(String s) {
StringBuilder buf = new StringBuilder(s);
buf.reverse();
return Integer.parseInt(buf.toString());
}
Excerpt from the output:
01011010
01100110
01111110
01200210
…
20111102
20200202
20211202
…
92800829
92900929
The algorithm idea is stolen from Andreas’ answer since it is so well thought.
Link
Oracle tutorial: Date Time explaining how to use java.time.
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuuMMdd");
for (LocalDate d = LocalDate.of(0, 1, 1); d.isBefore(LocalDate.of(10000, 1, 1)); d = d.plusDays(1)) {
String dateString = dateFormatter.format(d);
if (dateString.equals(new StringBuilder(dateString).reverse().toString())) {
System.out.println(d);
}
}
Since the year can be any 4-digit year, there is no constraint there, so just go through all 3661 MMdd values of a year, reverse it and use as the year.
1) Since the leap date of 0229 reversed is 9220, it is a leap year, and hence a valid palindrome date.
As code, using Calendar, in year order:
List<String> palimdromeDates = new ArrayList<>();
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"/*No DST*/));
cal.clear();
cal.set(2000/*Leap Year*/, Calendar.JANUARY, 1);
for (; cal.get(Calendar.YEAR) == 2000; cal.add(Calendar.DAY_OF_YEAR, 1)) {
int day = cal.get(Calendar.DAY_OF_MONTH);
int month = cal.get(Calendar.MONTH) + 1;
int year = 0; // Calculate: year = reverse(MMdd)
for (int i = 0, n = month * 100 + day; i < 4; i++, n /= 10)
year = year * 10 + n % 10;
palimdromeDates.add(String.format("%04d-%02d-%02d", year, month, day));
}
Collections.sort(palimdromeDates); // Sort by year
for (String date : palimdromeDates)
System.out.println(date);
Note that this code only loops 366 times, and does not create any unnecessary String objects or other type of objects, so it is very fast, and generates minimum garbage.
Output
0101-10-10
0110-01-10
0111-11-10
0120-02-10
0121-12-10
0130-03-10
0140-04-10
0150-05-10
0160-06-10
0170-07-10
0180-08-10
0190-09-10
0201-10-20
0210-01-20
0211-11-20
0220-02-20
0221-12-20
0230-03-20
0240-04-20
0250-05-20
0260-06-20
0270-07-20
0280-08-20
0290-09-20
0301-10-30
0310-01-30
0311-11-30
0321-12-30
0330-03-30
0340-04-30
0350-05-30
0360-06-30
0370-07-30
0380-08-30
0390-09-30
1001-10-01
1010-01-01
1011-11-01
1020-02-01
1021-12-01
1030-03-01
1040-04-01
1050-05-01
1060-06-01
1070-07-01
1080-08-01
1090-09-01
1101-10-11
1110-01-11
1111-11-11
1120-02-11
1121-12-11
1130-03-11
1140-04-11
1150-05-11
1160-06-11
1170-07-11
1180-08-11
1190-09-11
1201-10-21
1210-01-21
1211-11-21
1220-02-21
1221-12-21
1230-03-21
1240-04-21
1250-05-21
1260-06-21
1270-07-21
1280-08-21
1290-09-21
1301-10-31
1310-01-31
1321-12-31
1330-03-31
1350-05-31
1370-07-31
1380-08-31
2001-10-02
2010-01-02
2011-11-02
2020-02-02
2021-12-02
2030-03-02
2040-04-02
2050-05-02
2060-06-02
2070-07-02
2080-08-02
2090-09-02
2101-10-12
2110-01-12
2111-11-12
2120-02-12
2121-12-12
2130-03-12
2140-04-12
2150-05-12
2160-06-12
2170-07-12
2180-08-12
2190-09-12
2201-10-22
2210-01-22
2211-11-22
2220-02-22
2221-12-22
2230-03-22
2240-04-22
2250-05-22
2260-06-22
2270-07-22
2280-08-22
2290-09-22
3001-10-03
3010-01-03
3011-11-03
3020-02-03
3021-12-03
3030-03-03
3040-04-03
3050-05-03
3060-06-03
3070-07-03
3080-08-03
3090-09-03
3101-10-13
3110-01-13
3111-11-13
3120-02-13
3121-12-13
3130-03-13
3140-04-13
3150-05-13
3160-06-13
3170-07-13
3180-08-13
3190-09-13
3201-10-23
3210-01-23
3211-11-23
3220-02-23
3221-12-23
3230-03-23
3240-04-23
3250-05-23
3260-06-23
3270-07-23
3280-08-23
3290-09-23
4001-10-04
4010-01-04
4011-11-04
4020-02-04
4021-12-04
4030-03-04
4040-04-04
4050-05-04
4060-06-04
4070-07-04
4080-08-04
4090-09-04
4101-10-14
4110-01-14
4111-11-14
4120-02-14
4121-12-14
4130-03-14
4140-04-14
4150-05-14
4160-06-14
4170-07-14
4180-08-14
4190-09-14
4201-10-24
4210-01-24
4211-11-24
4220-02-24
4221-12-24
4230-03-24
4240-04-24
4250-05-24
4260-06-24
4270-07-24
4280-08-24
4290-09-24
5001-10-05
5010-01-05
5011-11-05
5020-02-05
5021-12-05
5030-03-05
5040-04-05
5050-05-05
5060-06-05
5070-07-05
5080-08-05
5090-09-05
5101-10-15
5110-01-15
5111-11-15
5120-02-15
5121-12-15
5130-03-15
5140-04-15
5150-05-15
5160-06-15
5170-07-15
5180-08-15
5190-09-15
5201-10-25
5210-01-25
5211-11-25
5220-02-25
5221-12-25
5230-03-25
5240-04-25
5250-05-25
5260-06-25
5270-07-25
5280-08-25
5290-09-25
6001-10-06
6010-01-06
6011-11-06
6020-02-06
6021-12-06
6030-03-06
6040-04-06
6050-05-06
6060-06-06
6070-07-06
6080-08-06
6090-09-06
6101-10-16
6110-01-16
6111-11-16
6120-02-16
6121-12-16
6130-03-16
6140-04-16
6150-05-16
6160-06-16
6170-07-16
6180-08-16
6190-09-16
6201-10-26
6210-01-26
6211-11-26
6220-02-26
6221-12-26
6230-03-26
6240-04-26
6250-05-26
6260-06-26
6270-07-26
6280-08-26
6290-09-26
7001-10-07
7010-01-07
7011-11-07
7020-02-07
7021-12-07
7030-03-07
7040-04-07
7050-05-07
7060-06-07
7070-07-07
7080-08-07
7090-09-07
7101-10-17
7110-01-17
7111-11-17
7120-02-17
7121-12-17
7130-03-17
7140-04-17
7150-05-17
7160-06-17
7170-07-17
7180-08-17
7190-09-17
7201-10-27
7210-01-27
7211-11-27
7220-02-27
7221-12-27
7230-03-27
7240-04-27
7250-05-27
7260-06-27
7270-07-27
7280-08-27
7290-09-27
8001-10-08
8010-01-08
8011-11-08
8020-02-08
8021-12-08
8030-03-08
8040-04-08
8050-05-08
8060-06-08
8070-07-08
8080-08-08
8090-09-08
8101-10-18
8110-01-18
8111-11-18
8120-02-18
8121-12-18
8130-03-18
8140-04-18
8150-05-18
8160-06-18
8170-07-18
8180-08-18
8190-09-18
8201-10-28
8210-01-28
8211-11-28
8220-02-28
8221-12-28
8230-03-28
8240-04-28
8250-05-28
8260-06-28
8270-07-28
8280-08-28
8290-09-28
9001-10-09
9010-01-09
9011-11-09
9020-02-09
9021-12-09
9030-03-09
9040-04-09
9050-05-09
9060-06-09
9070-07-09
9080-08-09
9090-09-09
9101-10-19
9110-01-19
9111-11-19
9120-02-19
9121-12-19
9130-03-19
9140-04-19
9150-05-19
9160-06-19
9170-07-19
9180-08-19
9190-09-19
9201-10-29
9210-01-29
9211-11-29
9220-02-29
9221-12-29
9230-03-29
9240-04-29
9250-05-29
9260-06-29
9270-07-29
9280-08-29
9290-09-29
I want the sort starting on Sunday at 00:00. My problem is that the zero of this code starts on Thursday at 8:00. I sort by getting the minutes, but zero starts at Thu 8:00.
This is my code so far.
String[] lines = S.split("\n");
System.out.println(Arrays.toString(lines));
int longest = 0;
try {
for (int i = 0; i < lines.length - 1; i++) {
SimpleDateFormat formatter = new SimpleDateFormat("EEE HH:mm-HH:mm", Locale.US);
long diffMinutes;
diffMinutes = TimeUnit.MILLISECONDS.toMinutes(
formatter.parse(lines[i + 1]).getTime() -
formatter.parse(lines[i]).getTime());
if (longest < diffMinutes) {
longest = (int) diffMinutes;
}
}
} catch (ParseException e) {
e.printStackTrace();
}
return longest;
The function takes a String like this
"Mon 01:00-23:00\\nTue 01:00-23:00\\nWed 01:00-23:00\\nThu 01:00-23:00\\nFri 01:00-23:00\\nSat 01:00-23:00\\nSun 01:00-21:00"
The program slices the string and stores it in array lines, then I'm trying to sort it.
I think this problem may be solved by applying some more splitting, due to your String representation of the period being of the form from-to instead of an absolute value like 1320 (minutes). I would use java.time, especially LocalTime and Duration for proper calculating and comparing.
My code basically does the following (see code comments) making use of helper methods:
splits the input by "\n"
splits every result of the first step by space in order to separate the day of week from the times of day
splits the second result of the second split by "-" in order to get the times of day
converts the results into appropriate objects
stores them in an appropriate data structure
finds the maximum durations
This is what I came up with:
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.TextStyle;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
class WeekdayDurationHandler {
public static void main(String[] args) {
// input String splitting...
String input = "Mon 01:00-23:00\nTue 01:00-23:00\nWed 01:00-23:00\nThu 01:00-23:00\nFri 01:00-23:00\nSat 01:00-23:00\nSun 01:00-21:00";
String[] times = input.split("\n");
// data structure for holding the durations per day
Map<DayOfWeek, Duration> weekdayDurations = new TreeMap<>();
// the result of the first splitting is unparseable, that's why some more
// splitting is applied
for (String s : times) {
// separate the day of week from the time duration
String[] sp = s.split(" ");
// split the duration into "from" and "to" (time of day)
String[] tp = sp[1].split("-");
// parse the day of week into an appropriate object
DayOfWeek dayOfWeek = parseDayOfWeek(sp[0]);
// parse the times of day into appropriate objects
LocalTime localTimeFrom = LocalTime.parse(tp[0]);
LocalTime localTimeTo = LocalTime.parse(tp[1]);
// calculate the duration between "from" and "to" time of day
Duration duration = Duration.between(localTimeFrom, localTimeTo);
// store them in the data structure
weekdayDurations.put(dayOfWeek, duration);
}
// print them
weekdayDurations.forEach((DayOfWeek dayOfWeek, Duration duration) -> {
System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL_STANDALONE, Locale.getDefault()) + ": "
+ duration.toHours() + " hours (" + duration.toMinutes() + " minutes)");
});
System.out.println("######################################################");
// then print the maximum durations found
findMaxDurationsFrom(weekdayDurations).forEach((DayOfWeek dayOfWeek, Duration duration) -> {
System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL_STANDALONE, Locale.getDefault()) + ": "
+ duration.toHours() + " hours (" + duration.toMinutes() + " minutes)");
});
}
private static DayOfWeek parseDayOfWeek(String weekday) {
switch (weekday.toLowerCase()) {
case "mon":
return DayOfWeek.MONDAY;
case "tue":
return DayOfWeek.TUESDAY;
case "wed":
return DayOfWeek.WEDNESDAY;
case "thu":
return DayOfWeek.THURSDAY;
case "fri":
return DayOfWeek.FRIDAY;
case "sat":
return DayOfWeek.SATURDAY;
case "sun":
return DayOfWeek.SUNDAY;
default:
throw new RuntimeException("Unparsable weekday: \"" + weekday + "\"");
}
}
private static Map<DayOfWeek, Duration> findMaxDurationsFrom(Map<DayOfWeek, Duration> weekDurations) {
final Map<DayOfWeek, Duration> maxDurations = new TreeMap<>();
// find the maximum duration as a reference for all equal durations
Duration maxDuration = findMaxDuration(weekDurations);
// go through all durations and store those equal to maxDuration (no matter what day of week)
weekDurations.forEach((DayOfWeek dayOfWeek, Duration duration) -> {
if (duration.equals(maxDuration)) {
maxDurations.put(dayOfWeek, duration);
}
});
return maxDurations;
}
private static <K, V extends Comparable<V>> V findMaxDuration(Map<K, V> map) {
Entry<K, V> maxEntry = Collections.max(map.entrySet(),
(Entry<K, V> e1, Entry<K, V> e2) -> e1.getValue().compareTo(e2.getValue()));
return maxEntry.getValue();
}
}
I hope it helps…
I have jdk java version "1.8.0_45", i am using joda time api (joda-time-2.7.jar)
By using Joda time api i am getting a wrong date.
By using Jdk 8 hijri date api i am getting a correct date.
I have a requirement to convert a gregorian date to hijri date using java api.
My sample test class is as follows:
import org.joda.time.*;
import org.joda.time.chrono.*;
import java.time.*;
import java.time.chrono.HijrahChronology;
import java.util.*;
public class Test {
public static void main(String[] args) throws Exception {
DateTime dtISO = new DateTime();
System.out.println("dtISO = "+dtISO);
DateTime dtIslamic = dtISO.withChronology(IslamicChronology.getInstance(DateTimeZone.UTC ));
System.out.println(dtIslamic.getYear()+"-" +dtIslamic.getMonthOfYear()+ "-"+ dtIslamic.getDayOfMonth());
java.time.chrono.HijrahDate hijradate = java.time.chrono.HijrahDate.now();
System.out.println("hijradate "+hijradate);
}
}
Output of this class is
C:\>java Test
dtISO = 2015-05-24T09:44:51.704+04:00
1436-8-5
hijradate Hijrah-umalqura AH 1436-08-06
Can you please tell me joda api is correct one or wrong one?
My production server has JDK1.6 i cannot upgrade it to 1.8 as of now, so kindly let me know your suggestions to get a proper hijri date .... Awaiting for your reply....
The difference you are seeing between JodaTime and JDK8 is because they use different implementations of the Hijri Calendar. There are multiple algorithms to compute (approximate) a Hijri date.
Jdk8's HijrahChoronology uses an implementation of Umm-AlQura calendar which closely matches the official Hijri calendar in Saudi Arabia as defined in http://www.ummulqura.org.sa/.
JodaTime IslamicChronology has different implementations which you can select from using its factory methods see http://joda-time.sourceforge.net/apidocs/org/joda/time/chrono/IslamicChronology.html
So it really depends on system audience. If you are in Saudi Arabia or any country which relies on UmmAlQura calendar stick with the JDK8's implementation.
i found this code on http://junaedhalim.blogspot.com/2010/01/hijri-calendar-in-java-using-kuwaiti.html hopefully it help you
import java.util.Calendar;
import java.util.Date;
/**
*
* #author junaed
*/
public class HijriCalendar
{
private int[] userDateG;
private int[] userDateH;
private WaqtMidlet midlet;
private Calendar cal;
private int currentHijriDate;
private int currentHijriMonth;
private int currentHijriYear;
public static final String[] HIJRI_MONTHS =
{
"Muharram", "Safar", "Rabi' al-awwal", "Rabi' al-thani", "Jumada al-awwal",
"Jumada al-thani", "Rajab", "Sha'aban", "Ramadan", "Shawwal", "Dhu al-Qi'dah", "Dhu al-Hijjah"
};
public static final int[] BASE_DATE_G =
{
18, 11, 2009, 0, 0
};
public static final int[] BASE_DATE_H =
{
1, 0, 1431, 0, 0
};
public HijriCalendar(WaqtMidlet midlet)
{
this.midlet = midlet;
cal = Calendar.getInstance();
Date date = new Date();
cal.setTime(date);
}
private void updateDefinedTime()
{
String uTimeH = midlet.getRmsManager().getString(ApplicationConstants.RMS_HIJRI_DATE);
// String uTimeH = "";
if (uTimeH == null || uTimeH.equalsIgnoreCase(""))
{
userDateG = ApplicationConstants.BASE_DATE_G;
userDateH = ApplicationConstants.BASE_DATE_H;
}
else
{
System.out.println("uTimeH = " + uTimeH);
int date = Integer.parseInt(uTimeH.substring(0, uTimeH.indexOf(';')));
String rest = uTimeH.substring(uTimeH.indexOf(';') + 1);
int month = Integer.parseInt(rest.substring(0, rest.indexOf(';')));
rest = rest.substring(rest.indexOf(';') + 1);
int year = Integer.parseInt(rest.substring(0, rest.indexOf(';')));
rest = rest.substring(rest.indexOf(';') + 1);
int hour = Integer.parseInt(rest.substring(0, rest.indexOf(';')));
rest = rest.substring(rest.indexOf(';') + 1);
int minute = Integer.parseInt(rest);
userDateH = new int[]
{
date, month, year, hour, minute
};
// String uTimeG = "";
String uTimeG = midlet.getRmsManager().getString(ApplicationConstants.RMS_GREGORIAN_DATE);
System.out.println("uTimeG = " + uTimeG);
date = Integer.parseInt(uTimeG.substring(0, uTimeG.indexOf(';')));
rest = uTimeG.substring(uTimeG.indexOf(';') + 1);
month = Integer.parseInt(rest.substring(0, rest.indexOf(';')));
rest = rest.substring(rest.indexOf(';') + 1);
year = Integer.parseInt(rest.substring(0, rest.indexOf(';')));
userDateG = new int[]
{
date, month, year, hour, minute
};
}
cal.set(Calendar.HOUR_OF_DAY, userDateG[3]);
cal.set(Calendar.MINUTE, userDateG[4]);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.DATE, userDateG[0]);
cal.set(Calendar.MONTH, userDateG[1]);
cal.set(Calendar.YEAR, userDateG[2]);
currentHijriDate = userDateH[0];
currentHijriMonth = userDateH[1];
currentHijriYear = userDateH[2];
}
private boolean isALeapYear(int year)
{
int modValue = year % 30;
switch (modValue)
{
case 2:
return true;
case 5:
return true;
case 7:
return true;
case 10:
return true;
case 13:
return true;
case 15:
return true;
case 18:
return true;
case 21:
return true;
case 24:
return true;
case 26:
return true;
case 29:
return true;
}
return false;
}
private int getDaysInThisYear(int year)
{
if (isALeapYear(year))
{
return 355;
}
return 354;
}
public int getDaysInThisMonth(int month, int year)
{
if (month % 2 != 0)
{
return 30;
}
else
{
if (month == 12)
{
if (isALeapYear(year))
{
return 30;
}
}
return 29;
}
}
private void addOneDayToCurrentDate()
{
currentHijriDate++;
if(currentHijriDate >= 29)
{
int daysInCurrentMonth = getDaysInThisMonth(currentHijriMonth, currentHijriYear);
if( currentHijriDate > daysInCurrentMonth)
{
currentHijriDate = 1;
currentHijriMonth++;
if(currentHijriMonth > 11)
{
currentHijriMonth = 1;
currentHijriYear++;
}
}
}
}
private void addDays(long days)
{
for(long i = 0; i< days; i++)
{
addOneDayToCurrentDate();
}
}
public String getCurrentDateStr()
{
updateDefinedTime();
Date date = new Date();
// int currentTime = calendar.get(Calendar.HOUR_OF_DAY);
long diff = date.getTime() - cal.getTime().getTime();
long days = diff / (1000 * 86400);
addDays(days);
String ret = currentHijriYear + " "+HIJRI_MONTHS[currentHijriMonth] + ", " + currentHijriDate;
return ret;
// return midlet.getRmsManager().getString(ApplicationConstants.RMS_HIJRI_DATE);
}
}
Try using ICU4J. Its Calendar classes do not extend java.util.Calendar, but they do properly deal with Hijri dates (and many other calendar systems). I was able to get what I believe are correct results using its IslamicCalendar class, using Java 1.6.0_31:
import java.util.Date;
import java.util.Locale;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.IslamicCalendar;
public class HijriDate {
public static void main(String[] args) {
java.util.Calendar gregorianCal =
java.util.Calendar.getInstance(Locale.US);
System.out.printf("%tF%n", gregorianCal);
Date date = gregorianCal.getTime();
Calendar cal = new IslamicCalendar();
cal.setTime(date);
System.out.printf("%02d-%02d-%02d%n",
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH));
}
}
Below I have 3 methods. The first is very simple. It just counts the total number of days. The second, however, will not only count the days, but will ignore the days of the week that are passed in to the method.
My problem is that the third method is not always correct. It should match the second method. I am guessing it has something to do with leap years, because the difference is usually +=3|4 when it is incorrect.
Additional Info
I am attempting to mock Excel's weekday(serial_number,[return_type]) formula in a way.
serial_number = startDate:Date - daysOfWeekToInclude:Array<Integer>
Example
| A | B | C
+---------+----------------------------------------------------+-----------
1 | Start | =DATE(2014,9,7) | 9/7/2014
2 | End | =DATE(2025,6,13) | 6/13/2025
3 | Include | ={1,2,4,6} (Mon, Tue, Thu, & Sat) | <Disp Only>
4 | Days | =SUM(INT((WEEKDAY($B$1-{1,2,4,6},1)+$B$2-$B$1)/7)) | 2248
There is more information on this function here: How to count / calculate the number of days between two dates in Excel?
Raw Image
Methods
Simply count the number of days between two dates.
public static int simpleDaysBetween(final LocalDate start,
final LocalDate end) {
return (int) ChronoUnit.DAYS.between(start, end);
}
Count number of days, ignoring certain days of week, using a loop.
public static int betterDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int count = 0;
LocalDate curr = start.plusDays(0);
while (curr.isBefore(end)) {
if (!ignore.contains(curr.getDayOfWeek())) {
count++;
}
curr = curr.plusDays(1); // Increment by a day.
}
return count;
}
Count number of days. again but without a loop.
public static int bestDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int days = simpleDaysBetween(start, end);
if (days == 0) {
return 0;
}
if (!ignore.isEmpty()) {
int weeks = days / 7;
int startDay = start.getDayOfWeek().getValue();
int endDay = end.getDayOfWeek().getValue();
int diff = weeks * ignore.size();
for (DayOfWeek day : ignore) {
int currDay = day.getValue();
if (startDay <= currDay) {
diff++;
}
if (endDay > currDay) {
diff++;
}
}
if (endDay > startDay) {
diff -= endDay - startDay;
}
return days - diff;
}
return days;
}
Full code
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.List;
public class DayCounter {
public static void main(String[] args) {
final LocalDate start = LocalDate.of(2014, 9, 7);
final LocalDate end = LocalDate.of(2025, 6, 13);
List<DayOfWeek> ignore = Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY);
print(start);
print(end);
System.out.println(simpleDaysBetween(start, end));
System.out.println(betterDaysBetween(start, end, ignore));
System.out.println(bestDaysBetween(start, end, ignore));
}
public static void print(LocalDate date) {
System.out.printf("%s -> %s%n", date, date.getDayOfWeek());
}
public static int simpleDaysBetween(final LocalDate start,
final LocalDate end) {
return (int) ChronoUnit.DAYS.between(start, end);
}
public static int betterDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int count = 0;
LocalDate curr = start.plusDays(0);
while (curr.isBefore(end)) {
if (!ignore.contains(curr.getDayOfWeek())) {
count++;
}
curr = curr.plusDays(1); // Increment by a day.
}
return count;
}
public static int bestDaysBetween(final LocalDate start,
final LocalDate end, final List<DayOfWeek> ignore) {
int days = simpleDaysBetween(start, end);
if (days == 0) {
return 0;
}
if (!ignore.isEmpty()) {
int weeks = days / 7;
int startDay = start.getDayOfWeek().getValue();
int endDay = end.getDayOfWeek().getValue();
int diff = weeks * ignore.size();
for (DayOfWeek day : ignore) {
int currDay = day.getValue();
if (startDay <= currDay) {
diff++;
}
if (endDay > currDay) {
diff++;
}
}
if (endDay > startDay) {
diff -= endDay - startDay;
}
return days - diff;
}
return days;
}
}
If we talk about a Java 8 API, why not use the Java 8 features consequently…
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
return Stream.iterate(start, d->d.plusDays(1))
.limit(start.until(end, ChronoUnit.DAYS))
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}
Starting with Java 9, we can use the even simpler
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
return start.datesUntil(end)
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}
Though, it might be worth using a Set with a better-than-linear lookup rather than the List:
static long daysBetween(LocalDate start, LocalDate end, List<DayOfWeek> ignore) {
if(ignore.isEmpty()) return start.until(end, ChronoUnit.DAYS);
EnumSet<DayOfWeek> set = EnumSet.copyOf(ignore);
return start.datesUntil(end)
.filter(d->!ignore.contains(d.getDayOfWeek()))
.count();
}
You may consider changing the parameter to Set<DayOfWeek>, as it is not only more efficient but better suited to the actual use cases. Instead of Arrays.asList(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY), you can pass EnumSet.of(DayOfWeek.SUNDAY, DayOfWeek.WEDNESDAY, DayOfWeek.FRIDAY), but you can also use constructs like EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY), to denote the typical working days.
You can avoid iterating over all days, but it requires special care about corner cases and hence, thorough testing. And will only pay off for really large ranges. For completeness, this is the optimized variant:
static long daysBetween(LocalDate start, LocalDate end, Set<DayOfWeek> ignore) {
long d1 = start.toEpochDay(), d2 = end.toEpochDay();
if(d1 > d2) throw new IllegalArgumentException();
if(ignore.isEmpty()) return d2 - d1;
int incompleteWeek = 0;
DayOfWeek startDoW = start.getDayOfWeek(), endDoW = end.getDayOfWeek();
if(startDoW != endDoW) {
for(int v1 = startDoW.getValue(), v2 = endDoW.getValue();
v1 != v2 && d1 < d2; v1 = v1%7+1, d1++) {
if(!ignore.contains(DayOfWeek.of(v1))) incompleteWeek++;
}
}
return incompleteWeek + (d2 - d1) * (7 - ignore.size()) / 7;
}
Here, the performance of the ignore set’s lookup doesn’t matter, as we only look up at most six values, however, enforcing a Set, i.e. no duplicates, allows us to use the set’s size to calculate the number of days contained in complete weeks of the range. Complete weeks have the same day of week for the start and (exclusive) end date. So the code only needs to iterate the days, until the start and end day of week match.
You you are using wrong Excel formula. See the section "Using SUM and INT function to count the number of workdays" of the site that you have provided. It is stating the formula as:
=SUM(INT((WEEKDAY(A2-{2,3,4,5,6})+B2-A2)/7))
In Excel, Sunday is 1 and Saturday is 7. The numbers inside the curly braces indicates the day-of-weeks to be included. So for your case the formula will be:
=SUM(INT((WEEKDAY(A2-{2,3,5,7})+B2-A2)/7))
Please see the attached screenshot:
It is returning 2247 as the following code returns:
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class SO25798876 {
public static void main(String[] args) {
String strStartDate = "09/07/2014";
String strEndDate = "06/13/2025";
String pattern = "MM/dd/yyyy";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
LocalDate startDate = LocalDate.parse(strStartDate, formatter);
LocalDate endDate = LocalDate.parse(strEndDate, formatter);
int count = 0;
while(startDate.isBefore(endDate) || startDate.isEqual(endDate)) { // you may want to not to use the isEqual method
DayOfWeek dayOfWeek = startDate.getDayOfWeek();
if(!(dayOfWeek == DayOfWeek.SUNDAY || dayOfWeek == DayOfWeek.WEDNESDAY || dayOfWeek == DayOfWeek.FRIDAY)) {
count++;
}
startDate = startDate.plusDays(1);
}
System.out.println(count);
}
}
You also have mentioned your doubt that the java.time may be not considering leap year, which is wrong, if you add the following piece of code
long year = startDate.getYear();
if(Year.isLeap(year)) {
Month month = startDate.getMonth();
if(month == Month.FEBRUARY && startDate.getDayOfMonth() == 29) {
System.out.println("Calculated 29th Feb for the year: " + year);
}
}
You will see that it is printing:
Calculated 29th Feb for the year: 2016
Calculated 29th Feb for the year: 2020
Calculated 29th Feb for the year: 2024
Lastly the count will be 2247 which matches the Excel result.
Happy coding.
-Tapas
I have a method that gets a string and change that to a particular date format but the thing is the date will be any format
For Example
16 July 2012
March 20 2012
2012 March 20
So I need to detect the string is in which file format.
I use the below code to test it but I get exception if the file format changes.
private String getUpdatedDate(String updated) {
Date date;
String formatedDate = null;
try {
date = new SimpleDateFormat("d MMMM yyyy", Locale.ENGLISH)
.parse(updated);
formatedDate = getDateFormat().format(date);
} catch (ParseException e) {
e.printStackTrace();
}
return formatedDate;
}
Perhaps the easiest solution is to build a collection of date formats you can reasonably expect, and then try the input against each one in turn.
You may want to flag ambiguous inputs e.g. is 2012/5/6 the 5th June or 6th May ?
BalusC wrote a simple DateUtil which serves for many cases. You may need to extend this to satisfy your requirements.
Here is the link: https://balusc.omnifaces.org/2007/09/dateutil.html
and the method you need to look for determineDateFormat()
If you're using Joda Time (awesome library btw) you can do this quite easily:
DateTimeParser[] dateParsers = {
DateTimeFormat.forPattern("yyyy-MM-dd HH").getParser(),
DateTimeFormat.forPattern("yyyy-MM-dd").getParser() };
DateTimeFormatter formatter = new DateTimeFormatterBuilder().append(null, dateParsers).toFormatter();
DateTime date1 = formatter.parseDateTime("2012-07-03");
DateTime date2 = formatter.parseDateTime("2012-07-03 01");
Apache commons has a utility method to solve this problem . The org.apache.commons.lang.time.DateUtils class has a method parseDateStrictly
public static Date parseDateStrictly(String str,
String[] parsePatterns)
throws ParseException
Parameters:
str - the date to parse, not null
parsePatterns - the date format patterns to use, see SimpleDateFormat, not null
Parses a string representing a date by trying a variety of different parsers.
The parse will try each parse pattern in turn. A parse is only deemed successful if it parses the whole of the input string. If no parse patterns match, a ParseException is thrown.
The parser parses strictly - it does not allow for dates such as "February 942, 1996".
FTA (https://github.com/tsegall/fta) is designed to solve exactly this problem (among others). Here is an example:
import java.util.Locale;
import com.cobber.fta.dates.DateTimeParser;
import com.cobber.fta.dates.DateTimeParser.DateResolutionMode;
public abstract class DetermineDateFormat {
public static void main(final String[] args) {
final DateTimeParser dtp = new DateTimeParser(DateResolutionMode.MonthFirst, Locale.ENGLISH);
System.err.println(dtp.determineFormatString("26 July 2012"));
System.err.println(dtp.determineFormatString("March 9 2012"));
// Note: Detected as MM/dd/yyyy despite being ambiguous as we indicated MonthFirst above when insufficient data
System.err.println(dtp.determineFormatString("07/04/2012"));
System.err.println(dtp.determineFormatString("2012 March 20"));
System.err.println(dtp.determineFormatString("2012/04/09 18:24:12"));
}
Which will give the following output:
MMMM d yyyy
MM/dd/yyyy
yyyy MMMM dd
yyyy/MM/dd HH:mm:ss
Decide which formats are expected, and try to parse the date with each format, one after the other. Stop as soon as one of the formats parses the date without exception.
Click to see the result
Use the regex to parse the string for date. This regex can detect any kind of date format. The sample code here is not including time yet. You can change the code to add more parts of the date like time and time zone...The month name is depending on default language locale of the system.
import java.io.IOException;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DateUtils {
static String MONTH="";
static String dateRegEx="";
static Pattern DatePattern;
static HashMap<String, Integer> monthMap = new HashMap<String, Integer>();
static {
initializeMonthName();
dateRegEx="(?i)(\\d{1,4}|"+MONTH+")[-|/|.|\\s+]?(\\d{1,2}|"+MONTH+")[-|/|.|,]?[\\s+]?(\\d{1,4}|"+MONTH+")[\\s+|\\t|T]?(\\d{0,2}):?(\\d{0,2}):?(\\d{0,2})[.|,]?[\\s]?(\\d{0,3})?([+|-])?(\\d{0,2})[:]?(\\d{0,2})[\\s+]?([A|P]M)?";
DatePattern = Pattern.compile(dateRegEx);
}
private static void initializeMonthName() {
String[] monthName=getMonthString(true);
for(int i=0;i<12;i++){
monthMap.put(monthName[i].toLowerCase(), Integer.valueOf(i+1));
}
monthName=getMonthString(false);
for(int i=0;i<12;i++){
monthMap.put(monthName[i].toLowerCase(), Integer.valueOf(i+1));
}
Iterator<String> it = monthMap.keySet().iterator();
while(it.hasNext()){
String month=it.next();
if(MONTH.isEmpty()){
MONTH=month;
}else{
MONTH=MONTH + "|" + month;
}
}
}
public static boolean isInteger(Object object) {
if(object instanceof Integer) {
return true;
} else {
try{
Integer.parseInt(object.toString());
}catch(Exception e) {
return false;
}
}
return true;
}
public static String[] getMonthString(boolean isShort) {
DateFormatSymbols dfs = new DateFormatSymbols();
if (isShort) {
return dfs.getShortMonths();
} else {
return dfs.getMonths();
}
}
public static int getMonthMap(String value) {
if(monthMap.get(value)==null){
return 0;
}
return monthMap.get(value).intValue();
}
public static long parseDate(String value){
Matcher matcher = DatePattern.matcher(value);
int Year=0, Month=0, Day=0;
boolean isYearFound=false;
boolean isMonthFound=false;
boolean isDayFound=false;
if(matcher.find()) {
for(int i=1;i<matcher.groupCount();i++){
String data=matcher.group(i)==null?"":matcher.group(i);
if(data.equalsIgnoreCase("null")){
data="";
}
//System.out.println(String.valueOf(i) + ": " + data);
switch(i){
case 1:
if(!data.isEmpty()){
if(isInteger(data)){
Integer YMD = Integer.valueOf(data);
if(YMD==0){
return 0;
}
if(YMD>31){
Year = YMD.intValue();
isYearFound = true;
}else if(YMD>12){
Day = YMD.intValue();
isDayFound = true;
}else {
Month=YMD.intValue();
isMonthFound=true;
}
}else {
Month = getMonthMap(data.toLowerCase());
if(Month==0){
return 0;
}
isMonthFound=true;
}
}else {
return 0;
}
break;
case 2:
if(!data.isEmpty()){
if(isInteger(data)){
Integer YMD = Integer.valueOf(data);
if(YMD==0){
return 0;
}
if(YMD>31){
if(isYearFound) {
return 0;
}
Year = YMD.intValue();
isYearFound = true;
}else if(YMD>12){
if(isDayFound) {
return 0;
}
Day = YMD.intValue();
isDayFound = true;
}else {
if(isMonthFound){
Day=YMD.intValue();
isDayFound=true;
}else{
Month=YMD.intValue();
isMonthFound=true;
}
}
}else {
if(isMonthFound){
Day=Month;
isDayFound=true;
}
Month = getMonthMap(data.toLowerCase());
if(Month==0){
return 0;
}
isMonthFound=true;
}
}else {
return 0;
}
break;
case 3:
if(!data.isEmpty()){
if(isInteger(data)){
Integer YMD = Integer.valueOf(data);
if(YMD==0){
return 0;
}
if(YMD>31){
if(isYearFound) {
return 0;
}
Year = YMD.intValue();
isYearFound = true;
}else if(YMD>12){
if(isDayFound) {
return 0;
}
Day = YMD.intValue();
isDayFound = true;
}else {
if(isMonthFound){
Day=YMD.intValue();
isDayFound=true;
}else {
Month = YMD.intValue();
isMonthFound=true;
}
}
}else {
if(isMonthFound){
Day=Month;
isDayFound=true;
}
Month = getMonthMap(data.toLowerCase());
if(Month==0){
return 0;
}
isMonthFound=true;
}
}else {
return 0;
}
break;
case 4:
//hour
break;
case 5:
//minutes
break;
case 6:
//second
break;
case 7:
//millisecond
break;
case 8:
//time zone +/-
break;
case 9:
//time zone hour
break;
case 10:
// time zone minute
break;
case 11:
//AM/PM
break;
}
}
}
Calendar c = Calendar.getInstance();
c.set(Year, Month-1, Day, 0, 0);
return c.getTime().getTime();
}
public static void main(String[] argv) throws IOException {
long d= DateUtils.parseDate("16 July 2012");
Date dt = new Date(d);
SimpleDateFormat df2 = new SimpleDateFormat("d MMMM yyyy");
String dateText = df2.format(dt);
System.out.println(dateText);
d= DateUtils.parseDate("March 20 2012");
dt = new Date(d);
dateText = df2.format(dt);
System.out.println(dateText);
d= DateUtils.parseDate("2012 March 20");
dt = new Date(d);
dateText = df2.format(dt);
System.out.println(dateText);
}
}
public static String detectDateFormat(Context context, String inputDate, String requiredFormat) {
String tempDate = inputDate.replace("/", "").replace("-", "").replace(" ", "");
String dateFormat = "";
if (tempDate.matches("([0-12]{2})([0-31]{2})([0-9]{4})")) {
dateFormat = "MMddyyyy";
} else if (tempDate.matches("([0-31]{2})([0-12]{2})([0-9]{4})")) {
dateFormat = "ddMMyyyy";
} else if (tempDate.matches("([0-9]{4})([0-12]{2})([0-31]{2})")) {
dateFormat = "yyyyMMdd";
} else if (tempDate.matches("([0-9]{4})([0-31]{2})([0-12]{2})")) {
dateFormat = "yyyyddMM";
} else if (tempDate.matches("([0-31]{2})([a-z]{3})([0-9]{4})")) {
dateFormat = "ddMMMyyyy";
} else if (tempDate.matches("([a-z]{3})([0-31]{2})([0-9]{4})")) {
dateFormat = "MMMddyyyy";
} else if (tempDate.matches("([0-9]{4})([a-z]{3})([0-31]{2})")) {
dateFormat = "yyyyMMMdd";
} else if (tempDate.matches("([0-9]{4})([0-31]{2})([a-z]{3})")) {
dateFormat = "yyyyddMMM";
} else {
}
try {
String formattedDate = new SimpleDateFormat(requiredFormat, Locale.ENGLISH).format(new SimpleDateFormat(dateFormat).parse(tempDate));
Toast.makeText(context, formattedDate, Toast.LENGTH_SHORT).show();
return formattedDate;
} catch (Exception e) {
Toast.makeText(context, "Please check the date format", Toast.LENGTH_SHORT).show();
return "";
}
}
I encountered this issue as well, where at some places:
I did the same thing having a collection of format which matches my need.
Updated my sql query in a way that it returns the date in a format which I can easily parse for e.g. used this in my query TO_CHAR (o.CREATE_TS, 'MM-DD-YYYY')
& while converting in my other desired format used "MM-dd-yyyy" in java to parse and change to desired format.
Hopefully, #2 will help you in atleast few cases.