how to add a (big)difference between to dates to another date - java

In a Jython script I want to move a date with the same amount an another date is changed. So in my script I get two variables:
scheduledDate and scheduledDate_previous
Both are java Date objects. I want to apply the difference to another Date: reservationDate
The problem is that with big differences, I get a 'cannot convert to integer'-error on the calendar.add() function. Here's my code:
from java.util import Date
form java.util import Calendar
myDiff = int(scheduledDate.getTime() - scheduledDate_previous.getTime())
reservationCal = Calendar.getInstance()
reservationCal.setTime(reservationDate)
reservationCal.add(Calendar.MILLISECOND, myDiff)
reservationDate = reservationCal.getTime()
If the difference between two dates becomes to large, the myDiff is no longer an Int, but a Big Int
(note that it can also be a negative number!)
So I tried something like this:
reservationCal.add(Calendar.MINUTE, int(myDiff / 60000) )
I don't need that insane presicion anyway. But this didn't work all the time. EDIT It would result in a 'add(): second arg cant be coerced to an int'-error Which seemed fair since if you had a weird difference the division could result in a float. So I tried this:
from java.lang import Math
reservationCal.add(Calendar.MINUTE, int(math.floor(myDiff / 60000)))
I still get an error like:
TypeError: unsupported operant type(s) for: 'java.math.BigInterger' and 'int'
The weird thing is that I don't get this error when I change the date a few days. It happens when I change it 3 months. User are able to change the date and time. They need to change it within a few years.
due to compatibility issues the machine is still on java 32 bit 1.6.0_25. It uses jython 2.5.2
Is there a solution or do I need different approuch?

My other answer correctly solves the direct problem raised in the Question. This answer is a bonus, an alternate avenue to accomplish the goal of calculating and applying elapsed time.
Doing this kind of date-time work is much easier if using either of these libraries:
Joda-Time
java.time package(built into Java 8, inspired by Joda-Time, defined by JSR 310)
The old date-time classes (java.util.Date, .Calendar, java.text.SimpleDateFormat) bundled with Java are notoriously troublesome, confusing, and flawed. Avoid them. If required you can convert to-and-fro with either library listed above.
Joda-Time
The code example below is using Joda-Time 2.5.
Elapsed Time
You can count elapsed time in either of two ways:
Calendar styleNumber of months, weeks, days, and such.
Stopwatch styleTotal number of milliseconds, as if measured with a running stopwatch.
These two ways to measure elapsed time may give different results! This code example shows both.
Time Zone
Unlike j.u.Date, a DateTime object in Joda-Time actually knows its own assigned time zone. That is crucial if you count elapsed time by the calendar style (months, days, and so on). Note how this example uses Montréal, Québec time zone (arbitrarily chosen).
Example Code
// Simulate inputs, a trio of java.util.Date objects.
java.util.Date dateStart = new DateTime( 2014 , 1 , 2 , 0 , 0 , 0 , DateTimeZone.UTC ).toDate();
java.util.Date dateStop = new DateTime( 2014 , 3 , 2 , 0 , 0 , 0 , DateTimeZone.UTC ).toDate();
java.util.Date dateTarget = new DateTime( 2014 , 7 , 1 , 0 , 0 , 0 , DateTimeZone.UTC ).toDate();
// Convert inputs to Joda-Time
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" ); // Or DateTimeZone.UTC.
DateTime start = new DateTime( dateStart , timeZone );
DateTime stop = new DateTime( dateStop , timeZone );
DateTime target = new DateTime( dateTarget , timeZone );
// Determine elapsed time in three fashions: (a) pair of points on timeline, (b) An amount of weeks, days, hours, and such, and (c) actual milliseconds.
Interval interval = new Interval( start , stop );
Period period = interval.toPeriod();
Duration duration = interval.toDuration();
// Add elapsed time to target date-time. Show results of adding either period or duration.
DateTime laterByPeriod = target.plus( period );
DateTime laterByDuration = target.plus( duration );
Dump to console.
System.out.println( "dateStart: " + dateStart ); // BEWARE: j.u.Date objects are in UTC by definition, but "toString" method applies the JVM's current default time zone. Misleading!
System.out.println( "dateStop: " + dateStop );
System.out.println( "dateTarget: " + dateTarget );
System.out.println( "start: " + start );
System.out.println( "stop: " + stop );
System.out.println( "target: " + target );
System.out.println( "interval: " + interval );
System.out.println( "period: " + period );
System.out.println( "duration: " + duration );
System.out.println( "laterByPeriod: " + laterByPeriod ); // Notice the change in offset because of DST (Daylight Saving Time) in Québec.
System.out.println( "laterByDuration: " + laterByDuration );
When run.
dateStart: Wed Jan 01 16:00:00 PST 2014
dateStop: Sat Mar 01 16:00:00 PST 2014
dateTarget: Mon Jun 30 17:00:00 PDT 2014
start: 2014-01-01T19:00:00.000-05:00
stop: 2014-03-01T19:00:00.000-05:00
target: 2014-06-30T20:00:00.000-04:00
interval: 2014-01-01T19:00:00.000-05:00/2014-03-01T19:00:00.000-05:00
period: P2M
duration: PT5097600S
laterByPeriod: 2014-08-30T20:00:00.000-04:00
laterByDuration: 2014-08-28T20:00:00.000-04:00

Use a long (64-bit integer) rather than an int (32-bit integer). As described in the Tutorial by Oracle.

Related

Create instance of joda DateTime from integer representing # of days since epoch?

In my application, it saves a preference which is an integer that is the number of days since the epoch. (not relevant but it is used to create backups every x days)
Given this value, how can I reliably create an instance of joda DateTime?
I'm tempted to convert it to milliseconds by doing the multiplication value * 24 * 60 * 60 * 1000 but this will be wrong due to astronomy / solar time?
Multiplying number of days into the number of milliseconds might be more readable if you use a library function. I highly recommend using Joda. :)
You have a number of days since epoch (GMT), and you want a DateTime (date + time + timezone). At a bare minimum, before you get further, you'll need to specify how you want to treat the time and timezone calculation.
The simplest way (which might not be what you intend) would be to create an instant in the local timezone representing the beginning of epoch, and then use plusDays to add the right number of days:
// in class - note that this will cache the current default timezone
private static final DateTime EPOCH_START_INSTANT = new DateTime(0);
// West of Greenwich, this will actually represent the "day" before.
// Day 0 will be Dec 31, 1969, local time.
DateTime localTime = EPOCH_START_INSTANT.plusDays(yourDayCount);
For the purpose of creating a backup every X days, you might instead want a LocalDate initialized at epoch (January 1, 1970), plus the number of days you want. That could then be changed to a specified local time relatively easily.
// in class
private static final EPOCH_LOCALDATE = new LocalDate(1970, 1, 1);
private static final THREE_AM = new LocalTime(3, 0);
LocalDate localDate = EPOCH_LOCALDATE.plusDays(yourDayCount);
// Midnight (or closest valid time thereto) in the default time zone
DateTime startOfDay = localDate.toDateTimeAtStartOfDay();
// 3 AM in the default time zone
DateTime threeAM = localDate.toDateTime(THREE_AM);
The answer by Jeff Bowman is correct.
I'll show the same idea in the java.time framework, intended to succeed Joda-Time.
java.time
Java 8 and later has the new java.time framework built-in. These new classes supplant the old java.util.Date/.Calendar classes. They are inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.
I am assuming your count-of-day-from-epoch is in UTC. So we can use the Instant class, basically a count of nanoseconds from the first moment of 1970 in UTC.
long myCountOfDays = 16_721L;
Instant instant = Instant.EPOCH.plus ( myCountOfDays , ChronoUnit.DAYS );
Let's adjust into a time zone. Choosing Montreal arbitrarily. Use a proper time zone name, never the 3-4 letter codes like "EST" or "IST".
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
Dump to console.
System.out.println ( "myCountOfDays: " + myCountOfDays + " from epoch: " + Instant.EPOCH + " in UTC is: " + instant + " and in Montréal is: " + zdt + "." );
When run.
myCountOfDays: 16721 from epoch: 1970-01-01T00:00:00Z in UTC is: 2015-10-13T00:00:00Z and in Montréal is: 2015-10-12T20:00-04:00[America/Montreal].
According to the FAQ:
Joda-Time does not support leap seconds. Leap seconds can be supported by writing a new, specialized chronology, or by making a few enhancements to the existing ZonedChronology class. In either case, future versions of Joda-Time will not enable leap seconds by default. Most applications have no need for it, and it might have additional performance costs.
That suggests to me that you need not worry about that aspect.
But rather than doing the math, I would use DateTime#plusDays or MutableDateTime#addDays instead, using The Epoch as your starting point.
I assume, though, that your "days since The Epoch" is allowing for leap days (and that you're using the Gregorian chronology so JodaTime is, too).

Difference between two dates, in days, varies

Date d = new Date(today.getTimeInMillis());
Date d1 = new Date(dueDate.getTimeInMillis());
int daysUntil = (int) ((d1.getTime() - d.getTime())/ (1000 * 60 * 60 * 24));
Using the above code, where today is a calendar set to 00:00 on the current day, and dueDate is set to 00:00 on the date I am comparing today to, my results from this differ.
There is something in this which varies, making my output either x or x+1 where x is the correct answer.
What is the issue here, and what can I do to make it more stable?
Vague Question
You do not provide actual values, so we cannot determine precisely the problem. We do not know what the today and dueDate variables are.
Outmoded
The question is now outmoded, as the troublesome old date-time classes including java.util.Date/.Calendar have been supplanted by the new java.time framework. See Tutorial. Defined by JSR 310, inspired by Joda-Time, and extended by the ThreeTen-Extra project.
In java.time:
An Instant is a moment on the timeline in UTC.
A ZoneId represents a time zone. Use proper time zone names, never the 3-4 letter codes like "EST" or "IST" as they are neither standardized nor unique.
Conceptually, ZonedDateTime = Instant + ZoneId.
ThreeTen-Extra
Unfortunately, java.time does not include a facility for calculating days elapsed between date-time values. We can use the ThreeTen-Extra project and its Days class with between method to provide that calculation. The ThreeTen-Extra project is a collection of features deemed non-essential for java.time during the JSR process.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime then = now.minusDays ( 4 );
ZonedDateTime due = now.plusDays ( 3 );
Integer days = org.threeten.extra.Days.between ( then , due ).getAmount ();
Dump to console.
System.out.println ( "From then: " + then + " to due: " + due + " = days: " + days );
From then: 2015-10-31T16:01:13.082-04:00[America/Montreal] to due: 2015-11-07T16:01:13.082-05:00[America/Montreal] = days: 7
Joda-Time
For Android or older versions of Java, use the excellent Joda-Time library.
The Days class is smart and handles anomalies such as Daylight Saving Time (DST).
Note that unlike java.util.Date, a Joda-Time DateTime object knows its own time zone.
// Specify a time zone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( "America/Regina" ); // Or "Europe/London".
DateTime now = new DateTime( timeZone );
DateTime startOfToday = now.withTimeAtStartOfDay();
DateTime fewDaysFromNow = now.plusDays( 3 );
DateTime startOfAnotherDay = fewDaysFromNow.withTimeAtStartOfDay();
Days days = Days.daysBetween( startOfToday, startOfAnotherDay );
Dump to console…
System.out.println( days.getDays() + " days between " + startOfToday + " and " + startOfAnotherDay + "." );
When run…
3 days between 2014-01-21T00:00:00.000-06:00 and 2014-01-24T00:00:00.000-06:00.
There are mainly two reasons why your code is broken:
second parts or millisecond fractions (you might have overlooked)
daylight saving effects
I demonstrate and explain the second reason.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse("2016-03-20");
Date d2 = sdf.parse("2016-03-28");
int daysUntil = (int) ((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
System.out.println(daysUntil); // 7 (should be 8)
The code was run in timezone "Europe/Berlin". Due to the change from winter time to summer time causing a jump of clocks by one hour forward on 2016-03-27 at 2 am, there is one hour missing. One day has only 23 hours so the division by 24 yields zero resulting in counting one day less.
What can you do else?
Your workaround adding 1000 milliseconds to dueDate sounds as if you have overlooked possible millisecond deltas in your input. This might solve a special case but will usually not be sufficient to solve the daylight saving problem, too. Whatever you choose on base of java.util.Date it is a more or less an evil hack.
The best I have in mind (within the scope of Android-built-in stuff) is to construct an instance of java.util.GregorianCalendar and to add successively one day after one until you have passed the due-date, and then count how many days you have added. Not elegant and errorprone because varying millisecond parts can easily be overlooked here, too.
Otherwise you can try various external libraries for this task. There are four available on Android which can calculate elapsed days in an easy way.
Date4J (main advantage: very small but else limited features)
Threeten-ABP (uses backport of Java-8)
Joda-Time-Android (based on Joda-Time)
Time4A (my own library for Android)

Compensating for BST when calculating difference between 2 times

I need some help or a pointer in the right direction.
I am trying to get the difference between 2 times. I am in UK on GMT with timezone set to adjust for daylight saving automatically.
When I preform the following it is always 1 hour out unless, I switch off automatically adjust for daylight saving.
String strDate = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date().getTime() - oldDate.getTime());
If I run the following there is not the 1 hour difference the 2.
System.out.println("Current time " + Formats.HOURMIN.formatValue(new Date().getTime()));
System.out.println("Old time " + Formats.HOURMIN.formatValue(oldDate.getTime()));
Any assistance would be appreciated.
The cardinal rule for calculating time intervals when different timezones are involved is to make sure to convert the times to UTC before subtracting.
Each time, no matter what zone and DST offset is in effect at the time (pun somewhat intended), converts to a unique UTC instant. Once you have the times in UTC, calculating the difference is a simple subtraction. The result is time-zone-independent.
The java.util.Date class has no time zone attached to it yet confusingly uses your default time zone when rendering a string. I'm guessing this may be your problem. One of many reasons to avoid java.util.Date/Calendar classes.
The Joda-Time 2.3 library makes this kind of work easier. Look at the Period, Duration, and Interval classes.
In contrast to a java.util.Date, in Joda-Time a DateTime instance does indeed know its assigned time zone.
The ISO 8601 standard defines a way to describe durations as hours, minutes, and such in a PnYnMnDTnHnMnS format. I use that in my example code below. Joda-Time offers other ways as well.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone timeZone = DateTimeZone.forID( "Europe/London" );
DateTime dateTimeNew = new DateTime( timeZone );
DateTime dateTimeOld = dateTimeNew.minusHours( 2 );
Period period = new Period( dateTimeOld, dateTimeNew );
Dump to console…
System.out.println( "dateTimeNew: " + dateTimeNew );
System.out.println( "dateTimeOld: " + dateTimeOld );
System.out.println( "period: " + period );
When run…
dateTimeNew: 2014-01-02T23:19:45.021Z
dateTimeOld: 2014-01-02T21:19:45.021Z
period: PT2H

Java and Joda-Time: date wrong value

I'm getting a wrong date in Joda-Time when I try to parse a string date like this:
2013-11-20 18:20:00 +01:00
I'm expecting to obtain the following date:
Wed Nov 20 19:20:00 CET 2013
but I'm getting:
Wed Nov 20 18:20:00 CET 2013
I'm using Joda-Time and this is my code:
String dateString = "2013-11-20 18:20:00 +01:00";
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z");
DateTime temp = formatter.parseDateTime(dateString);
Date date = temp.toDate();
Expectations
Your expectation is wrong.
The "+01:00" means that time is one hour ahead of UTC/GMT. So, adjusting to UTC means subtracting an hour (17:20) rather than adding (19:20).
The "+01:00" has the same effect as saying CET (Central European Time), meaning one hour ahead of UTC/GMT. So…
2013-11-20 18:20:00 +01:00 = Wed Nov 20 18:20:00 CET 2013
…those are two different ways of stating the same time, same hour.
When I run your code here in United States west coast time, I get… (note the same hours)
temp: 2013-11-20T09:20:00.000-08:00
date: Wed Nov 20 09:20:00 PST 2013
j.u.Date Confusion
As the answer by Stroboskop said, you may be fooled by java.util.Date. The object itself does not have time zone information. Yet it's implementation of the toString() method uses the default time zone in rendering the text to be displayed. Confusing. One of many reasons to avoid using the java.util.Date/Calendar classes. In contrast, Joda-Time DateTime objects do indeed know their own time zone.
Specify Time Zone
Your real problem is an all too common one: Ignoring time zones. By not specifying a time zone, your default time zone was used. As you can see above, my default time zone is different than yours, so I got different results while running the same code.
A better practice is to always specify your time zone. If you want UTC/GMT, say so. If you want CET, say so. (Actually, don't use the three-letter code like CET as they are not standardized and have duplicates – use a time zone name such as Europe/Prague or Europe/Paris.) When parsing that string, specify the time zone to be incorporated within the new DateTime object.
Example Code
Here is some example code showing how to specify the time zone while parsing. Note the call to withZone().
Note that the result of all three parsings is the same moment in the time line of the Universe. To make that point, my code dumps to the console the milliseconds since the Unix Epoch backing each DateTime object. Usually I try to not use nor think about the milliseconds-since-epoch. But here the use of milliseconds-since-epoch proves a point.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
String dateString = "2013-11-20 18:20:00 +01:00";
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss Z");
// Time Zone list… http://joda-time.sourceforge.net/timezones.html (not quite up-to-date, read page for details)
DateTime dateTimeInUtc = formatter.withZone( DateTimeZone.UTC ).parseDateTime( dateString );
DateTime dateTimeInPrague = formatter.withZone( DateTimeZone.forID( "Europe/Prague" ) ).parseDateTime(dateString);
DateTime dateTimeInVancouver = formatter.withZone( DateTimeZone.forID( "America/Vancouver" ) ).parseDateTime(dateString);
Dump to console…
System.out.println( "dateTimeInUtc: " + dateTimeInUtc + " … In Milliseconds since Unix Epoch: " + dateTimeInUtc.getMillis() );
System.out.println( "dateTimeInPrague: " + dateTimeInPrague + " … In Milliseconds since Unix Epoch: " + dateTimeInPrague.getMillis() );
System.out.println( "dateTimeInVancouver: " + dateTimeInVancouver + " … In Milliseconds since Unix Epoch: " + dateTimeInVancouver.getMillis() );
When run… (Note that whether this code runs on your computer or mine, we both get the same results!)
dateTimeInUtc: 2013-11-20T17:20:00.000Z … In Milliseconds since Unix Epoch: 1384968000000
dateTimeInPrague: 2013-11-20T18:20:00.000+01:00 … In Milliseconds since Unix Epoch: 1384968000000
dateTimeInVancouver: 2013-11-20T09:20:00.000-08:00 … In Milliseconds since Unix Epoch: 1384968000000
Standard question: what time zone are you in? CET?
I assume the parsed DateTime is correct? What timezone does it have?
Bear in mind that Date doesn't have timezones. I'm not even sure if it actually considers Timezone.getDefault().
So, in short it looks like you have a timezone different from +1 and that's why your time is moved by one hour.
-- edit --
hold on. why do you even expect 19:20? The text says 18:20 +1, Joda parses this just like that and Date drops the timezone. That's it.

Explaination of time format (Google Directions API)

I have read the documentation of the Google Directions API for making a direction request. An example of a URL is given as
http://maps.googleapis.com/maps/api/directions/json?origin=Brooklyn&destination=Queens&sensor=false&departure_time=1343605500&mode=transit
The value of the departure_time variable is supposed to reflect the following information:
July 30, 2012 at 09:45 am.
Can someone please explain this time format.
Thanks.
It's a timestamp - seconds elapsed since the Unix epoch, 1970-01-01 00:00:00 UTC. If you want "right now" in that format, you can use System.currentTimeMillis() / 1000, or if you have a Date object, you can use date.getTime() / 1000.
That's an epoch unix timestamp (number of seconds since Jan 1 1970). You can create a date by
Date d = new Date(1343605500L);
Or use http://www.epochconverter.com/
Flaw In Google Documentation
Googling for that particular number led to places such as this similar StackOverflow.com question. These pages lead me to conclude that the documentation for Google Directions API is flawed.
You and others report that the doc says 1343605500 = July 30, 2012 at 09:45 am in New York. But that is incorrect. Both the day of month and the hour of day are wrong.
1343605500 seconds from the beginning of the year 1970 UTC/GMT:
In New York is 2012-07-29T19:45:00.000-04:00
In UTC/GMT is 2012-07-29T23:45:00.000Z
Getting Date-Time From A Number
As the other answers stated, apparently Google is handing you the number of seconds since the Unix Epoch at the beginning of the year 1970 in UTC/GMT (no time zone offset).
Alternatively to using java.util.Date/Calendar classes, you can use the third-party open-source Joda-Time library.
Here is some example source code to show you how to parse the text into a date-time with time zone.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
// Starting data.
String string = "1343605500";
String timeZoneName = "America/New_York";
// Convert string of seconds to number of milliseconds.
long millis = Long.parseLong( string ) * 1000 ; //
// Specify time zone rather than rely on default.
DateTimeZone timeZone = DateTimeZone.forID( timeZoneName );
// Instantiate DateTime object.
DateTime dateTime = new DateTime( millis, timeZone );
System.out.println( "dateTime: " + dateTime );
System.out.println( "dateTime in UTC/GMT: " + dateTime.toDateTime( DateTimeZone.UTC ) );
When run…
dateTime: 2012-07-29T19:45:00.000-04:00
dateTime in UTC/GMT: 2012-07-29T23:45:00.000Z
When using a count from epoch, you must be careful about:
Which epoch (Unix Time is but one of several possibilities)
Precision of count (seconds, milliseconds, nanoseconds)

Categories

Resources