This question already has answers here:
Convert Joda LocalDate or java.util.Date to LocalDateTime having time at Start of the Day
(2 answers)
Closed 5 years ago.
I am trying to convert Joda LocalDate to Joda LocalDateTime, for that I am using the method toLocalDateTime(LocalTime.MIDNIGHT), as of now it is working
fine for example: for the given joda Localdate 2025-02-28 I getting the expected joda LocalDateTime 2025-02-28T00:00:00.000, But my fear is, whether this method works fine at all situation. For example during dayLight saving time zone anomalies..etc..
Update: I did a small research on this question, here it is
toLocalDateTime(LocalTime time) Documentation saying that: Converts LocalDate object to a LocalDateTime with LocalTime to fill in the missing fields.
As I initializing LocalTime with LocalTime.MIDNIGHT, from here LocalTime.MIDNIGHT is a static final field initialized to new LocalTime(0, 0, 0, 0);, you can see that it is a time values are hardcode to zero values with ISOChronology getInstanceUTC(), so I think I will get the required output without any issue.
From the documentation, we know that
LocalDate is an immutable datetime class representing a date without a time zone.
LocalDateTime is an unmodifiable datetime class representing a datetime without a time zone.
Internally, LocalDateTime uses a single millisecond-based value to represent the local datetime. This value is only used internally and is not exposed to applications.
Calculations on LocalDate are performed using a Chronology. This chronology will be set internally to be in the UTC time zone for all calculations.
We also know that the toLocalDateTime method of LocalDate class is implemented like this:
public LocalDateTime toLocalDateTime(LocalTime time) {
if (time == null) {
throw new IllegalArgumentException("The time must not be null");
}
if (getChronology() != time.getChronology()) {
throw new IllegalArgumentException("The chronology of the time does not match");
}
long localMillis = getLocalMillis() + time.getLocalMillis();
return new LocalDateTime(localMillis, getChronology());
}
Considering also that UTC has no Daylight saving time, we can conclude that you don't have to fear daylight saving problems nor time zone anomalies using the toLocalDateTime method because this method dont deal with timezones.
Related
I've tried almost everything about this snippet, and I still get IllegalInstentException.
public int getDateDay() {
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
DateTime dt;
try {
dt = formatter.parseDateTime(date);
} catch (IllegalInstantException e) {
dt = formatter.parseLocalDateTime(date).toDateTime();
}
return dt.getDayOfMonth();
}
Fatal Exception: org.joda.time.IllegalInstantException Illegal instant
due to time zone offset transition (daylight savings time 'gap'):
2018-10-21T00:00:00.000 (America/Sao_Paulo) keyboard_arrow_up
arrow_right org.joda.time.chrono.ZonedChronology.localToUTC
(ZonedChronology.java:157)
org.joda.time.chrono.ZonedChronology.getDateTimeMillis
(ZonedChronology.java:122)
org.joda.time.chrono.AssembledChronology.getDateTimeMillis
(AssembledChronology.java:133) org.joda.time.base.BaseDateTime.
(BaseDateTime.java:257) org.joda.time.DateTime. (DateTime.java:532)
org.joda.time.LocalDateTime.toDateTime (LocalDateTime.java:750)
org.joda.time.LocalDateTime.toDateTime (LocalDateTime.java:731)
Seems the input is not a valid date. The problem has been discussed in this page.
Reason:
Joda-Time only allows the key classes to store valid date-times. For
example, 31st February is not a valid date so it can't be stored
(except in Partial).
The same principle of valid date-times applies to daylight savings
time (DST). In many places DST is used, where the local clock moves
forward by an hour in spring and back by an hour in autumn/fall. This
means that in spring, there is a "gap" where a local time does not
exist.
The error "Illegal instant due to time zone offset transition" refers
to this gap. It means that your application tried to create a
date-time inside the gap - a time that did not exist. Since Joda-Time
objects must be valid, this is not allowed.
Possible solutions may be as follows:
Use LocalDateTime, as all local date-times are valid.
When converting a LocalDate to a DateTime, then use toDateTimeAsStartOfDay() as this handles and manages any gaps.
When parsing, use parseLocalDateTime() if the string being parsed has no time-zone.
I'm using the below function to convert a microsecond format time string to ZoneDateTime so I can do comparisons later.
public static ZonedDateTime createTimeFromString(String inputTime) {
ZonedDateTime time;
try {
System.out.printf("Input time %s%n", inputTime);
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyyMMdd-HH:mm:ss.SSSSSS");
LocalDate date = LocalDate.parse(inputTime, formatter);
time = date.atStartOfDay(ZoneId.systemDefault());
System.out.printf("Formated time %s%n", time);
return time;
}
catch (DateTimeParseException exc) {
System.out.printf("%s is not parsable!%n", inputTime);
throw exc; // Rethrow the exception.
}
}
However, whatever time string I pass into the function I get the same output.
eg:
Input time 20171025-10:58:24.062151
Formated time 2017-10-25T00:00+05:30[Asia/Colombo]
Input time 20171025-10:58:25.446862
Formated time 2017-10-25T00:00+05:30[Asia/Colombo]
I'm using Java 8.
Can you please clarify what I'm doing wrong?
When you call LocalDate.parse, you're getting just the date part (day, month and year) and discarding the rest. A LocalDate doesn't have the time fields (hour, minute, seconds and fraction of second), so they are simply discarded and lost.
Then you call atStartOfDay(ZoneId.systemDefault()), which sets the time to midnight at the JVM default timezone.
If you want to keep everything (date and time), parse it to a LocalDateTime, which is a class that contains all the date and time fields. Then you call the atZone method to convert it to a ZonedDateTime:
String inputTime = "20171025-10:58:24.062151";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HH:mm:ss.SSSSSS");
// parse to a LocalDateTime (keeping all date and time fields)
LocalDateTime date = LocalDateTime.parse(inputTime, formatter);
// convert to ZonedDateTime
ZonedDateTime z = date.atZone(ZoneId.systemDefault());
PS: ZoneId.systemDefault() returns the JVM default timezone, but keep in mind that this can be changed without notice, even at runtime, so it's better to always make it explicit which one you're using.
The API uses IANA timezones names (always in the format Region/City, like Asia/Colombo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like IST or CET) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds(). Then you call the ZoneId.of() method with the zone name, like this:
// using specific timezone instead of JVM's default
ZonedDateTime z = date.atZone(ZoneId.of("Asia/Colombo"));
How to calculate the difference between current day and date of the object that user had previously selected from jXDatePicker swing component and that had been added as Date to that object.
In my current code at the last line I'm getting this error message:
no suitable method found for between(Date, Date)
Date currentDate = new Date();
Date objDate = obj.getSelectedDate(); //getting date the user had
//previously selected and that been
//added to object
long daysDifference = ChronoUnit.DAYS.between(objDate, currentDate);
You are mixing up the legacy Date-Time code with the new Java 8 Date-Time API. The ChronoUnit.between(Temporal, Temporal) method is from java.time.temporal package which takes two Temporal objects. It does not support the java.util.Date as an argument, hence the compilation error.
Instead of using the legacy Date class, you can use java.time.LocalDate class , and then get the difference between the two dates.
LocalDate currentDate = LocalDate.now(ZoneId.systemDefault());
LocalDate objDate = obj.getSelectedDate(); // object should also store date as LocalDate
long daysDifference = ChronoUnit.DAYS.between(objDate, currentDate);
Update
As per your comment , the objDate can only be a Date, so in this case you can use the inter-operability between the Legacy Date -Time and the Java 8 Date-Time classes.
LocalDateTime currentDate = LocalDateTime.now(ZoneId.systemDefault());
Instant objIns = obj.getSelectedDate().toInstant();
LocalDateTime objDtTm = LocalDateTime.ofInstant(objIns, ZoneId.systemDefault());
long daysDifference = ChronoUnit.DAYS.between(objDtTm, currentDate);
Update 2
As pointed out by Ole V.V in the comments, to handle Time Zone issues that may occur , calculating the difference using Instant is a better approach.
Instant now = Instant.now();
long daysDifference = obj.getSelectedDate()
.toInstant()
.until(now, ChronoUnit.DAYS);
I agree with Pallavi Sonal’s answer that when you can use the modern java.time classes, you should keep your use of the oldfashioned classes like Date to an absolute minimum. I don’t know JXDatePicker, but I see that its getDate method returns a Date. So the first thing you should do with this is convert it to a more modern thing.
It may seem from your question that in this case you are only concerned with days, not times. If this is correct, Pallavi Sonal is also correct that LocalDate is the correct class for you. I think that this conversion should work for you
LocalDate selectedDate = jXDatePicker.getDate()
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
This is with a bit of reservation for time zone issues since I don’t know in which time zone the date picker is giving you the date. Once you know that, you can fill in the correct time zone instead of ZoneId.systemDefault().
Unfortunately I am not aware of a date picker component that can give you a LocalDate directly. There could well be one, I hope there is, so it’s probably worth searching for one.
Consider a code:
TemporalAccessor date = DateTimeFormatter.ofPattern("yyyy-MM-dd").parse("9999-12-31");
Instant.from(date);
The last line throws an exception:
Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 9999-12-31 of type java.time.format.Parsed
How to create Instant from yyyy-MM-dd pattern?
The string "9999-12-31" only contains information about a date. It does not contain any information about the time-of-day or offset. As such, there is insufficient information to create an Instant. (Other date and time libraries are more lenient, but java.time avoids defaulting these values)
Your first choice is to use a LocalDate instead of an `Instant:
LocalDate date = LocalDate.parse("9999-12-31");
Your second choice is to post process the date to convert it to an instant, which requires a time-zone, here chosen to be Paris:
LocalDate date = LocalDate.parse("9999-12-31");
Instant instant = date.atStartOfDay(ZoneId.of("Europe/Paris")).toInstant();
Your third choice is to add the time-zone to the formatter, and default the time-of-day:
static final DateTimeFormatter FMT = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd")
.parseDefaulting(ChronoField.NANO_OF_DAY, 0)
.toFormatter()
.withZone(ZoneId.of("Europe/Paris"));
Instant instant = FMT.parse("9999-31-12", Instant::from);
(If this doesn't work, ensure you have the latest JDK 8 release as a bug was fixed in this area).
It is worth noting that none of these possibilities use TemporalAccessor directly, because that type is a low-level framework interface, not one for most application developers to use.
The problem isn't the fact that you are using the year 9999. The Instant.MAX field evaluates to the timestamp 1000000000-12-31T23:59:59.999999999Z, so 9999 as a year is fine.
Dealing with TemporalAccessors instead of the more semantically rich types like LocalDateTime or ZonedDateTime is like using a Map to model an object and its properties instead of writing a class -- you have to assure that the value has the fields (like seconds, nanoseconds, etc) that are expected by something receiving it, rather than depending on formally declared operations in a higher level class to prevent dependencies from going unmet.
In your case it is likely that the temporal accessor contained the parsed date fields it was given, but didn't have a "seconds" field that the Instant needed. It is best to use the more semantically rich types like LocalDateTime in most instances.
Since you only have date fields, you should parse it as a date, then add the time fields before converting it to an Instant. Here is one way, using LocalDate to parse the date:
LocalDate localDate = LocalDate.parse("2016-04-17");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
Either you are only interested in the date itself (31st of December 9999), in which case the appropriate type would be a LocalDate:
LocalDate date = LocalDate.parse("9999-12-31");
Or you do want an Instant, in which case you need to set a time and time zone, for example, 00:00 in Tokyo:
Instant instant = date.atStartOfDay(ZoneId.of("Asia/Tokyo")).toInstant();
public static void main(String[] args) throws ParseException {
System.out.println(new SimpleDateFormat("yyyy-MM-dd").parse("2016-12-31").toInstant());
}
the above code gives the following output:
2016-12-31T00:00:00Z
i have answered this question using features('toInstant' method) of java 8. hope this answers your question...
I am pulling data from an external source into my program and it has an ISO8601 Date attached to it but one of our requirements is that the hour/minutes/seconds get set to zero. This happens before I receive the date. So I get this from the data.
2013-05-17T00:00:00.000Z
for instance. I am then putting that value into a Joda DateTime object called "businessDay". I do some processing based off of this value but then I need to persist it to MongoDB.
Since a Joda DateTime object is not serializable I need to put the DateTime object into a Date object and persist it to Mongo (and reverse that when it comes out).
When I use Joda in this way
businessDay.toDate() -- I receive a Java Date object but it is
Sun May 19 20:00:00 EDT 2013
and businessDay printed out normally is
2013-05-20T00:00:00.000Z
It converts it to my local time zone, which is then making it the previous day.
What I want is to convert the DateTime object into a Date object that retains the values.
I've been trying a bunch of things with DateTimeFormatter but I can't get it to work at all. I've also been deleting all of my efforts otherwise I would paste them here but I've been doing this all day to try to figure this out.
Thank you for any assistance.
EDIT:
Showing method that converts a String Date into a Joda DateTime object.
private DateTime asDateTime(String value) {
// Was experiencing an issue converting DateTime to date, it would convert to localtime zone
// giving me the wrong date. I am splitting the value into its year/month/day values and using a dateFormatter
// to give me an appropriate format for the date. Timezone is based on UTC.
String[] splitValue = value.split("-");
String[] splitDay = splitValue[2].split("T");
int year = Integer.parseInt(splitValue[0]);
int month = Integer.parseInt(splitValue[1]);
int day = Integer.parseInt(splitDay[0]);
DateTime date = new DateTime(DateTimeZone.UTC).withDate(year, month, day).withTime(0, 0, 0, 0);
return date;
}
Firstly, if you've just got a date, I would suggest using LocalDate rather than DateTime. However, I think you've misunderstood what java.util.Date does:
It converts it to my local time zone, which is then making it the previous day.
No, it really doesn't. Your DateTime value is precisely 2013-05-20T00:00:00.000Z. Now a java.util.Date is just a number of milliseconds since the Unix epoch. It doesn't have the concept of a time zone at all. It's equivalent to a Joda Time Instant.
When you call toString() on a Date, that converts the instant in time into your local time zone - but that's not part of the state of the object.
So both your DateTime and your Date represent midnight on May 20th UTC. I don't know what MongoDB is then doing with the value, but just the conversion from Joda Time to java.util.Date has not performed any time zone conversion for you.
My apologies, I found out that it wasn't an issue of the Dates it was a completely different issue. MongoDB can accept a Java Date and will convert it to UTC format automatically.
My fault for creating this post before looking at this problem from different angles.
Do I accept the other answer and give the bounty? Just curious if that is the correct thing to do on Stack Overflow.