I am new to Java and I am working on Java 8.
I am trying to convert LocalDateTime Object to LocalDateTime but not able to find any way without converting it to String. Is there any direct method for converting Object to LocalDateTime when the underlying Object type is LocalDateTime?
Moreover, if there is any way to convert, can it work for underlying String type LocalDateTime Object too?
Below is my current code which is converting the Object to String before converting it to LocalDateTime as LocalDateTime.parse method needs String input.
public static LocalDateTime toDateTime(Object dateTimeObject) {
LocalDateTime dateTime = LocalDateTime.parse(dateTimeObject.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"));
return dateTime;
}
If the object is a LocalDateTime, you can cast the object.
public static LocalDateTime toDateTime(Object dateTimeObject) {
if (dateTimeObject instanceof LocalDateTime) {
return (LocalDateTime) dateTimeObject;
}
return null;
}
According to the Java 8 LocalDateTime API there is no method that takes an Object argument and returns a LocalDateTime. But there is one that takes a CharSequence parameter, which is why it works when you convert the object to String, and why it won't work if you just pass the Object parameter. If you don't want to have to do the call to the toString() method, perhaps the parameter of toDateTime(Object o) should be of a different type.
Related
I have an Object MyTimes and in that object there are fields name ,start_date and configuration.
I have an array of this object, MyTimes [] mytimes
I am trying to sort the array by the start time but am struggling how to go about it.
The start_time field is a string, so this needs converting to a datetime.
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
for(int i=0; i<mytimes.length; i++) {
Date date = formatter.parse(mytimes[i].getStartTime());
}
I'd then put the date into an array list perhaps and then sort by datetime? But then I wouldnt know which start_time corresponds with which mytimes object...
What is the most efficient way of doing this?
Under the right circumstances this is a one-liner:
Arrays.sort(myTimes, Comparator.comparing(MyTimes::getStartDate));
Let’s see it in action:
MyTimes[] myTimes = {
new MyTimes("Polly", "2019-03-06T17:00:00Z"),
new MyTimes("Margaret", "2019-03-08T09:00:00Z"),
new MyTimes("Jane", "2019-03-01T06:00:00Z")
};
Arrays.sort(myTimes, Comparator.comparing(MyTimes::getStartDate));
Arrays.stream(myTimes).forEach(System.out::println);
Output:
Jane 2019-03-01T06:00:00Z
Polly 2019-03-06T17:00:00Z
Margaret 2019-03-08T09:00:00Z
I am assuming that getStartDate returns an Instant or another type the natural order of which agrees with the chronological order you want. For example:
public class MyTimes {
private String name;
private Instant startDate;
// Constructor, getters, toString, etc.
}
If you are receiving your start dates as strings somehow, you may write a convenient constructor that accepts a string for start date. I am already using such a constructor in the above snippet. One possibility is having two constructors:
public MyTimes(String name, Instant startDate) {
this.name = name;
this.startDate = startDate;
}
public MyTimes(String name, String startDate) {
this(name, Instant.parse(startDate));
}
The Instant class is part of java.time, the modern Java date and time API.
I am exploiting the fact that your strings are in the ISO 8601 format for an instant, the format that Instant.parse accepts and parses.
Avoid SimpleDateFormat and Date
I recommend you don’t use SimpleDateFormat and Date. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. There is also an error in your format pattern string for parsing: Z (pronounced “Zulu”) means UTC, and of you don’t parse it as such, you will get incorrect times (on most JVMs). Instant.parse efficiently avoids any problems here.
Don’t store date-tine as a string
It looks like you are are storing start time in a String field in your object? That would be poor modelling. Use a proper date-time type. Strings are for interfaces. Date-time classes like Instant offer much more functionality, for example define sort order.
You have two main approaches:
Make your class implement Comparable
Use a custom Comparator
Then, you can choose the field to compare from, and transform it.
IE (implementing comparable):
class Example implements Comparable<Example> {
private String stringDate;
public int compareTo(Example e) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
Date date1 = formatter.parse(this.stringDate);
Date date2 = formatter.parse(e.stringDate);
return date1.getTime() - date2.getTime();
}
}
And then using Arrays.sort would use your custom comparison.
Let your class implement Comparable and implement compareTo using modern formatting and date classes. Note that LocalDateTime also implements Comparable so once the string has been parsed you let LocalDateTime do the comparison
public class MyTimes implements Comparable<MyTimes> {
private final DateTimeFormatter dtf = DateTimeFormatter.ISO_INSTANT;
//other code
public int compareTo(MyTimes o) {
LocalDateTime thisDate = LocalDateTime.from(dtf.parse(this.getStartTime()));
LocalDateTime otherDate = LocalDateTime.from(dtf.parse(o.getStartTime()));
return thisDate.compareTo(otherDate);
}
}
You can also create a separate class as a comparator if this comparison is special and what you not always want to use
public class MyTimesComparator implements Comparator<MyTimes> {
#Override
public int compare(MyTimes arg0, MyTimes arg1) {
DateTimeFormatter dtf = DateTimeFormatter.ISO_INSTANT;
LocalDateTime thisDate = LocalDateTime.from(dtf.parse(this.getStartTime()));
LocalDateTime otherDate = LocalDateTime.from(dtf.parse(o.getStartTime()));
return thisDate.compareTo(otherDate);
}
}
and then use it like
someList.sort(new MyTimesComparator());
or use an inline function (I am using Instant here)
someList.sort( (m1, m2) -> {
DateTimeFormatter dtf = DateTimeFormatter.ISO_INSTANT;
Instant instant1 = Instant.from(dtf.parse(m1.getStartTime));
Instant instant2 = Instant.from(dtf.parse(m2.getStartTime));
return intant1.compareTo(instant2);
});
I noticed now that you have an array and not a list so you need to convert to a list or use Arrays.sort instead.
LocalDateTime is abstract class. So I cannot write:
LocalDateTime value = new LocalDateTime(); //error
If I want to get its instance, I have to write:
LocalDateTime value = LocalDateTime.now(); //not error
I have a question, Why can LocalDateTime return the instance? It's an abstract class.
I saw the overview, but I could not find it...
LocalDateTime is not an abstract class.
public final class LocalDateTime
implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable {
It has private constructors, so direct instantiation is not possible. Factory method such now(), now(ZoneId) etc are used to create instances.
LocalDateTime is an immutable date-time object that represents a date-time.
This class does not store or represent a time-zone. Instead, it is a description of the date. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
Hence it has static methods e.g.
LocalDateTime desc = LocalDateTime.now();
In our recent project we use java 8. I need to serialize java.time.LocalDateTime to java script Date format.
Currently what I did was define a custom serializer to convert LocalDateTime to timestamp.
public class LocalDateTimeSerializer implements JsonSerializer<LocalDateTime> {
#Override
public JsonElement serialize(LocalDateTime localDateTime, Type type, JsonSerializationContext jsonSerializationContext) {
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date = Date.from(instant);
return new JsonPrimitive(date.getTime());
}
}
then create Gson object using GsonBuilder with my custom LocalDateTimeSerializer
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer());
Gson gson = gsonBuilder.create();
Then in Java Script I create a Date object using this time stamp. It's working fine.
I need to know, is this way ok or is there a better way to do this?
Java 8 solution from LocalDateTime to Epoch Milliseconds or Seconds:
// to Epoch Seconds
long sec = localDateTime.toInstant(ZoneOffset.UTC).getEpochSecond();
// to Epoch Milliseconds
long msec = localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();
In your case however I see a bug which uses Local Timezone instead of UTC. My recommended solution would be:
#Override
public JsonElement serialize(LocalDateTime localDateTime, Type type, JsonSerializationContext jsonSerializationContext) {
long sec = localDateTime.toInstant(ZoneOffset.UTC).getEpochSecond();
return new JsonPrimitive(sec);
}
YES, that's the best way.
It's highly recommended to convert a Time object into it's long type representation when you're going to transfer it from one system to another. This can avoid many problems, such as data formatting and time local in different systems.
And what's more, long representation takes only 8 bytes, while string representation takes a little more. Which means long representation is more efficient to transfer and parse.
I have Date in this format 2009-09-17T00:00:00.000-35:00 . As per the business Rules for my Application , i have written 3 Methods which will accept this Date and returns the Date in MM/yyyy , yyyyMM and dd .
For example one method is shown below MM/yyyy
private String getMonthYear(String date) throws Exception {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
String s1 = date;
String s2 = null;
Date d;
try {
d = sdf.parse(s1);
s2 = (new SimpleDateFormat("MM/yyyy")).format(d);
} catch (ParseException e) {
e.printStackTrace();
}
return s2;
}
Similarly i have other two methods which will return data in yyyyMM and dd formats ??
This works fine , but does not look good
My question is can we have only one utility which satisfies my requirement ??
My question is can we have only one utility which satisfies my requirement ??
I think you're going about this the wrong way to start with. Fundamentally the data is just a date. You can apply formats later, when you need to. I suggest you start using Joda Time and make your method return a LocalDate. That captures all the real information, and you can then have three separate DateTimeFormatter objects used to format the value whenever you want.
Wherever you can, represent data using a type which most naturally represents the real information. Get your data into that natural format as early as possible, and keep it in that format until you have to convert it into something else (such as a string).
You could define a single method and receive as a parameter the string with the expected date format, the three strings with the formats could be defined as constants.
Yes, you could group the three methods together, and use an additional argument (an enum, for example) to specify which kind of output format you want. But I would not do that. Your solution is cleaner. Why do you think it doesn't look good?
What I would do, however, is transforming the String to a Date once and for all, and using a Date everywhere rather than the String, and transforming the Date with one of your 3 methods (which would take a Date as argument rather than a String) when needed.
The Apache Commons Lang library already has utility methods to do this for you.
For example:
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
///
// first, convert the string to a date object
Date parsedDate = DateUtils.parseDate("2012-05-25T16:10:30.000",
new String[] {"yyyy-MM-dd'T'HH:mm:ss.SSS"});
// now, format the date object to a string, using different formats
String formattedDate = DateFormatUtils.format(parsedDate, "MM/yyyy");
String formattedDate2 = DateFormatUtils.format(parsedDate, "yyyyMM");
Take a look at DateFormatUtils and DateUtils for more information.
You could just have a Date class which has the three methods. Like below:
public class MyDate {
private String date = null;
public MyDate(String date) {
this.date = date;
}
public String getMonthYear() {
return null;
}
public String getYearMonth() {
return null;
}
public String getDay() {
return null;
}
}
You can format the String into three different Strings in the constructor and just return those strings on method calls. That implementation would be good if you make numberous/repeated calls on the same date string. Or you could format the string in the method call, if you are doing it once but if you are doing it once you may want to make the class/methods static and get rid of the constructor.
I want a nice way to get the current unix timestamp from a java Date object, this is my solution:
public class Date extends java.util.Date {
public int getUnixTimeStamp() {
int unixtimestamp = (int) (this.getTime() * .001);
return unixtimestamp;
}
}
That works fine, but the problem is when I try to cast a java Date object to my custom date class, i.e:
Calendar foo = Calendar.getInstance();
foo.set(0, 0, 0, 12, 30);
myapp.Date foo2 = (myapp.Date)foo.getTime();
This generates: Exception in thread "main" java.lang.ClassCastException: java.util.Date cannot be cast to myapp.Date
I understand why this exception is made but is there any way to cast a superclass to a subclass? If not, how would you implement the unixtimestamp method? I use it quite often in my application.
You can't cast a superclass in a subclass because the subclass may have a bigger interface than the superclass means the subclass can have functions like getUnixTimeStamp() that the superclass doesn't have. In your example that would mean you trying to call getUnixTimeStamp on a java.util.Date.
You can use a Delegate or Composition instead of inheritance here.
That means you have a Class
public class Date {
private java.util.date date;
public Date(java.util.Date date) {
this.date = date
}
public int getUnixTimeStamp() {
int unixtimestamp = (int) ((this.date.getTime()) * .001);
return unixtimestamp;
}
}
In this way you don't cast the date into your date you create a class arround the java.util.date.
If you use only this function it could be an easier solution to just create a static util function getUnixTime(Date date) that returns the changed date.
If you're keen on having your subclass, implement a constructor in your Date class taking a java.util.Date foo and in it call super with foo.getTime(); then instead of casting you just call Date(foo) to instantiate your subclass.
Why do you need to make this class extend java.util.Date at all? Make a static function that takes a Date and returns the unix timestamp of that date.
As already mentioned you could implement it by letting the constructor of the class take the time as an input.
Something like this:
public class Date {
long unixtimestamp;
public Date(long time) {
unixtimestamp = (long) (time * .001);
}
public long getUnixTimeStamp() {
return unixtimestamp;
}
}
Another option is just to create a static method which converts it. It depends on whether you are planning on adding other similar features to the class or not. If not then a static-method is probably better.
No, you can't cast a type to a more derived type if the reference doesn't point to an instance of the derived type.
The Date being returned by Calendar.getTime() isn't one of your Date objects, and it doesn't have the additional attributes and behaviours those objects do.
You could modify your Date class to use composition instead of inheritance, e.g.
class Date {
private java.util.Date date;
public Date( java.util.Date date ) {
this.date = date;
}
public int getUnixTimestamp() {
return (int)( date.getTime() * .001 );
}
}