Compensating for BST when calculating difference between 2 times - java

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

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).

Date gives one day less than actual date while converting from date to calendar

I am passing date from front end which is IST(date of indian timezone). And in java code i am converting date to calendar using the following code(This is happening in the server which is there in US PST timezone).
Calendar cal = Calendar.getInstance();
int offset = date.getTimezoneOffset();
logger.info("Calendar Instance - " + cal);
cal.setTime(date);
logger.info("Calendar Instance after setting date - " + cal);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
logger.info("Calendar Instance after setting zeros - " + cal);
return cal;
so when i see the last log the day of the month will be one day less than what i passed.eg. if i pass 22/06/2015 IST it shifts to 21/06/2015. so after processing finally it displays 21/06/2015 in the list of data which is in another UI page.
This happens because JVM on server side and JVM on client side use different time zones by default Java TimeZone:
Typically, you get a TimeZone using getDefault which creates a
TimeZone based on the time zone where the program is running. For
example, for a program running in Japan, getDefault creates a TimeZone
object based on Japanese Standard Time.
As we can see, Pacific Time Zone on server has UTC−8:00 and Indian Standard Time on client has UTC+05:30. They differ by 13.30 and Indian date X converts to US as X-13.30 what may yield a day before on server side for certain X.
Several workarounds are possible depending on how you can influence/modify your server and client application. For example, you may work with dates in UTC+00:00 time zone on both server and client sides. If you need to show a date to the user you may convert it to Indian time zone when needed.
// Set default GMT+0:00 time zone
TimeZone timeZone;
timeZone = TimeZone.getTimeZone("GMT+0:00");
TimeZone.setDefault(timeZone);
Instead of simply using Calendar cal = Calendar.getInstance(); you may create "clear" calendar which you will user later on to set day, month and year
public static Calendar createClearedCalendar() {
Calendar cal = Calendar.getInstance();
cal.setTimeZone(timeZone);
cal.set(1970, 0, 1, 0, 0, 0);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.clear(Calendar.MILLISECOND);
return cal;
}
By the way, if you manipulate date-time in Java you may consider Joda Time which has more extended options and optimized performance.
The Answer by Antonio is correct and should be accepted (click the big empty check mark).
This Answer adds some thoughts and example code.
Avoid 3-Letter Time Zone Codes
Avoid using, or even thinking about, those 3 or 4 letter codes such as IST or PST. They are not standardized, they are not unique, and they further confuse issues around Daylight Saving Time (DST). For example, IST means "India Standard Time", "Irish Standard Time", and more.
Use proper time zone names. Most of these are in a "continent" + "/" + "city/region" pattern. The city/region name is not meant specifically for that town, but rather as an easily identifiable name for as wide an area as possible that shares the same set of past, present, and future rules for time zone rules and anomalies (including DST).
Use UTC
Generally you should be using UTC time zone for all your business logic, data storage, and data exchange. Adjust to a particular time zone only for presentation when expected by the user.
Use A Decent Date-Time Framework
The old java.util.Date/.Calendar classes were a bold attempt at handling date-time work, but ultimately they failed. They are notoriously troublesome, flawed in both design and implementation. Avoid them.
The 3rd-party Joda-Time library is one solution. It works in many versions of Java and also in Android. Joda-Time inspired the other solution, the java.time package found in Java 8 and later (Tutorial).
Solution
The Question seems to have a goal of taking a java.util.Date object, assign desired time zone, and produce a java.util.Calendar object.
Fortunately the java.time framework has conversion methods. See this Tutorial page.
Example code follows, using java.time from Java 8 Update 45.
You may want imports such as:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
Let's simulate getting a java.util.Date passed in. We'll instantiate a Date based on "now".
Date inputDate = new Date( ); // Simulate getting a java.util.Date object.
Then we define the desired time zones, using proper time zone names. Let’s throw in Montréal just for fun as well as the pacific United States and India time zones mentioned in the Question.
ZoneId zoneLosAngeles = ZoneId.of( "America/Los_Angeles" );
ZoneId zoneMontréal = ZoneId.of( "America/Montreal" );
ZoneId zoneKolkata = ZoneId.of( "Asia/Kolkata" );
Then we convert that to an Instant, a point on the timeline without regard to time zone.
Instant instant = inputDate.toInstant( );
Then we assign various time zones to create ZonedDateTime instances. See how we can instantiate a ZonedDateTime in either of two ways: [a] from an Instant, or [b] from another ZonedDateTime via the withZoneSameInstant method. Both ways are shown below.
Note that java.time (and Joda-Time) uses immutable objects, a design pattern where we create new instances based on the old instance rather than alter ("mutate") the old instance. Thread-safety is one of the major benefits.
ZonedDateTime zdtLosAngeles = ZonedDateTime.ofInstant( instant, zoneLosAngeles );
ZonedDateTime zdtMontréal = ZonedDateTime.ofInstant( instant, zoneMontréal );
ZonedDateTime zdtKolkata = ZonedDateTime.ofInstant( instant, zoneKolkata );
ZonedDateTime zdtUtc = zdtKolkata.withZoneSameInstant( ZoneOffset.UTC );
Lastly, we convert one of those to a GregorianCalendar object which is a subclass of java.util.Calendar.
GregorianCalendar calendarKolkata = GregorianCalendar.from( zdtKolkata );
Dump to console.
System.out.println( "inputDate: " + inputDate );
System.out.println( "zdtLosAngeles: " + zdtLosAngeles );
System.out.println( "zdtMontréal: " + zdtMontréal );
System.out.println( "zdtKolkata: " + zdtKolkata );
System.out.println( "zdtUtc: " + zdtUtc );
System.out.println( "calendarKolkata: " + calendarKolkata );
When run.
inputDate: Wed Jun 24 15:12:12 PDT 2015
zdtLosAngeles: 2015-06-24T15:12:12.153-07:00[America/Los_Angeles]
zdtMontréal: 2015-06-24T18:12:12.153-04:00[America/Montreal]
zdtKolkata: 2015-06-25T03:42:12.153+05:30[Asia/Kolkata]
zdtUtc: 2015-06-24T22:12:12.153Z
calendarKolkata: java.util.GregorianCalendar[time=1435183932153,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Asia/Kolkata",offset=19800000,dstSavings=0,useDaylight=false,transitions=6,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2015,MONTH=5,WEEK_OF_YEAR=26,WEEK_OF_MONTH=4,DAY_OF_MONTH=25,DAY_OF_YEAR=176,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=4,AM_PM=0,HOUR=3,HOUR_OF_DAY=3,MINUTE=42,SECOND=12,MILLISECOND=153,ZONE_OFFSET=19800000,DST_OFFSET=0]

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)

Java-Adding timezone to date when date is grabbed from datepicker

I have a jsp page that takes the value from a jquery datapicker and passes it into a search. The user of the site has the opportunity to change their timezone to fit where they are located in the world. I want to take the value searched which is based off the browsers time and format it and show it on screen with the user’s timezone.
The column is expireDate and I use datatables to display the results.
{
"mData":"expireDate",
"mRender":function(source,type,full){
if(-1==source)
return "";
var toDate = new Date(source);
var stringDate = toDate.toString(dateTableFormater);
return stringDate;
I get the value and pass in my own custom formatting, the formatting is based on where the person lives. Each format is different depending on where they live and prevents me from using the simpledateFormat.setTimezoneOffset();
$("#expireFrom").datepicker($.datepicker.regional[plannerLang]);
$("#expireFrom").datepicker( "option", "dateFormat",dateFormater);
$("#expireTo").datepicker($.datepicker.regional[plannerLang]);
$("#expireTo").datepicker( "option", "dateFormat",dateFormater);
I have a dto set up so it gets the users Timezone, I just cant figure out how to implemet that so when the time is sent back to the jsp the timezone has been included in the time.
How do you add/subtract the timezone difference from the date that the browser has gotten?
Adjust for Time Zone Offset
Computers track time in a universal manner, free of time zone information. They use a count of seconds/milliseconds/nanoseconds since an epoch. So adjusting for time zone is not a matter of adding or subtracting to the time itself. It's a matter of adjusting the expression of that time/count as a string.
Joda-Time
The bundled java.util.Date/Calendar classes are notoriously bad in both design and implementation. You should use a competent date-time library instead. Currently, that means Joda-Time. In the future, with Java 8, you can continue with Joda-Time or switch to the new bundled java.time.* classes defined by JSR 310. Those classes are inspired by Joda-Time but are entirely re-architected.
A DateTime instance in Joda-Time knows its own time zone, unlike a java.util.Date.
Server Time
Most programmers find it wiser to use the server's clock rather that obtain time from the user’s machine. Users’ machines are notorious for being out of sync with the correct time. That is less true today with the Internet and NTP servers. Nevertheless, I suggest you stick with server’s clock.
From the user’s machine you should obtain their Locale information, country (culture) and language.
By the way, usually best to work in UTC (no time zone offset) in your business logic and switch to a time zone only for presentation to user.
Example Code For 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.*;
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Athens" );
DateTime now_Athens = new DateTime( timeZone );
DateTime now_Seattle = now_Athens.toDateTime( DateTimeZone.forID( "America/Los_Angeles" ));
DateTime now_UTC = now_Athens.toDateTime( DateTimeZone.UTC );
Dump to console…
System.out.println( "now_Athens: " + now_Athens );
System.out.println( "now_Seattle: " + now_Seattle );
System.out.println( "now_UTC: " + now_UTC );
When run…
now_Athens: 2014-01-02T20:11:43.657+02:00
now_Seattle: 2014-01-02T10:11:43.657-08:00
now_UTC: 2014-01-02T18:11:43.657Z
Formatting Strings
Joda-Time has many features for rendering strings via formatting:
You can format with Locale-sensitive Long, Medium, Short formatters.
You can define your own formats.
You can go with standard ISO 8601 formats, the default, as seen above.
Example Code For Formatting
DateTimeZone timeZone_Paris = DateTimeZone.forID( "Europe/Paris" );
String nowLocalizedParis = DateTimeFormat.forStyle("LS").withLocale(Locale.FRANCE).withZone( timeZone_Paris ).print( now_UTC );
Dump to console…
System.out.println( "nowLocalizedParis: " + nowLocalizedParis );
When run…
nowLocalizedParis: 2 janvier 2014 19:11

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