SimpleDateFormat showing inconsistent results - java

val dateStr = "2020 10 12 23 12 13"
val dateFormat = "yyyyMMddHHmmss"
import java.util.Date
val sdf = new SimpleDateFormat(dateFormat)
sdf.setLenient(false)
val res = sdf.parse(dateStr)
println("res = "+res)
scala> val res = sdf.parse(dateStr)
java.text.ParseException: Unparseable date: "2020 10 12 23 12 13"
at java.text.DateFormat.parse(DateFormat.java:366)
... 50 elided
The above code block parses and results in an exception, but if i change the "MM" part to "11" instead of "10" then it parses fine, without any exception , but with a wrong date. Any idea why is that ?
I want the code to fail or throw an exception if my date String is not in this format "yyyyMMddHHmmss"
/*Note the 11 instead of 10*/
val dateStr = "2020 11 12 23 12 13"
val dateFormat = "yyyyMMddHHmmss"
import java.util.Date
val sdf = new SimpleDateFormat(dateFormat)
sdf.setLenient(false)
val res = sdf.parse(dateStr)
println("res = "+res)
scala> val res = sdf.parse(dateStr)
res: java.util.Date = Wed Jan 01 01:02:23 PST 2020

SimpleDateFormat is simply too lenient for what you want.
It's parsing your date as:
2020 yyyy
_1 MM (where _ represents a space)
1 dd
_1 HH
2 mm
23 seconds
12 13 ignored
So I think the best way around it for you would be to bite the bullet and forbid spaces.
So try something like trimming the string and then searching for spaces in the middle. If you find spaces, throw an Exception.
But ultimately its probably better to drop SimpleDateFormat and use the new stuff. I think the new DateTimeFormatter class will serve you better:
// In Java
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
LocalDateTime date = LocalDateTime.parse(dateStr, formatter);
System.out.println("date="+date);
This throws and exception.
In Scala:
val formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
val date = LocalDateTime.parse(dateStr, formatter);
println("date="+date);

The Answer by Ruokki is correct, your formatting pattern does not match your input data.
java.time
More importantly, you are using the wrong classes. The date-time classes bundled with the earliest versions of Java are terrible. They were years ago supplanted by the modern java.time classes defined in JSR 310.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu MM dd HH mm ss" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
To detect faulty inputs, trap for the DateTimeParseException.
try
{
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
}
catch ( DateTimeParseException e )
{
…
}
ResolverStyle
The DateTimeFormatter uses one of three different approaches in parsing: strict, smart and lenient. These are represented by the ResolverStyle enum. SMART is used by default, but you can specify STRICT if that better suits your needs.
ISO 8601
I suggest you educate the publisher of your input data about ISO 8601. That standard defines formats for exchanging date-time values textually.
The java.time classes use ISO 8601 formats by default when parsing/generating strings. So no need to define a formatting pattern for compliant inputs.

Hello I think the problem is the date format:
val dateFormat = "yyyyMMddHHmmss"
And should be
val dateFormat = "yyyy MM dd HH mm ss"
Because your dateStr contains some space who play a important part in the format
But if you want to fail in case you have space or other thing unwanted in the date maybe a regex is the best answer ?

Related

How to change Timestamp String to "DD.MM.YYYY"?

I need a different format of strings to convert to "DD.MM.YYYY".
"Thu, 3 Nov 2022 06:00:00 +0100" has to be changed to "03.11.2022"
and
"01.11.2022 20:00:00" to "01.11.2022".
All the formats are in String.
I tried doing
String pattern="DD.MM.YYYY";
DateTimeFormatter formatter=DateTimeFormatter.ofPattern(pattern);
new SimpleDateFormat(pattern).parse("01.11.2022 20:00:00")
I have also tried doing the following
java.time.LocalDateTime.parse(
item.getStartdatum(),
DateTimeFormatter.ofPattern( "DDMMYYYY" )
).format(
DateTimeFormatter.ofPattern("DD.MM.YYYY")
)
But got the error :
Exception in thread "main" java.time.format.DateTimeParseException:
Text 'Sun, 30 Oct 2022 00:30:00 +0200' could not be parsed at index 0
I tried doing the following as well
String pattern="DD.MM.YYYY";
DateFormat format = new SimpleDateFormat(pattern);
Date date = format.parse(01.11.2022 20:00:00);
However, I am not getting the correct output. How can I get my desired result?
Several things…
if you can use java.time, use it exclusively if possible (no SimpleDateFormat or similar legacy stuff)
a DateTimeFormatter can be used to parse and format Strings representing a datetime, if input and output format are different, you will need two different DateTimeFormatters
the Text 'Sun, 30 Oct 2022 00:30:00 +0200' could not be parsed at index 0 due to your try to parse it with the pattern "DD.MM.YYYY", which is wrong on several levels:
the pattern seems to expect the String to start with a numerical representation of the day of month, but it starts with Thu, an abbreviation of the name of a day of week
the symbol D means day of year, a number between 1 and 366 (in leap years, 365 otherwise)
the symbol Y means week-based year
Read more about those symbols in the JavaDocs of DateTimeFormatter
You could do the following instead:
public static void main(String[] args) {
// two example inputs
String first = "Thu, 3 Nov 2022 06:00:00 +0100";
String second = "01.11.2022 20:00:00";
// prepare a formatter for each pattern in order to parse the Strings
DateTimeFormatter dtfInFirst = DateTimeFormatter.ofPattern(
"EEE, d MMM uuuu HH:mm:ss x",
Locale.ENGLISH
);
// (second one does not have an offset from UTC, so the resulting class is different)
DateTimeFormatter dtfInSecond = DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss");
// parse the Strings using the formatters
OffsetDateTime odt = OffsetDateTime.parse(first, dtfInFirst);
LocalDateTime ldt = LocalDateTime.parse(second, dtfInSecond);
// prepare a formatter, this time for output formatting
DateTimeFormatter dtfDateOnlySeparatedByDots = DateTimeFormatter.ofPattern("dd.MM.uuuu");
// extract the date part of each result of the parsing
LocalDate firstResult = odt.toLocalDate();
LocalDate secondResult = ldt.toLocalDate();
// and print it formatted using the output formatter
System.out.println(first + " ---> "
+ firstResult.format(dtfDateOnlySeparatedByDots));
System.out.println(second + " ---> "
+ secondResult.format(dtfDateOnlySeparatedByDots));
}
Which will output the conversion results as follows:
Thu, 3 Nov 2022 06:00:00 +0100 ---> 03.11.2022
01.11.2022 20:00:00 ---> 01.11.2022
The first formatter will need a Locale because of the presence of names (day of week & month). You cannot parse that using any exclusively numerical parser and the language / culture must match.<
short version
public static void main(String[] args) {
// two example inputs
String first = "Thu, 3 Nov 2022 06:00:00 +0100";
String second = "01.11.2022 20:00:00";
// prepare a custom formatter for the second pattern
DateTimeFormatter dtfInSecond = DateTimeFormatter
.ofPattern("dd.MM.uuuu HH:mm:ss");
// parse the first String by means of a built-in RFC formatter
OffsetDateTime odt = OffsetDateTime.parse(
first,
DateTimeFormatter.RFC_1123_DATE_TIME);
// parse the second String using the custom formatter
LocalDateTime ldt = LocalDateTime.parse(second, dtfInSecond);
// prepare a formatter, this time for output formatting
DateTimeFormatter dtfDateOnlySeparatedByDots = DateTimeFormatter
.ofPattern("dd.MM.uuuu");
// and print it formatted using the output formatter
System.out.println(first + " ---> "
+ odt.format(dtfDateOnlySeparatedByDots));
System.out.println(second + " ---> "
+ ldt.format(dtfDateOnlySeparatedByDots));
}
HINT:
For dates like the one mentioned in your comment…
Text '9.28.2022 6:30:00' could not be parsed at index 0
you will have to use a pattern with single-digit day of month and hour of day, probably even month of year if anything like 9.8.2022 is possible. However, you will definitely need to switch day of month and month of year because there is just no month no. 28 in a year.
Short example:
String third = "9.28.2022 6:30:00";
DateTimeFormatter dtfInThird = DateTimeFormatter
.ofPattern("M.d.uuuu H:mm:ss");
LocalDateTime ldtThird = LocalDateTime.parse(third, dtfInThird);
System.out.println(third + " ---> "
+ ldtThird.format(dtfDateOnlySeparatedByDots));
Executed in a main, this will output
9.28.2022 6:30:00 ---> 28.09.2022
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.
deHaar has already written a good answer. However, if you want to use a single DateTimeFormatter, you can check this answer.
For parsing, you can build a DateTimeFormatter with optional patterns and default time-zone offset value (since you do not have time-zone offset in the second date-time string) as follows:
DateTimeFormatter parser = new DateTimeFormatterBuilder()
.appendPattern("[d.M.uuuu H:m:s][EEE, d MMM uuuu H:m:s X]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter(Locale.ENGLISH);
where the optional patterns are in square brackets. Alternatively, you can use DateTimeFormatterBuilder#optionalStart and DateTimeFormatterBuilder#optionalEnd to specify optional patterns.
With this parser, you can parse the given date-time strings to OffsetDateTime and format it to the desired string using the following DateTimeFormatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.ENGLISH);
Demo:
public class Main {
public static void main(String[] args) {
DateTimeFormatter parser = new DateTimeFormatterBuilder()
.appendPattern("[d.M.uuuu H:m:s][EEE, d MMM uuuu H:m:s X]")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter(Locale.ENGLISH);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.uuuu", Locale.ENGLISH);
// Test
Stream.of(
"Thu, 3 Nov 2022 06:00:00 +0100",
"01.11.2022 20:00:00"
)
.map(s -> OffsetDateTime.parse(s, parser).format(formatter).toString())
.forEach(System.out::println);
;
}
}
Output:
03.11.2022
01.11.2022
Note
Make sure to check the DateTimeFormatter documentation to understand the difference between Y and y and between D and d.
You can use y instead of u but I prefer u to y with DateTimeFormatter.
Learn more about the modern Date-Time API from Trail: Date Time.

How to parse a UTC offset dateformat string into the resulting date separated by | symbol

I have a very peculiar question where I am trying to parse "2019-12-25T17:00:00-05:00"
such that it should give me the result DEC 12 | Thursday | 5:00pm
I tried the following code by using DateTimeFormatter and LocalDate
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssz", Locale.US);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MM d | E | hh:mm a", Locale.US);
LocalDate date = LocalDate.parse("2019-12-25T17:00:00-05:00", inputFormatter);
String formattedDate = outputFormatter.format(date);
contentTextView.setText(formattedDate);
but it crashes with DateTimeParseException: Text '2019-12-25T17:00:00-05:00' could not be parsed at index 19
Any idea why it's crashing and if my output will render the expected result?
Thanks!
Your String 2019-12-25T17:00:00-05:00 represents UTC timezone with offset UTC offset, so use OffsetDateTime for parsing that string
OffsetDateTime odt = OffsetDateTime.parse("2019-12-25T17:00:00-05:00");
System.out.println(odt.format(DateTimeFormatter.ofPattern("MMM d | E | hh:mm a", Locale.US)));
If you want to set particular time zone you can use atZoneSameInstant to pass ZoneId for eaxmple
ZoneId zone = ZoneId.of("America/Chicago");
ZonedDateTime zdt = odt.atZoneSameInstant(zone);
A way to format uppercase DEC and lowercase pm
I’m just giving a small supplement to #Deadpool’s good answer. A way of getting the month abbreviation in all caps like DEC and am/pm in lowercase is a DateTimeFormatterBuilder and its two-arg appendText​(TemporalField, Map<Long,String>) method.
Locale userLocale = Locale.US;
Map<Long, String> monthNames = new HashMap<>();
for (Month m : Month.values()) {
monthNames.put(Long.valueOf(m.getValue()),
m.getDisplayName(TextStyle.SHORT, userLocale).toUpperCase(userLocale));
}
Map<Long, String> amPmNames = new HashMap<>(3);
amPmNames.put(0L, "am");
amPmNames.put(1L, "pm");
DateTimeFormatter outputFormatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.MONTH_OF_YEAR, monthNames)
.appendPattern(" d | E | hh:mm ")
.appendText(ChronoField.AMPM_OF_DAY, amPmNames)
.toFormatter(userLocale);
OffsetDateTime odt = OffsetDateTime.parse("2019-12-25T17:00:00-05:00");
String formattedDate = odt.format(outputFormatter);
System.out.println(formattedDate);
Output:
DEC 25 | Wed | 05:00 pm
I have assumed that you are programming for Android under API level 26 and using ThreeTenABP, so I have tested on my desktop Java 7 with ThreeTen Backport. From Java 8 and on newer API levels and even more from Java 9 more elegant ways to populate the two maps exist.
What went wrong in your code?
The lowercase z that comes last in your format pattern string matches a time zone name. The documentation gives examples Pacific Standard Time and PST. It doesn’t match an offset like -05:00. If you ever need a format pattern letter for this, use x, X or uppercase Z (they are different and all well documented). However, as already shown in Deadpool’s answer, you need no explicit formatter and no format pattern string in this case.
Another issue in your code: The LocalDate class that you used in the question is a date without time of day. You can parse your string into a LocalDate, but the time of day and offset get lost. Hence you cannot format the LocalDate into a string that contains time of day. For that you need a class that has DateTime in its name, for example OffsetDateTime used in the two answers.
Link
DateTimeFormatter documentation spelling out all the possible format pattern letters.

DateTimeFormatter could not be parsed using "HH:mm E d MMM YYYY" pattern

I am retrieving a date/time from an external data source, this is returned in the following format "14:30 Sat 05 May" with no year.
I've been trying to parse this to a LocalDateTime unsuccessfully. The data returned does not return a year as it is an assumption that we are always operating in the current year.
//date to parse
String time = "14:30 Sat 05 May";
//specify date format matching above string
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm E d MMM YYYY") ;
//we do not have a year returned but i can make the assumption we use the current year
LocalDateTime formatDateTime = LocalDateTime.parse(time, formatter).withYear(2018);
The above code throws the following exception
Exception in thread "main" java.time.format.DateTimeParseException: Text '14:30 Sat 05 May' could not be parsed at index 16
Any help appreciated.
Default year
Specify a default year in your DateTimeFormatter, using the DateTimeFormatterBuilder class by calling parseDefaulting and specifying the year-field with ChronoField.YEAR.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("HH:mm E d MMM")
.parseDefaulting(ChronoField.YEAR, 2018) // <------
.toFormatter(Locale.ENGLISH);
With this formatter instead of yours:
LocalDateTime.parse( "14:30 Sat 05 May" , formatter )
…I get:
2018-05-05T14:30
See that code run live at IdeOne.com.
Points to note:
Your format pattern string needs to match the parsed string end-to-end. So when your date-time string doesn’t have a year in it, don’t include YYYY in your format pattern.
In any case don’t use uppercase YYYY here. It’s for week-based year and only useful with week numbers. If your string had had a year in it, you should have used uuuu or lowercase yyyy.
Make it a habit to give explicit locale to your formatter so you know it also works on other computers, and on yours when one day you play with its settings.
LocalDateTime.parse() expects a String that represents a valid date, which the year part.
You cannot set the year after invoking this method in this way :
LocalDateTime.parse(time, formatter).withYear(2018);
The year has to be set before because otherwise parse() throws DateTimeParseException.
As a workaround you may concatenate the current year in the input.
Some additional notes:
the pattern you use and the input date in textual format don't match exactly.
You don't specify a Locale for the parsing operation.
It means that it will work according to the local where the JVM is run.
To ensure that it works in any case, you should specify the Locale.
So you could try something like :
//date to parse
String time = "14:30 Sat 05 May";
time += " " + LocalDate.now().getYear();
//specify date format matching above string
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm EEE dd MMM yyyy", Locale.US) ;
//we do not have a year returned but i can make the assumption we use the current year
LocalDateTime formatDateTime = LocalDateTime.parse(time, formatter);

Timestamp string to timestamp in java

I have the following string "2015-04-02 11:52:00+02" and I need to parse it in Java to a Timestamp.
I tried all sorts of formats including
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+Z");
but nothing seems to work - I keep getting a ParseException
Can anyone help?
I need something like:
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+Z");
Timestamp t = new Timestamp(mdyFormat.parse("2015-04-02 11:52:00+02").getTime());
Try This
String str="2009-12-31 23:59:59 +0100";
/\
||
Provide Space while providing timeZone
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
System.out.println(mdyFormat.parse(str));
Output
Fri Jan 01 04:29:59 IST 2010
java.sql.Timestamp objects don't have time zones - they are instants in time, like java.util.Date
So try this:
SimpleDateFormat mdyFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timestamp t = new Timestamp(mdyFormat.parse("2015-04-02 11:52:00").getTime());
try "yyyy-MM-dd HH:mm:ssX"
Z stand for timezone in the following format: +0800
X stand for timezone in the following format: +08
Examples here
ISO 8601
Replace that SPACE in the middle with a T and you have a valid standard (ISO 8601) string format that can be parsed directly by either the Joda-Time library or the new java.time package built into Java 8 (inspired by Joda-Time). Search StackOverflow for hundreds of examples.
If using java.time, read my comment on Question about a bug when parsing hours-only offset value.
Example in Joda-Time 2.7.
String inputRaw = "2015-04-02 11:52:00+02";
String input = inputRaw.replace( " ", "T" );
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ); // Specify desired time zone adjustment.
DateTime dateTime = new DateTime( input, zone );

How to parse a date? [duplicate]

This question already has answers here:
Java string to date conversion
(17 answers)
Closed 6 years ago.
I am trying to parse this date with SimpleDateFormat and it is not working:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Formaterclass {
public static void main(String[] args) throws ParseException{
String strDate = "Thu Jun 18 20:56:02 EDT 2009";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date dateStr = formatter.parse(strDate);
String formattedDate = formatter.format(dateStr);
System.out.println("yyyy-MM-dd date is ==>"+formattedDate);
Date date1 = formatter.parse(formattedDate);
formatter = new SimpleDateFormat("dd-MMM-yyyy");
formattedDate = formatter.format(date1);
System.out.println("dd-MMM-yyyy date is ==>"+formattedDate);
}
}
If I try this code with strDate="2008-10-14", I have a positive answer. What's the problem? How can I parse this format?
PS. I got this date from a jDatePicker and there is no instruction on how modify the date format I get when the user chooses a date.
You cannot expect to parse a date with a SimpleDateFormat that is set up with a different format.
To parse your "Thu Jun 18 20:56:02 EDT 2009" date string you need a SimpleDateFormat like this (roughly):
SimpleDateFormat parser=new SimpleDateFormat("EEE MMM d HH:mm:ss zzz yyyy");
Use this to parse the string into a Date, and then your other SimpleDateFormat to turn that Date into the format you want.
String input = "Thu Jun 18 20:56:02 EDT 2009";
SimpleDateFormat parser = new SimpleDateFormat("EEE MMM d HH:mm:ss zzz yyyy");
Date date = parser.parse(input);
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = formatter.format(date);
...
JavaDoc: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
The problem is that you have a date formatted like this:
Thu Jun 18 20:56:02 EDT 2009
But are using a SimpleDateFormat that is:
yyyy-MM-dd
The two formats don't agree. You need to construct a SimpleDateFormat that matches the layout of the string you're trying to parse into a Date. Lining things up to make it easy to see, you want a SimpleDateFormat like this:
EEE MMM dd HH:mm:ss zzz yyyy
Thu Jun 18 20:56:02 EDT 2009
Check the JavaDoc page I linked to and see how the characters are used.
We now have a more modern way to do this work.
java.time
The java.time framework is bundled with Java 8 and later. See Tutorial. These new classes are inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project. They are a vast improvement over the troublesome old classes, java.util.Date/.Calendar et al.
Note that the 3-4 letter codes like EDT are neither standardized nor unique. Avoid them whenever possible. Learn to use ISO 8601 standard formats instead. The java.time framework may take a stab at translating, but many of the commonly used codes have duplicate values.
By the way, note how java.time by default generates strings using the ISO 8601 formats but extended by appending the name of the time zone in brackets.
String input = "Thu Jun 18 20:56:02 EDT 2009";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE MMM d HH:mm:ss zzz yyyy" , Locale.ENGLISH );
ZonedDateTime zdt = formatter.parse ( input , ZonedDateTime :: from );
Dump to console.
System.out.println ( "zdt : " + zdt );
When run.
zdt : 2009-06-18T20:56:02-04:00[America/New_York]
Adjust Time Zone
For fun let's adjust to the India time zone.
ZonedDateTime zdtKolkata = zdt.withZoneSameInstant ( ZoneId.of ( "Asia/Kolkata" ) );
zdtKolkata : 2009-06-19T06:26:02+05:30[Asia/Kolkata]
Convert to j.u.Date
If you really need a java.util.Date object for use with classes not yet updated to the java.time types, convert. Note that you are losing the assigned time zone, but have the same moment automatically adjusted to UTC.
java.util.Date date = java.util.Date.from( zdt.toInstant() );
How about getSelectedDate? Anyway, specifically on your code question, the problem is with this line:
new SimpleDateFormat("yyyy-MM-dd");
The string that goes in the constructor has to match the format of the date. The documentation for how to do that is here. Looks like you need something close to "EEE MMM d HH:mm:ss zzz yyyy"
In response to:
"How to convert Tue Sep 13 2016 00:00:00 GMT-0500 (Hora de verano central (México)) to dd-MM-yy in Java?", it was marked how duplicate
Try this:
With java.util.Date, java.text.SimpleDateFormat, it's a simple solution.
public static void main(String[] args) throws ParseException {
String fecha = "Tue Sep 13 2016 00:00:00 GMT-0500 (Hora de verano central (México))";
Date f = new Date(fecha);
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("-5GMT"));
fecha = sdf.format(f);
System.out.println(fecha);
}

Categories