Check if a string contains only date - java

I have a string which can contain a date(yyyy-MM-dd) or date and time (yyyy-MM-dd HH:mm:ss) in respective formats.
I want to know which strings contains only date.
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
System.out.println(dateFormat.parse("2015-02-02"));
System.out.println(dateFormat.parse("2015-02-02 23:23:23"));
In above code, both the strings are parsed successfully, whereas the format is same for only first.

I would use the overload of parse which takes a ParsePosition - you can then check the position afterwards:
import java.util.*;
import java.text.*;
public class Test {
public static void main(String[] args) throws Exception {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
System.out.println(parseFully(dateFormat, "2015-02-02"));
System.out.println(parseFully(dateFormat, "2015-02-02 23:23:23"));
}
private static Date parseFully(DateFormat format, String text)
throws ParseException {
ParsePosition position = new ParsePosition(0);
Date date = format.parse(text, position);
if (position.getIndex() == text.length()) {
return date;
}
if (date == null) {
throw new ParseException("Date could not be parsed: " + text,
position.getErrorIndex());
}
throw new ParseException("Date was parsed incompletely: " + text,
position.getIndex());
}
}

public static void main(String[] args) {
String dateOnly = "2015-02-02";
String dateAndTimeOnly = "2015-02-02 23:23:23";
System.out.println("Date Only = " + validateDateFormat(dateOnly));
System.out.println("Date And time Only = " + validateDateFormat(dateAndTimeOnly));
}
public static boolean validateDateFormat(String input) {
return input.matches("([0-9]{4})-([0-9]{2})-([0-9]{2})");
}
output
Date Only = true
Date And time Only = false
Regex is self explanatory - Input will be separated by -, ist part([0-9]{4}) can contain 4 digit , 2nd part can contain 2 digit [0-9]{2}, so as 3rd.

java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
Let's first try to do it the way you have done:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String[] arr = { "2015-02-02", "2015-02-02 23:23:23" };
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.ENGLISH);
for (String s : arr) {
System.out.println("Attempting to parse '" + s + "':");
LocalDate date = LocalDate.parse(s, dtf);
System.out.println("Parsed successfully: " + date);
}
}
}
Output:
Attempting to parse '2015-02-02':
Parsed successfully: 2015-02-02
Attempting to parse '2015-02-02 23:23:23':
Exception in thread "main" java.time.format.DateTimeParseException: Text '2015-02-02 23:23:23' could not be parsed, unparsed text found at index 10
As you can see, the java.time API correctly throws an exception informing you about the problem. SimpleDateFormat, on the other hand, parses the input string silently which has caused the problem that you have posted.
Thus, with the modern date-time API, you have two easy options:
Simply catch the exception and say that the second input (i.e. 2015-02-02 23:23:23) is not a date string as per the specified date pattern.
Use the function, DateTimeFormatter#parse(CharSequence, ParsePosition) with the ParsePosition index set to 0.
Given below is a demo of the second option:
import java.text.ParsePosition;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String[] arr = { "2015-02-02", "2015-02-02 23:23:23" };
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.ENGLISH);
for (String s : arr) {
ParsePosition pp = new ParsePosition(0);
LocalDate.from(dtf.parse(s, pp));
if (pp.getIndex() < s.length()) {
System.out.println("'" + s + "' is not a date string as per the specified date pattern.");
}
}
}
}
Output:
'2015-02-02 23:23:23' is not a date string as per the specified date pattern.
ONLINE DEMO
Note: Never use SimpleDateFormat or DateTimeFormatter without a Locale.
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Once the desired format is reached , SimpleDateFormat doesnt format the rest of String . It is the reason why your second string is parsed.
This post SimpleDateFormat parse(string str) doesn't throw an exception when str = 2011/12/12aaaaaaaaa? may help you .
Also check the DateFormat#parse method in java docs

Related

Query a Table based on the column as datetime2(7) from JPA

I need to query list of records between the given date range based on the column which was defined as datetime2(7) in MS SQL Server.
From the HTTP request I will be receiving startDate and endDate as below.
http://{host:port}/api/records/date?startDate=**2021-05-31T14:12:44.8020000**&endDate=**2021-05-31T14:12:44.8020000**
In the database, value in lastUpdated column is stored as 2021-05-31 14:12:44.8020000
I am trying to convert the incoming query params which is a String to java.sql.Date in the code as below
#Override
public Page<Entity> getAllRecordsWithDateRange(String startDate, String endDate) {
Page<Entity> recordsWithinDateRange = null;
String time = startDate;
String formatIn = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS";
String formatOut = "yyyy-MM-dd HH:mm:ss.SSSSSS";
SimpleDateFormat in = new SimpleDateFormat(formatIn);
SimpleDateFormat out = new SimpleDateFormat(formatOut);
Date dateIn = null;
try {
dateIn = in.parse(time);
} catch (ParseException e) {
e.printStackTrace();
}
String valueOut = out.format(dateIn);
System.out.println(">>> " + valueOut);
Pageable page = PageRequest.of(0,5000);
Date date1= null;
try {
date1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").parse(valueOut);
java.util.Date utilDate = date1;
recordsWithinDateRange = repo.getAllRecordsBetweenDates(utilDate,utilDate,page);
} catch (ParseException e) {
e.printStackTrace();
}
return recordsWithinDateRange;
}
Issue I am seeing here is my actual input date is 2021-05-31T14:12:44.8020000
But, after the conversion it is incremented to a different time 2021-05-31 16:26:24.000000. So, query is returning no records from the DB.
Could someone help me to solve this issue? TIA!
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API*:
datetime2 maps to TIMESTAMP ANSI SQL type or LocalDateTime in JDBC.
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("u-M-d'T'H:m:s.SSSSSSS", Locale.ENGLISH);
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSS", Locale.ENGLISH);
String strDateTime = "2021-05-31T14:12:44.8020000";
LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtfInput);
System.out.println(ldt.format(dtfOutput));
}
}
Output:
2021-05-31 14:12:44.8020000
ONLINE DEMO
Check this answer to learn how to perform JDBC operations using LocalDateTime.
Solution using legacy API:
SimpleDateFormat does not handle fraction-of-second beyond millisecond precision correctly. Check this answer to learn more about it.
You need to truncate the date-time string to millisecond precision.
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "2021-05-31T14:12:44.8020000";
strDateTime = strDateTime.substring(0, strDateTime.indexOf('.') + 4);
String formatIn = "yyyy-MM-dd'T'HH:mm:ss.SSS";
String formatOut = "yyyy-MM-dd HH:mm:ss.SSS";
SimpleDateFormat in = new SimpleDateFormat(formatIn);
SimpleDateFormat out = new SimpleDateFormat(formatOut);
System.out.println(out.format(in.parse(strDateTime)));
}
}
Output:
2021-05-31 14:12:44.802
ONLINE DEMO
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

How can I retrieve datetiime from mongodb? By comparing the data with jDateChosser Java

private void showdataTable_btnActionPerformed(java.awt.event.ActionEvent evt) {
try {
DateFormat df = new SimpleDateFormat("YYYY-mm-dd'T'HH:MM:ss'Z'"); //set date format
String set = df.format(dateChoos1.getDate()); //add value to set
BasicDBObject whereQuery = new BasicDBObject();
whereQuery.put("datetimes", set); //where date via set(date)
DBCursor cursor = table.find(whereQuery);
while (cursor.hasNext()) {
DBObject obj = cursor.next();
String ip_address = (String) obj.get("ip_address");
String mac_address = (String) obj.get("mac_address");
Date datetimes = (Date) obj.get("datetimes");
String url = (String) obj.get("url");
model.insertRow(model.getRowCount(), new Object[]{datetimes, ip_address, mac_address, url});
}
} catch (Exception e) {
System.out.println("Something went wrong.");
}
}
Your format, YYYY-mm-dd'T'HH:MM:ss'Z' is not correct. Let's discuss everything which is wrong with this format.
You have used Y instead of y: The symbol Y is used for Week year while y is used for Year. Check Difference between year-of-era and week-based-year? to learn more about it.
You have used mm for month: The correct symbol for the month is M.
You have used MM for minutes: The correct symbol for the minute is m.
You have enclosed Z within single quotes: The symbol, Z is used for Time zone whereas 'Z' is nothing but a character literal. Probably you want to format the timezone offset of +00:00 as Z and for this, you should in fact use X.
So, the correct format is as follows:
yyyy-MM-dd'T'HH:mm:ssX
A demo with the suggested format:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.ENGLISH);
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
System.out.println(sdf.format(date));
}
}
Output:
2021-01-14T08:13:01Z
Note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Use Date#toInstant to convert a java.util.Date object (the legacy type) to java.time.Instant (the modern type). Instant represents an instantaneous point on the time-line and should be just enough for most of your JSON operations. The Instant#toString returns the date-time string with UTC timezone offset which is compliant with ISO-8601 standards.
Demo:
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
Instant instant = date.toInstant();
// Print the value of instant#toString
System.out.println(instant);
OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);
System.out.println(odt);
// Custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX", Locale.ENGLISH);
System.out.println(dtf.format(odt));
}
}
Output:
2021-01-14T08:28:35.659Z
2021-01-14T08:28:35.659Z
2021-01-14T08:28:35Z

How to get a specific part of a string in java

I'm developing an Android app that gets the date from the internet. What I have is a complete date format like this one : 2020-06-13T16:21:15.239920+02:00. I want to get the day of the month (which is 13 in this case).
If you are using at least API level 26, then you can use ZonedDateTime class as your string uses the default format that is understood by that class.
ZonedDateTime zdt = ZonedDateTime.parse("2020-06-13T16:21:15.239920+02:00");
int d = zdt.getDayOfMonth();
Alternatively, if the format is constant, simply use method substring()
String dd = "2020-06-13T16:21:15.239920+02:00".substring(8, 10);
If the format is not constant, I would suggest either regular expression or combining ZonedDateTime with DateTimeFormatter
Your date/time string complies with DateTimeFormatter.ISO_OFFSET_DATE_TIME. You can use java.time API to get the day of the month as shown below:
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
String dateTimeStr = "2020-06-13T16:21:15.239920+02:00";
OffsetDateTime odt = OffsetDateTime.parse(dateTimeStr);
int day = odt.getDayOfMonth();
System.out.println(day);
}
}
Output:
13
If you can not use Java SE 8 Date and Time, check ThreeTenABP and also How to use ThreeTenABP in Android Project.
Its always a bad idea to split a string and extract data becuase the string will change to some other value once the date , month or any part of the date string changes and the string indexing will change
So use DateTimeFormatter
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class SDF {
public static void main(String[] args) {
final TemporalAccessor parse = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSxxx")
.parse("2020-06-13T16:21:15.239920+02:00");
int dayOfMonth = MonthDay.from(parse).getDayOfMonth();
System.out.println(dayOfMonth);
}
}
There should be a method getDayOfMonth() available on this variable
private int parseDate(ZonedDateTime date) {
int day = date.getDayOfMonth();
return day;
}
You can use String split. Just take this whole format of date and put it into String and then create a new String Array String[] array= str.split("[-T]"); and then you can get result from array[2].
String str = "2020-06-13T16:21:15.239920+02:00";
String[] array= str.split("[-T]");
System.out.println("OUTPUT: " + array[2]);
Output: 13
String str = "2020-06-13T16:21:15.239920+02:00";
String substr = "";
// prints the substring after index 7(8 includes) till index 9(10 excludes)
substr = str.substring(8, 10);

Validating dates containing & or $ in Java

I was surprised to discover that certain characters embedded in a year (e.g. $ or &) will "successfully" parse when using DateFormat.parse() with DateFormat.SHORT. For example, "08/01/20&&" will parse into "Sat Aug 01 00:00:00 EDT 2020".
I was even more surprised that I could not find any hits googling the issue.
The exercise is to parse and validate a date. We could scan the string we are parsing for special characters, but this seems inelequent.
Does anyone have any suggestions?
public static void main(String[] args) {
String s = "08/01/20&&";
Date value = null;
try {
value = getDateFormat().parse(s);
} catch (ParseException pe) {
System.out.println("' must be a valid date in the form 'mm/dd/yyyy'");
}
System.out.println("Value:" + value);
}
public static DateFormat getDateFormat() {
DateFormat formatDate = null;
if (formatDate == null) {
formatDate = DateFormat.getDateInstance(DateFormat.SHORT);
//or at least in English locale
//formatDate = DateFormat.getDateInstance(DateFormat.SHORT,Locale.ENGLISH);
formatDate.setLenient(false);
}
return formatDate;
}
The DateFormat returned by DateFormat.getDateInstance is a SimpleDateFormat.
formatDate instanceof SimpleDateFormat => true
The pattern (in Locale.US) is M/d/yy according to the toPattern() method in SimpleDateFormat.
It appears that the parse method will not consider trailing text that extends beyond the date pattern. The following values for s will produce Sat Aug 01 00:00:00 PDT 2020 without an exception being thrown. The 20 is interpreted to be 2020 for the format characters yy, and the trailing text appears to be ignored.
"08/01/20"
"08/01/20&&"
"08/01/20**"
"08/01/20..."
"08/01/20ABCDEFGHIJKLMNOPQRSTUVWXYZ"
The Javadocs for DateFormat.parse state:
Parses text from the beginning of the given string to produce a date. The method may not use the entire text of the given string.
It certainly isn't parsing the entire string. Also, there is nothing special about the & characters you've used, apart from the fact that they're extraneous.
You could get the length of the pattern, then compare it to the length of the inputted string to see if there are extraneous characters. This would work for DateFormat.SHORT, because the expected number of characters would be a maximum of 8.
java.time
With the release of Java SE 8 in March 2014, the outdated and error-prone legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) was supplanted by java.time, the modern date-time API* and it is strongly recommended to switch to this new API.
With the modern API, you would not have faced this problem e.g.
With valid date:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String s = "08/01/20";
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
System.out.println(LocalDate.parse(s, dtf));
}
}
Output:
2020-08-01
With invalid date:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String s = "08/01/20&&";
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
System.out.println(LocalDate.parse(s, dtf));
}
}
Output:
Exception in thread "main" java.time.format.DateTimeParseException:
Text '08/01/20&&' could not be parsed, unparsed text found at index 8
What if I want the modern API to behave in the way SimpleDateFormat behaves by default w.r.t. the following rule:
Parses text from the beginning of the given string to produce a date.
The method may not use the entire text of the given string.
If you need it, DateTimeFormatter#parse(CharSequence, ParsePosition) is at your disposal:
import java.text.ParsePosition;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String s = "08/01/20&&";
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).localizedBy(Locale.ENGLISH);
LocalDate date = LocalDate.from(dtf.parse(s, new ParsePosition(0)));
System.out.println(date);
}
}
Output:
2020-08-01
Learn more about java.time, the modern date-time API* from Trail: Date Time.
Just for the sake of completeness:
Here is what you could have done using the legacy API.
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
String s = "08/01/20&&";
ParsePosition pp = new ParsePosition(0);
Date value = DateFormat.getDateInstance(DateFormat.SHORT, Locale.ENGLISH).parse(s, pp);
if (value == null || pp.getIndex() != s.length()) {
System.out.println("The input must be a valid date in the form MM/dd/yyyy");
} else {
System.out.println("Value: " + value);
}
}
}
Output:
The input must be a valid date in the form MM/dd/yyyy
ParsePosition#getIndex returns the index of the character following the last character parsed, which is the index of the first & in the string, 08/01/20&&.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Java SimpleDateFormat decrementing date by one day

I am trying to reformat a date string using sdf. SDF is decrementing the date by a day. Pointers would be helpful.
java version "1.8.0_31"
Input: ChangeDateStringFormat("10-Mar-2015");
Code:
public static String ChangeDateStringFormat (String Input) throws InterruptedException
{
System.out.print("Input Date inside ChangeDateStringFormat : " + Input );
SimpleDateFormat sdf = new SimpleDateFormat("MMM-dd-yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("MST"));
System.out.print(" || Output Date inside ChangeDateStringFormat : " + sdf.format(new Date(Input)) + "\n");
return sdf.format(new Date(Input));
}
Output Actual:
Input Date inside ChangeDateStringFormat : 10-Mar-2015 || Output Date inside ChangeDateStringFormat : Mar-09-2015
Output I was Expecting :
Input Date inside ChangeDateStringFormat : 10-Mar-2015 || Output Date inside ChangeDateStringFormat : Mar-10-2015
This is the problem:
new Date(Input)
You should not use that. Instead, construct a SimpleDateFormat to parse your input:
import java.text.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws ParseException {
System.out.println(convertDateFormat("10-Mar-2015"));
}
public static String convertDateFormat(String input) throws ParseException {
TimeZone zone = TimeZone.getTimeZone("MST");
SimpleDateFormat inputFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
inputFormat.setTimeZone(zone);
SimpleDateFormat outputFormat = new SimpleDateFormat("MMM-dd-yyyy", Locale.US);
outputFormat.setTimeZone(zone);
Date date = inputFormat.parse(input);
return outputFormat.format(date);
}
}
However:
If you're just parsing a date, you'd be better of specifying UTC as the time zone; you don't want to end up with problems due to time zones that switch DST at midnight
If you're going to run this code on Java 8 and nothing lower, I'd strongly recommend using java.time instead of Date, Calendar etc.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(changeDateStringFormat("10-Mar-2015"));
}
static String changeDateStringFormat(String input) {
DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("d-MMM-u", Locale.ENGLISH);
DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("MMM-dd-uuuu", Locale.ENGLISH);
LocalDate date = LocalDate.parse(input, dtfInput);
return date.format(dtfOutput);
}
}
Output:
Mar-10-2015
ONLINE DEMO
Note: Never use SimpleDateFormat or DateTimeFormatter without a Locale.
Learn more about the modern Date-Time API from Trail: Date Time.
Side Note: Always follow Java naming conventions e.g. the name of your function should be changeDateStringFormat instead of ChangeDateStringFormat and the parameter Input should be named as input.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Categories