i am trying Joda time in java using the latest version 2.2 i have written a small snippet here is my code
public static void main(String[] args)
{
BoilerTester clazz = new BoilerTester();
Calendar today = Calendar.getInstance();
Calendar born = Calendar.getInstance();
//when returns 0 is 10363 when returning 1 = 10362 just a millisecond what have to do with days??
System.out.println(Math.abs(today.getTimeInMillis()-born.getTimeInMillis()));
born.set(1984,10,20);
clazz.compute(born,today);
}
private void compute(Calendar born, Calendar today)
{
System.out.println("JODA: " + org.joda.time.Days.daysBetween(new org.joda.time.DateTime(born.getTime()),new org.joda.time.DateTime(today.getTime())).getDays());
}
when i run the source code i am getting this values
JODA: 10363
later I run the same code and I am getting
JODA: 10362
Yes i have run maybe 2 or 3 times the same code to get different values but why this???
thanks a lot.
My guess is that sometimes, the today and born dates are on the exact same millisecond, and sometimes they differ by a few milliseconds (the time that elapses between the first call to Calendar.getInstance() and the second one). Since getDays() returns the number of complete days, a few milliseconds could make a difference.
I was writing my answer but JB Nizet was faster (he is absolutely right on what is happening). If you want to get rid of this kind of problems, you should leverage the concept of partial in joda-time:
A partial in Joda-Time is a partial date and time representation. All implementations represent local dates and times, and do not reference a time zone. As such, they only partially represent a date or time in the datetime continuum.
For example, with a LocalDate:
LocalDate born = new LocalDate(1984, 11, 20); // BE CAREFUL!: months in JDK are 0-11, but in Joda-Time are 1-12
System.out.println(Days.daysBetween(born, LocalDate.now()).getDays());
With this "partial" representation, you are not using hours, minutes, seconds or milliseconds internally, so you cannot face this problem due to milliseconds.
You're running a mix of JDK and Joda -- don't do that -- Joda replaces the JDK time classes completely.
Related
I found this code:
long timeStampSeconds = ChronoUnit.MICROS.between(Instant.EPOCH, Instant.now());
but when I converted this back to fetch month and year using the following code, it gives the wrong output.
try {
epochLong = Long.parseLong(epoch);
} catch (RuntimeException e) {
//Log exception
return null;
}
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(epochLong);
String month = String.valueOf(cal.get(Calendar.MONTH));
String year = String.valueOf(cal.get(Calendar.YEAR));
//print month and year
Any pointers as to how I can generate this in microseconds and get the month and year back right? Please help.
If you are using java.time from Java-8 you can use :
long timeStampSeconds = ChronoUnit.MICROS.between(Instant.EPOCH, Instant.now());
to back you can convert this to an instant, then the instant to the ZoneDateTime
Instant inst = Instant.EPOCH.plus(timeStampSeconds, TimeUnit.MICROSECONDS.toChronoUnit());
ZonedDateTime zdt = inst.atZone(ZoneId.of("Europe/Paris"));
Then you can get the month, year, day, hour, ...
Month month = zdt.getMonth();
int year = zdt.getYear();
Outputs
MICROS: 1574073141066090
ZoneDateTime: 2019-11-18T11:32:21.066090+01:00[Europe/Paris]
It depends on the platform and the Java version.
On my Mac example timeStampSeconds values from your code include
using jdk-1.8.0_121: 1574193249064000 and 1574193338130000; so always ending in 000
using jdk-9.0.4: 1574193430428678 and 1574193438362321; so usually not ending in 000.
On Java 8 the now methods of the java.time classes haven’t got any finer granularity than millisenods, so the microsecond of millisecond will always be 000. On Java 9 a finer granularity is available if the platform supports it, which may not be the case for all platforms.
So if you’re getting 000 always, the solution is to upgrade at least to Java 9 and run your Java program on a computer that supports microsecond precision.
Don’t use Calendar
The Calendar class is poorly designed and long outdated. Also it never supports any unit finer than milliseconds. To convert your microsecond value back to a date and time object, use for example:
long timeStampSeconds = 1_574_193_438_362_321L;
Instant convertedBack = Instant.EPOCH.plus(timeStampSeconds, ChronoUnit.MICROS);
System.out.println(convertedBack);
2019-11-19T19:57:18.362321Z
You will notice that the full microsecond precision is preserved. YCF_L in another answer has already shown how to get the year and month values.
I need to calculate a value that is based on dates. So I'm parsing the date first using date format class and then i'm using getTime() to get milliseconds. With those milliseconds i'll calculate some value. But getTime() is returning different values in different servers. We develop here in India, where i'm getting correct value but in US server i'm getting different value.
Scenario:
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String now = "11/03/2018";
Date UsualDateformat = sdf.parse(now);
System.out.println(UsualDateformat.getTime());
}
}
Above is a sample code, but my actual code is a rule in a drl file (drools).
This program returns
"1541183400000" which i convert to date is "Sat 3 November 2018 00:00:00".,
but in US server im getting "1541217600000" equal to date "Sat 3 November 2018 09:30:00".
So when i use this value i'm getting marginal decimal point formatting issue.
How to resolve this issue?
Thanks in advance!
You need to set the time zone on SimpleDateFormat to be consistent across servers in different regions. For example:
public class Test {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
....
}
}
You get these different values, because the time difference between your server in the US and the one in India is 9h 30.
This has nothing to do with floating points, but with time zones.
One way to solve this problem is to work always within the same time zone (e.g. India)
This code snippet might work for you,
public static String getGmtTime(String timezone) {
return ZonedDateTime
.now()
.withZoneSameInstant(ZoneId.of(timezone))
.toLocalDateTime()
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
pass timezone as America/Los_Angeles to get time with proper timezone,
Timezones can be found here
java.time
I recommend you use java.time, also known as JSR-310, for this. The classes you use, Date and SimpleDateFormat, are long outdated, and SimpleDateFormat in particular has a reputation for producing surprising results, which one may say also happened in your case. The modern API is generally so much nicer to work with.
As I think you have suspected already, your issue comes from the fact that your servers are running different time zones, and the conversion of a date to millis since the epoch is a time zone dependent operation since the epoch is always the same point in time (Jan 1 1970 at midnight in UTC). As mweiss I am using UTC for the conversion to make sure it gives the same result no matter the time zone of the server:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/yyyy");
String now = "11/03/2018";
LocalDate date = LocalDate.parse(now, dtf);
long millisInUtc = date.atStartOfDay(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
System.out.println(millisInUtc);
As my code stands, it prints
1541203200000
This is between the values you got in India and US because UTC is between those two time zones. If you consider it more correct to use for example Asia/Kolkata time, simply substitute ZoneId.of("Asia/Kolkata") instead of ZoneOffset.UTC in the code, and you should get the same output as you already got when you ran your code on your server in India (please remember to rename the variable too).
My code is a bit longer than yours. I consider this an advantage in this case. Yes, indeed. The code using java.time is making explicit that we are using the time at the start of the day (0:00 midnight) and that we are using a time zone or offset for the conversion. This forces you as the coder to think about these issues, and you will be very unlikely to write code that produces results that differ unexpectedly across time zones, that is, your issue would never arise. At the same time it makes explicit to the reader that the operation depends on time zone, and that you have made a conscious choice of which zone to use. These advantageous are well worth a few more code lines.
This question already has answers here:
How to check if 2 dates are on the same day in Java
(4 answers)
Closed 8 years ago.
I have two calendar objects, they seems to contain same dates but the compareTo() method is returning -1 as result, Can any one explain the reason behind this.
On debugging the two Calendar objects, the result is shown as :
2014-06-01T00:00:00.000Z
for both calendar objects but the compareTo() is returning -1. Even the long time in millis for both dates are different.
Well, have a look at the Calendar code (this is from JDK 1.7.0-13):
public int compareTo(Calendar anotherCalendar) {
return compareTo(getMillisOf(anotherCalendar));
}
private int compareTo(long t) {
long thisTime = getMillisOf(this);
return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
}
It should be obvious that if the two Calendar's have different millis, then they're different as per the second method.
In any case, the millis in your example should not both represent 2014-06-01T00:00:00.000Z so there's another problem in your code. Try this:
Timestamp ts1 = new Timestamp( 1401561000000L );
Timestamp ts2 = new Timestamp( 1401595200000L );
System.err.println( ts1 );
System.err.println( ts2 );
Outputs:
2014-05-31 20:30:00.0
2014-06-01 06:00:00.0
Cheers,
The milliseconds number is the "offical" time in Java. However, for a variety or reasons, there are numbers with the same date/time which have different numbers of milliseconds. Then normal reason is clock adjustments. E.g. Sometimes you have to add a second or two to account for irregularities in the earth's orbit. The other big source is when regions were first brought into the UTC, then some time zones moved hours.
THere is also the common source for these things: DST.
This will happen twice a year when you move to daylight saving time, on the one hand there are date/times which do not exists, as they were "skipped", and there are other times which happened twice, as the clock gets reset at midnight, so 11pm-midnight happens twice on the same day.
If you want to just compare the minutes and ignore the milliseconds or seconds do this:
You need to use
cal.set(Calendar.MILLISECOND, 0);
and possibly as well
cal.set(Calendar.SECOND, 0);
if you just need the minutes to match.
Quick explanation of what is going on:
The JavaDoc for Calendar states:
Compares the time values (millisecond offsets from the Epoch)
represented by two Calendar objects.
So you acknowledge that ".. long time in millis for both dates are different .."
#JonSkeet says in this question:
Calendar.setTime takes a java.util.Date, which is just a wrapper
around a long indicating the number of milliseconds since midnight Jan
1st 1970, UTC. It's not "in the format MM/dd/yyy" - that's a string
representation, not a java.util.Date. If it happens to print something
out in the format MM/dd/yyyy, that's just what Date.toString is doing
for you - it's not inherently part of the format.
This should answer your question about what is going on.
Note: java.util.Date has the same problem.
PS. A lot of people say use Joda Time, which I have heard is going to be in Java 8, but I have not personally tried it. If you are going to be using a lot of date code, I'd recommend you use it.
I invoked compareTo on Date instead of Calendar and got the correct result. It might be because of the fact that Calendar stores Timezone information but Date object does not.
Thanks
I would like to know exactly how many months and days(possibly years) some older date is from today. Is there a method to do that?
I know how to get the difference of the months, I know how to get the difference in days. But I am unable to get the months and the days.
Ex:
old = '2013-03-04'
now = '2013-04-17'
so the result im looking for is something like 1 month(s) and 13* day(s)
*maybe its 12 im not every sure.
This can be done by using Period in JodaTime.
For example,
LocalDate old = new LocalDate(2013, 3, 4);
LocalDate now = new LocalDate(2013, 4, 17);
Period p = new Period(old, now, PeriodType.yearMonthDay());
To get the months, use p.getMonths(), to get the days p.getDays().
The result of the example is 1 month, 13 days.
Yes, see the documentation of intervals:
Intervals
An interval in Joda-Time represents an interval of time from one
instant to another instant. Both instants are fully specified instants
in the datetime continuum, complete with time zone.
Intervals are implemented as half-open, which is to say that the start
instant is inclusive but the end instant is exclusive. The end is
always greater than or equal to the start. Both end-points are
restricted to having the same chronology and the same time zone.
Two implementations are provided, Interval and MutableInterval, both
are specializations of ReadableInterval.
So I'm using JodaTime in an app I've got and I need a way to tell if the current time is within 6 hours of midnight. Well actually I need to know if the time is within 8 hours of 2am, but JodaTime seems to provide a constant for midnight so I was looking at that. Anyway, I've tried a number of different things but nothing quite works. Any help or pointers would be appreciated.
This can be accomplished simply by using JodaTime without any math involved.
DateTime time = new DateTime(DateTimeZone.UTC);
Period period = new Period(time, time.plusDays(1).toDateMidnight());
System.out.println(period.getHours());
The time.plusDays(1).toDateMidnight() (yes, I was lazy), is so that I'm comparing with the next midnight, and not with today's midnight (which already passed).
If you want to check both before and after, just check both periods.
I would suggest using a DateTime object.
DateTime date = new DateTime();
int i = getSecondOfDay();
Then using a little math we can find the number of seconds 6pm would be.
18hours*60min*60seconds= 64800 seconds.
if ( i > 64800 ){
// Do what you need here
}
I assumed you needed to tell if it was 8 hours of am of this current day and not a specific day.
This is a bit hardcoded and pcalcao's answer is probably more flexible:
private static boolean isLessThan8HoursFrom2AM(DateTime date) {
return (date.getHourOfDay() >= 18 || date.getHourOfDay() < 10);
}
You can also check if the time of day is 6 hours from midday.
if(Math.abs(timeOfDay - 43200) >= 21600) // first or last 6 hours of day.