I want to parse LocalDateTime 2021-11-24T15:11:38.395 to LocalDateTime 2021-11-24T15:11:38.39. But LocalDateTime.parse() always adds zero in the end, ignoring my pattern.
public class DateTimeFormatUtils {
private static final String ISO_DATE_TIME = "yyyy-MM-dd'T'HH:mm:ss.SS";
public static LocalDateTime formatToISO(final LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ISO_DATE_TIME);
return LocalDateTime.parse(formatter.format(localDateTime), formatter);
}
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
System.out.println(formatToISO(now));
}
}
Output:
2021-11-30T11:48:28.449195200
2021-11-30T11:48:28.440
Is there way to deal with this problem?
Note that the strings "2021-11-24T15:11:38.39" and "2021-11-24T15:11:38.390" represent the same LocalDateTime. Technically, you've already got your expected output!
Since you say that the output is not what you expect, you are actually expecting a String as the output, since "2021-11-24T15:11:38.39" and "2021-11-24T15:11:38.390" are different strings. formatToISO should return a string - you should not parse the formatted date back to a LocalDateTime:
public static String formatToISO(final LocalDateTime localDateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ISO_DATE_TIME);
return formatter.format(localDateTime);
}
This is similar to the common mistake of beginners printing out doubles and expecting the specific format they have used to assign to the variable to come out.
double d = 5;
System.out.println(d); // expected 5, actual 5.0
LocalDateTime, just like double, doesn't store anything about how it should formatted. It just stores a value, and the same value will be formatted the same way.
Java fraction-of-seconds is always return 3 digits.
Work around is, first convert LocalDateTime to String, then remove last character of the string.
Off course, please validate null checks.
private static String removeLastDigit(String localDateTime) {
return localDateTime.substring(0, localDateTime.length()-1);
}
Related
I was writing some tests for some legacy code that validates a user's date of birth. I encounter the following method in the class. My doubt is that whether the if statement in the try block is necessary. From my understanding, if the parse function returns a LocalDate object successfully, then date.toString() should always equal to the input dobstr, and there's no need to do an additional check. Am I missing anything? I could not think of any case that we need this extra check. Please help. Thanks!
private LocalDate format(String dobStr) throws Exception {
LocalDate date = null;
try {
date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
if (!dobStr.equals(date.toString())) {
throw new DateTimeParseException("some message");
}
}
catch (DateTimeParseException ex) {
throw ex;
}
return date;
}
this is what I found in the source code for DateTimeFormatter.ISO_DATE
public static final DateTimeFormatter ISO_DATE;
static {
ISO_DATE = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.optionalStart()
.appendOffsetId()
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
The only reason that I could see for doing a toString() check would be to avoid lenient issue: the parser may be lenient and try to interpret wrong values (for example: 2020-12-32 could be interpreted as 2021-01-01).
DateFormat allows the parser to be lenient
The same behaviour is offered by DateTimeFormatter and the default value is ResolverStyle.SMART.
If you want to remove it, you should check if DateTimeFormatter.ISO_DATE is ResolverStyle.STRICT by default or not. Assuming it is not STRICT by default, your code could be:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE.withResolverStyle(ResolverStyle.STRICT));
}
TL;DR: The check makes a difference
If the string contains an unwanted offset ID, you will still be able to parse it using DateTimeFormatter.ISO_DATE. But since a LocalDate cannot have an offset (this is what local in the name means), the result of toString() will never have that offset ID, so the strings will not be equal.
DateTimeFormatter.ISO_DATE accepts an optional offset ID after the date. So if you are parsing 2020-08-12z or 2020-08-12+01:02:03, the custom exception would be thrown. Except for a detail: DateTimeParseException hasn’t got a constructor that matches a single string argument, so the code doesn’t compile. I reckon that this comes from sloppy copy-paste from the original code.
To demonstrate:
String dobStr = "2020-08-12+01:02:03";
LocalDate date = LocalDate.parse(dobStr, DateTimeFormatter.ISO_DATE);
String asStringAgain = date.toString();
System.out.format("Original string: %s; result of toString(): %s; equal? %s%n",
dobStr, asStringAgain, dobStr.equals(asStringAgain));
Output is:
Original string: 2020-08-12+01:02:03; result of toString():
2020-08-12; equal? false
How to obviate the check
Unless you require a custom exception in the case of an unwanted offset, the method may be written much more simply:
private LocalDate format(String dobStr) throws Exception {
return LocalDate.parse(dobStr, DateTimeFormatter.ISO_LOCAL_DATE);
}
DateTimeFormatter.ISO_LOCAL_DATE does not accept any offset in the string. And it is strict just like DateTimeFormatter.ISO_DATE, so we know that toString() would create the same string again.
Furthermore you may declare the method static, and you may leave out throws Exception since DateTimeParseException is an unchecked exception.
Link
Documentation of DateTimeFormatter.ISO_DATE
This is my first time looking into the Date Api's i don't understand where i'm going wrong. The Question has been commented out so you can see exactly whats expected.
Could someone please simply explain how to solve/approach this problem?
When i get to the DateUtil class>DayofTheWeek method i attempt to return the LocalDate.DayofTheWeek method using the theDate field which by now has been initialised. but it wont work. It keeps saying 'cannot resolve method'?
public class ChallengeThree {
public static String dayOfWeek(String date) {
/**
*** Returns a String storing the day of the week in all capital letters of the
* given date String
* Complete the implementation of the DateUtil class and use it in this function
* Arguments
* date - a String storing a local date, such as "2000-01-01"
* Examples
* dayOfWeek("2000-01-01") returns "SATURDAY"
*/**
// ====================================
// Do not change the code before this
// CODE1: Write code to return the day of the week of the String date
// using the DateUtil class at the bottom of this file
DateUtil newdates= new DateUtil("2000-01-01");
System.out.println(newdates.dayOfWeek());
// ====================================
// Do not change the code after this
}
// public static void main(String[] args) {
// String theDayOfWeek = dayOfWeek("2000-01-01");
String expected = "SATURDAY";
// Expected output is
// true
// System.out.println(theDayOfWeek == expected);
// }
}
class DateUtil {
LocalDate theDate;
public DateUtil(String date) {
/**
* Initialize the theDate field using the String date argument
* Arguments
* date - a String storing a local date, such as "2000-01-01"
*/
// ====================================
// Do not change the code before this
LocalDate theNewDate = LocalDate.parse(date);
this.theDate=theNewDate;
// ====================================
// Do not change the code after this
}
public String dayOfWeek() {
/**
* Return a String the day of the week represented by theDate
*/
// ====================================
// Do not chDate theDate = new ange the code before this
return LocalDate.of(theDate).getDayOfWeek();
// ====================================
// Do not change the code after this
}
}
You are making this much too complicated.
One problem is that you are thinking in text, using dumb strings rather than smart objects. Do not be passing around the string "2000-01-01", pass around a LocalDate object. Do not pass around the string SATURDAY, pass around the DayOfWeek.SATURDAY object.
LocalDate
.parse(
"2000-01-01"
)
.getDayOfWeek()
.equals(
DayOfWeek.SATURDAY
)
If you insist on using strings against my advice, you can get the name of the DayOfWeek enum object as text by calling toString.
String output = DayOfWeek.SATURDAY.toString() ;
Going the other direction, calling DayOfWeek.valueOf.
DayOfWeek dow = DayOfWeek.valueOf( "SATURDAY" ) ;
Edited
I made a small change in your code (it worked)
DateUtil
class DateUtil {
private LocalDate date;
public DateUtil(LocalDate date) {
this.date = date;
}
public String dayOfWeek() {
return String.valueOf(date.getDayOfWeek());
}
}
ChallengeThree
public class ChallengeThree {
public static void main(String[] args) {
String theDayOfWeek = dayOfWeek("2000-01-01");
System.out.println(theDayOfWeek);
}
public static String dayOfWeek(String date) {
LocalDate localDate = LocalDate.parse(date);
DateUtil dateUtil = new DateUtil(localDate);
return dateUtil.dayOfWeek();
}
}
The other answers are fine. I wanted to go closer to what you asked precisely:
It keeps saying 'cannot resolve method'?
As you have seen, the error message comes in this line:
return LocalDate.of(theDate).getDayOfWeek();
The method it cannot resolve is of(). LocalDate has a couple of overloaded of methods. theDate is already a LocalDate, and as MadProgrammer said in the comment, there is no of method accepting a LocalDate. This is the reason for the error message. BTW, the message I get in my Eclipse says “The method of(int, Month, int) in the type LocalDate is not applicable for the arguments (LocalDate)”.
Since theDate is already a LocalDate, you don’t need that method call at all. Just leave it out and call getDayOfWeek() on theDate directly (I am on purpose leaving to yourself to put it into code; you’re the one supposed to learn from doing this, so you should be the one doing it).
It seems that you are having another problem in that LocalDate.getDayOfWeek() returns a DayOfWeek and your DateUtil.dayOfWeek() is supposed to return a String. You can likely solve it yourself when you get around to it. If not, feel free to follow up in comments.
As a complete aside, for production code I would consider a DateUtil class for this purpose overkill. I understand that this is an assignment, so I have answered it being faithful to the assignment as given.
I am developing a multilingual Struts2 application, and I have quite a few actions which are dealing with Calendar properties. The default type conversion works most of the time, however in some locales I would like to change the default format used.
Specifically I would like to have the dates in English locale to follow the yyyy-MM-dd format. However, this does not work (strangely yyyy-MM-dd HH:mm works fine, but in this case I do not want to have a time part), as Struts2 expect dates in English locale to look different.
So, I would like to change the expected format of the conversion. I am looking for a sane solution for this. The options I have already tried:
A) Own StrutsTypeConverter. This should work, but I could not inject the format specified in the package.properties file into it.
B) Changing the getter/setter pair, to use String instead - works, but this is not a sane solution.
How to fix the solution A? Or is there an alternative approach? Of course, if this can be done entirely in configuration, that would be the best.
Okay, I found a solution for my problem at hand, still, I think this could done in a saner way. Anyway, I am posting my own type converter:
public class DateConverter extends StrutsTypeConverter {
private DateFormat dateFormat;
{
ActionContext ctx = ActionContext.getContext();
ActionSupport action = (ActionSupport) ctx.getActionInvocation().getAction();
String formatString = action.getText("dateformat.ui");
dateFormat = new SimpleDateFormat(formatString);
}
public Object convertFromString(Map context, String[] values, Class toClass) {
String input = values[0];
try {
Date date = dateFormat.parse(input);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal;
} catch (ParseException e) {
return null;
}
}
public String convertToString(Map context, Object object) {
Calendar cal = (Calendar) object;
return dateFormat.format(cal.getTime());
}
}
I removed the non-essential parts of the code, but this is a working solution.
Why does this code return 0001-02-05?
public static String getNowDate() throws ParseException
{
return Myformat(toFormattedDateString(Calendar.getInstance()));
}
I changed the code to:
public static String getNowDate() throws ParseException
{
Calendar temp=Calendar.getInstance();
return temp.YEAR+"-"+temp.MONTH+"-"+temp.DAY_OF_MONTH;
}
And now it returns 1-2-5.
Please, help me get the actual date. all i need is the Sdk date.
Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH are int constants (just look up in the API doc)...
So, as #Alex posted, to create a formatted String out of a Calendar instance, you should use SimpleDateFormat.
If however you need the numeric representations of specific fields, use the get(int) function:
int year = temp.get(Calendar.YEAR);
int month = temp.get(Calendar.MONTH);
int dayOfMonth = temp.get(Calendar.DAY_OF_MONTH);
WARNING! Month starts from 0!!! I've made some mistakes because of this!
Use SimpleDateFormat
new SimpleDateFormat("yyyy-MM-dd").format(Calendar.getInstance().getTime());
You are using constants to be used with the Calendar.get() method.
Why not use SimpleDateFormat?
public static String getNowDate() {
return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
}
You are doing it wrong. Change to:
return temp.get(Calendar.YEAR)+"-"+ (temp.get(Calendar.MONTH)+1) +"-"+temp.get(Calendar.DAY_OF_MONTH);
Also, you may want to look into Date:
Date dt = new Date();
//this will get current date and time, guaranteed to nearest millisecond
System.out.println(dt.toString());
//you can format it as follows in your required format
System.out.println(new SimpleDateFormat("yyyy-MM-dd").format(dt));
i want to use standard class called DateFormat which has subclass SimpleDateFormat TO write a method called convert which returns a String in the form dd.mm.yy: when passed a GregorianCalendar with a specific date
public String convert (Calendar gc) { ... }
For example, when myGC is a GregorianCalendar variable representing the 25th of December 2006, String s = convert(myGC); should set s to the string "25.12.06".
and i'm having trouble to write a convert method on this
public String convert(Calendar c) {
return new SimpleDateFormat("dd.MM.yy").format(c.getTime());
}
Eventually you'll want to store that SimpleDateFormat as a member (for example) if performance becomes a concern.
Why not just use a pattern like this one "dd.MM.yy" in your SimpleDateFormat ?
DateFormat dateFormatter = new SimpleDateFormat("dd.MM.yy");
String myDate = dateFormatter.format(cal.getTime());