Date time strings like "2018-04-01 10:00:00" can be used to create Date objects with this Kotlin code:
val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val d : Date = format.parse("2018-04-01 10:00:00") // works fine
But how to parse date time strings with offsets like these:
2018-04-01 10:00:00+02 // GMT + 2 hours
2018-04-01 10:00:00+02:30 // GMT + 2 hours, 30 minutes
2018-04-01 10:00:00+0230 // GMT + 2 hours, 30 minutes
Java 8: Instant is not an option.
edit:
I've tried the suggestion and used 'x', 'X', 'z' and 'Z', 'XXX' with and without leading space. Compiles fine. The x-versions crashes when SimpleDateFormat is instantiated - seems unsupported in the used android api level:
// java.lang.IllegalArgumentException: Unknown pattern character 'X'
var formatter3 = SimpleDateFormat("yyyy-MM-dd HH:mm:ssX")
// java.lang.IllegalArgumentException: Unknown pattern character 'x'
var formatter4 = SimpleDateFormat("yyyy-MM-dd HH:mm:ssx")
// java.lang.IllegalArgumentException: Unknown pattern character 'x'
var formatter5 = SimpleDateFormat("yyyy-MM-dd HH:mm:ss x")
The z-versions:
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ")
or
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ssz")
val date = formatter.parse("2018-04-24 17:33:02+02")
seems to work.
#Andreas: Date Time parsing is a pain in the ass. Instead of downvoting the question, a simple line of code would have been more helpful
Time zones can be parsed with Z (RFC 822) or X (ISO 8601), see https://developer.android.com/reference/java/text/SimpleDateFormat
Related
I have three date formats: YYYY-MM-DD, DDMMYYYY, MMDDYYYY this is how I pass date format in Spark to parse.
scala> val formatter = DateTimeFormatter.ofPattern("[MMddyyyy][yyyy-MM-dd][yyyyMMdd]")
formatter: java.time.format.DateTimeFormatter = [Value(MonthOfYear,2)Value(DayOfMonth,2)Value(YearOfEra,4,19,EXCEEDS_PAD)][Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)][Value(YearOfEra,4,19,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)]
For format MMddyyyy it's working
scala> LocalDate.parse("10062019",formatter)
res2: java.time.LocalDate = 2019-10-06
For format yyyyMMdd it's working
scala> LocalDate.parse("2019-06-20",formatter)
res3: java.time.LocalDate = 2019-06-20
For format yyyyMMdd, it's giving me an error
scala> LocalDate.parse("20190529",formatter)
java.time.format.DateTimeParseException: Text '20190529' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 20
at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
at java.time.LocalDate.parse(LocalDate.java:400)
... 66 elided
Caused by: java.time.DateTimeException: Invalid value for MonthOfYear (valid values 1 - 12): 20
at java.time.temporal.ValueRange.checkValidIntValue(ValueRange.java:330)
at java.time.temporal.ChronoField.checkValidIntValue(ChronoField.java:722)
at java.time.chrono.IsoChronology.resolveYMD(IsoChronology.java:550)
at java.time.chrono.IsoChronology.resolveYMD(IsoChronology.java:123)
at java.time.chrono.AbstractChronology.resolveDate(AbstractChronology.java:472)
at java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:492)
at java.time.chrono.IsoChronology.resolveDate(IsoChronology.java:123)
at java.time.format.Parsed.resolveDateFields(Parsed.java:351)
at java.time.format.Parsed.resolveFields(Parsed.java:257)
at java.time.format.Parsed.resolve(Parsed.java:244)
at java.time.format.DateTimeParseContext.toResolved(DateTimeParseContext.java:331)
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1955)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
... 67 more
If I pass 2 format yyyyMMdd, yyyy-MM-dd it's working fine
scala> val formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyyMMdd]")
scala> LocalDate.parse("20190529",formatter)
res5: java.time.LocalDate = 2019-05-29
scala> LocalDate.parse("2019-06-20",formatter)
res6: java.time.LocalDate = 2019-06-20
Same as yyyy-MM-dd, mmddyyy date format
scala> val formatter = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MMddyyyy]")
scala> LocalDate.parse("10062019",formatter)
res7: java.time.LocalDate = 2019-10-06
scala> LocalDate.parse("2019-06-20",formatter)
res8: java.time.LocalDate = 2019-06-20
Is there any way that I can pass three different formats?
Java's own DateTimeFormatterBuilder#appendOptional can handle it without without relying on exception handling. From the documentation:
The formatter will format if data is available for all the fields contained within it. The formatter will parse if the string matches, otherwise no error is returned.
Which means you will not have to handle the multiple cases with exceptions.
Here is an example from a real code-base where I had to do this handling:
def dtf: DateTimeFormatter =
new DateTimeFormatterBuilder()
.appendOptional(DateTimeFormatter.ofPattern("dd/MM/yy"))
.appendOptional(DateTimeFormatter.ofPattern("dd/MM/yyyy"))
.toFormatter()
Here are two unit tests (in ScalaTest) demonstrating the usage:
"Short form is parsed" in {
assert(LocalDate.parse("28/08/20", dtf) == LocalDate.of(2020, 8, 28))
}
"Long form is parsed" in {
assert(LocalDate.parse("02/10/2020", dtf) == LocalDate.of(2020, 10, 2))
}
You can´t have in the formatter [yyyyMMdd] and [MMddyyyy] at the same time.
My idea is to normalize so you have [yyyy-MM-dd] and [MM-dd-yyyy], instead of 3 formats .
Hope this helped
Edited:
If you don´t have a chance you can do something like this, but it´s not very pretty.
val formatter1 = DateTimeFormatter.ofPattern("[yyyy-MM-dd][MMddyyyy]")
val formatter2 = DateTimeFormatter.ofPattern("[yyyy-MM-dd][yyyyMMdd]")
val time = "20190529"
if (time.matches("2+\\d*")) LocalDate.parse(time,formatter2) else
LocalDate.parse(time,formatter1)
With only the information in the question this is not possible. The string 10111213 could denote December 13, 1011 or October 11, 1213. However, assuming that your dates are always after year 1300, you’re lucky because then the YYYY part of the string cannot be parsed as MMDD becuase the month will be 13 or greater, that is, not valid. You can use this for deciding which of the formats is the correct one to use.
I would use three formatters and try them in turn:
private static final DateTimeFormatter[] DATE_FORMATTERS = {
DateTimeFormatter.ofPattern("uuuuMMdd"),
DateTimeFormatter.ofPattern("MMdduuuu"),
DateTimeFormatter.ofPattern("uuuu-MM-dd")
};
With these just do:
String dateString = "20190529";
LocalDate result = null;
for (DateTimeFormatter df : DATE_FORMATTERS) {
try {
result = LocalDate.parse(dateString, df);
break;
} catch (DateTimeParseException dtpe) {
// Ignore; try next formatter
}
}
System.out.println("" + dateString + " was parsed to " + result);
Output is:
20190529 was parsed to 2019-05-29
Let’s try the two other formats too:
10062019 was parsed to 2019-10-06
2019-06-20 was parsed to 2019-06-20
I recommend you add a null check to catch any unparseable date string and a range check on the parsed date so that 10111213 doesn’t slip through as valid. For example:
if (result == null) {
System.out.println(dateString + " could not be parsed");
}
else if (result.isBefore(LocalDate.now(ZoneId.of("Asia/Aden")))) {
System.out.println("Date should be in the future, was " + result);
}
PS I assume a typo in the first sentence of your question:
I have three date formats: YYYY-MM-DD, DDMMYYYY, MMDDYYYY this is how
I pass date format in Spark to parse.
The middle format should have been YYYYMMDD (otherwise you’ve got no chance).
I have date strings in various formats like Oct 10 11:05:03 or 12/12/2016 4:30 etc
If I do
// some code...
getDate("Oct 10 11:05:03", "MMM d HH:mm:ss");
// some code ...
The date gets parsed, but I am getting the year as 1970 (since the year is not specified in the string.) But I want the year as current year if year is not specidied. Same applies for all fields.
here is my getDate function:
public Date getDate(dateStr, pattern) {
SimpleDateFormat parser = new SimpleDateFormat(pattern);
Date date = parser.parse(myDate);
return date;
}
can anybody tell me how to do that inside getDate function (because I want a generic solution)?
Thanks in advance!
If you do not know the format in advance, you should list the actual formats you are expecting and then try to parse them. If one fails, try the next one.
Here is an example of how to fill in the default.
You'll end up with something like this:
DateTimeFormatter f = new DateTimeFormatterBuilder()
.appendPattern("ddMM")
.parseDefaulting(YEAR, currentYear)
.toFormatter();
LocalDate date = LocalDate.parse("yourstring", f);
Or even better, the abovementioned formatter class supports optional elements. Wrap the year specifier in square brackets and the element will be optional. You can then supply a default with parseDefaulting.
Here is an example:
String s1 = "Oct 5 11:05:03";
String s2 = "Oct 5 1996 13:51:56"; // Year supplied
String format = "MMM d [uuuu ]HH:mm:ss";
DateTimeFormatter f = new DateTimeFormatterBuilder()
.appendPattern(format)
.parseDefaulting(ChronoField.YEAR, Year.now().getValue())
.toFormatter(Locale.US);
System.out.println(LocalDate.parse(s1, f));
System.out.println(LocalDate.parse(s2, f));
Note: Dates and times are not easy. You should take into consideration that date interpreting is often locale-dependant and this sometimes leads to ambiguity. For example, the date string "05/12/2018" means the 12th of May, 2018 when you are American, but in some European areas it means the 5th of December 2018. You need to be aware of that.
One option would be to concatenate the current year onto the incoming date string, and then parse:
String ts = "Oct 10 11:05:03";
int currYear = Calendar.getInstance().get(Calendar.YEAR);
ts = String.valueOf(currYear) + " " + ts;
Date date = getDate(ts, "yyyy MMM d HH:mm:ss");
System.out.println(date);
Wed Oct 10 11:05:03 CEST 2018
Demo
Note that we could have used StringBuilder above, but the purpose of brevity of code, I used raw string concatenations instead. I also fixed a few typos in your helper method getDate().
I'm trying to use Java 8 to re-format today's date but I'm getting the following error:
java.time.format.DateTimeParseException: Text '09-OCT-2017' could not be parsed:
Unable to obtain LocalDate from TemporalAccessor:
{WeekBasedYear[WeekFields[SUNDAY,1]]=2017, MonthOfYear=10, DayOfYear=9},ISO of type java.time.format.Parsed
Code:
public static String formatDate(String inputDate, String inputDateFormat, String returnDateFormat){
try {
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern(inputDateFormat).toFormatter(Locale.ENGLISH);
LocalDate localDate = LocalDate.parse(inputDate, inputFormatter);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(returnDateFormat);
String formattedString = localDate.format(outputFormatter);
return formattedString;
} catch (DateTimeParseException dtpe) {
log.error("A DateTimeParseException exception occured parsing the inputDate : " + inputDate + " and converting it to a " + returnDateFormat + " format. Exception is : " + dtpe);
}
return null;
}
I previously tried using SimpleDateFormat, but the problem is my inputDateFormat format is always in uppercase DD-MMM-YYYY, which was giving me incorrect results, so I tried using parseCaseInsensitive() to ignore the case sensitivity.
In the comments you told that the input format is DD-MMM-YYYY. According to javadoc, uppercase DD is the day of year field, and YYYY is the week based year field (which might be different from the year field).
You need to change them to lowercase dd (day of month) and yyyy (year of era). The parseCaseInsensitive() only takes care of the text fields - in this case, the month name (numbers are not affected by the case sensitivity - just because the month is in uppercase, it doesn't mean that the numbers patterns should also be).
The rest of the code is correct. Example (changing the format to yyyyMMdd):
String inputDate = "09-OCT-2017";
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
// use "dd" for day of month and "yyyy" for year
.appendPattern("dd-MMM-yyyy")
.toFormatter(Locale.ENGLISH);
LocalDate localDate = LocalDate.parse(inputDate, inputFormatter);
// use "dd" for day of month and "yyyy" for year
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String formattedString = localDate.format(outputFormatter);
System.out.println(formattedString); // 20171009
The output of the code above is:
20171009
Regarding your other comment about not having control over the input pattern, one alternative is to manually replace the letters to their lowercase version:
String pattern = "DD-MMM-YYYY";
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
// replace DD and YYYY with the lowercase versions
.appendPattern(pattern.replace("DD", "dd").replaceAll("YYYY", "yyyy"))
.toFormatter(Locale.ENGLISH);
// do the same for output format if needed
I don't think it needs a complex-replace-everything-in-one-step regex. Just calling the replace method multiple times can do the trick (unless you have really complex patterns that would require lots of different and complex calls to replace, but with only the cases you provided, that'll be enough).
I hope I got you right.
Formatting a String to LocalDate is acutally pretty simple. Your date format is that here right 09-Oct-2017?
Now you just need use the split command to divide that into a day, month and year:
String[] tempStr = inputDate.split("-");
int year = Integer.parseInt(tempStr[2]);
int month = Integer.parseInt(tempStr[1]);
int day = Integer.parseInt(tempStr[0]);
After that it´s pretty easy to get that to LocalDate:
LocalDate ld = LocalDate.of(year, month, day);
I hope that helps.
I am working on a Streaming Android application which I have to convert some php codes to java.
How can I convert this date format from php to java?
$today = gmdate("n/j/Y g:i:s A");
This date format in php is interpreted like this:
n: Numeric representation of a month, without leading zeros
j: Day of the month without leading zeros
Y: A full numeric representation of a year, 4 digits
g: 12-hour format of an hour without leading zeros
i: Minutes with leading zeros
s: Seconds, with leading zeros
A: Uppercase Ante meridiem and Post meridiem - AM/PM
and the same date format in java is like this:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("M/d/yyyy h:mm:ss a");
String today = simpleDateFormat.format(new Date());
To get a new java.util.Date object from your PHP date string, in Java:
String phpDateString = "7/24/2016 12:21:44 am";
SimpleDateFormat sdf = new SimpleDateFormat("M/d/yyyy h:mm:ss a");
Date javaDate = sdf.parse(phpDateString);
System.out.println(javaDate);
System.out.println(sdf.format(javaDate));
Output:
Sun Jul 24 00:21:44 CEST 2016
7/24/2016 12:21:44 AM
OP's self-answer was very informative, but it had an error in the Java expression (it's lowercase h for am/pm hours) and didn't include code to actually parse the PHP string into a Java Date object, which was the original question.
This question already has answers here:
Java program to get the current date without timestamp
(17 answers)
Closed 6 years ago.
I want to create a Date object without a TimeZone (eg : 2007-06-21). Is this possible?
When I use the following method it prints like Thu Jun 21 00:00:00 GMT 2007
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
TimeZone timeZone = TimeZone.getTimeZone("GMT");
timeZone.setDefault(timeZone);
sdf.setTimeZone(timeZone);
Date pickUpDate = sdf.parse("2007-06-21");
System.out.println(pickUpDate);
If you want to format a date, you need to use DateFormat or something similar. A Date is just an instant in time - the number of milliseconds since the Unix epoch. It doesn't have any idea of time zone, calendar system or format. The toString() method always uses the system local time zone, and always formats it in a default way. From the documentation:
Converts this Date object to a String of the form:
dow mon dd hh:mm:ss zzz yyyy
So it's behaving exactly as documented.
You've already got a DateFormat with the right format, so you just need to call format on it:
System.out.println("pickUpDate" + sdf.format(pickUpDate));
Of course it doesn't make much sense in your sample, given that you've only just parsed it - but presumably you'd normally be passing the date around first.
Note that if this is for interaction with a database, it would be better not to pass it as a string at all. Keep the value in a "native" representation for as much of the time as possible, and use something like PreparedStatement.setDate to pass it to the database.
As an aside, if you can possibly change to use Joda Time or the new date/time API in Java 8 (java.time.*) you'll have a much smoother time of it with anything date/time-related. The Date/Calendar API is truly dreadful.
This is the toString() of the java.util.Date
public String toString() {
// "EEE MMM dd HH:mm:ss zzz yyyy";
BaseCalendar.Date date = normalize();
StringBuilder sb = new StringBuilder(28);
int index = date.getDayOfWeek();
if (index == gcal.SUNDAY) {
index = 8;
}
convertToAbbr(sb, wtb[index]).append(' '); // EEE
convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
TimeZone zi = date.getZone();
if (zi != null) {
sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
} else {
sb.append("GMT");
}
sb.append(' ').append(date.getYear()); // yyyy
return sb.toString();
}
So, if you will pass a Date and try to print it this will be printed out all the time.
Code:
Date date = new Date();
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(date));
Date : Fri Apr 29 04:53:16 GMT 2016
Sample Output : 2016-04-29
Imports required :
import java.util.Date; //for new Date()
import java.text.SimpleDateFormat; // for the format change
System.out.println("pickUpDate " + sdf.format(pickUpDate));
You can use the above code to get formatted Date as String
Use this Code:
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd");
Date pickUpDate =sdf.parse("2007-06-21");
System.out.println("pickUpDate "+sdf.format(pickUpDate));
Hope it'll help you.
String your_format_date=sdf.format(pickUpDate);
System.out.println("pick Up Date " + your_format_date);
Date isn't a date. It's a timestamp. That's some impressive API design, isn't it?
The type you need is now java.time.LocalDate, added in Java 8.
If you can't use Java 8, you can use ThreeTen, a backport for Java 7.