0

I am stuck with an issue of timezone for date/time calculation in my code. will need your suggestions on the same. below is the scenario.

My application has to pick data from a hbase db. This data will be picked based on a date search criteria from a table in hbase. The table has a date time column which is used for the filtering.

Now the other application which populates data in this table is inserting datetime in GMT timezone format(which is what that team says). The application is deployed on a server which is in EST timezone. I get a input date(no time component) from the user which i will need to convert to GMT timezone. But currently what is happening is that when i do the conversion some data is not being picked in the EST timezone.The same data is getting picked in my local timezone IST. I have done the conversion to GMT in the code which is deployed in both my local and remote server.example below.

Date for which data is present in table : 2013-03-15 01:30:30

Data input by user : 2013-03-15 (No time component). I specifically added time component.

Date after adding time component : Start Date -2013-03-15 00:00:00, End Date - 2013-03-15 23:59:59.

I am in IST timezone(UTC+5:30). so both the start and end dates converted to GMT are

Start Date converted to GMT -2013-03-14 18:30:56.

End Date converted to GMT - 2013-03-15 18:30:56.

Now since the date provided by the user 2013-03-15 01:30:30 falls in the above range the data from the table is getting pulled in this timezone.

The same code is deployed in remote server which is in EST(UTC-5:00).

Start Date converted to GMT -2013-03-15 05:00:56.

End Date converted to GMT - 2013-03-16 05:00:56.

Now since the data provided by the user 2013-03-15 01:30:30 does not fall in this range data is not getting pulled up.

I am not sure about how to handle this scenario so that the calculation is consistent across timezones. because the testers say that the data should be consistent across timezones. but as you see the GMT conversion has been done but the dates are off by the offsets in both timezones and data is not getting pulled up. If you can let me know how to handle this it would be great help.

I have not put any code here as its a standard code for timezone found online and is same in most of the cases.

Roman C
  • 49,761
  • 33
  • 66
  • 176
vikeng21
  • 543
  • 8
  • 28
  • Do you really *want* the original data to be interpreted as if it's in IST or EST? Your requirements are very unclear, but using the default time zone of the server is almost *always* the wrong choice. And you should *absolutely* include your code - it's impossible to have any idea what you're doing wrong without that. – Jon Skeet Mar 19 '13 at 19:25
  • Thanks Jon. well that's my dilemma here. how do i interpret the data. as pcalcao has said below that i will have to handle inputs in a consistent time zonw. I guess GMT is well suited for this. your thoughts on the same. well i don't have the code right now with me but i guess i can pass that. – vikeng21 Mar 19 '13 at 19:51
  • 1
    What you're missing is *requirements* - and we can't tell you those. We don't know what the values are meant to represent, or what the meaning of the user's input is meant to be. – Jon Skeet Mar 19 '13 at 19:55

2 Answers2

0

It really depends on what you're trying to achieve here.

If you truly want the input to be interpreted as local time, and converted to GMT to check the Database, then the results are actually consistent, think of the problem the other way around, which records would you get if you magically converted every date in HBase to your local time?

If the dates the user inputs are actually TZ specific, then it's only natural that the same date "text" returns different results, since two users are actually referring to two different moments in time.

If, on the other hand, you need users that give the same input to get exactly the same results, then you need to assume that the input is already in some consistent TZ, for instance, always in UTC (or GMT in your case).

Basically what you need to decide is:

Is the input 2013-03-15 given by the user specific to the TZ of the user? Or is it always the same moment in time, in a specific TZ? IST, EST, GMT, you decide.

If you make that decision, your results will be consistent.

pcalcao
  • 15,789
  • 1
  • 44
  • 64
  • thanks pcalcao. The dates the users provide are not TZ specific. Its just REST URL that is being hit by the users in different TZ at different instance(or same) of time. I got your first point. But for the second point what you are saying is that i will have to assume 2013-03-15 in GMT every time. So is any conversion to GMT required in this case for the date input by the user or how do i handle this scenario – vikeng21 Mar 19 '13 at 19:48
  • Like @jon-skeet said, what you actually need to do is a matter of requirements, and seems to me that you need to straighten those out with whoever makes decisions for that product. – pcalcao Mar 19 '13 at 19:57
0

tl;dr

Using Half-Open query logic:

SELECT * 
FROM tbl 
WHERE when >= ? AND when < ?   -- Half-Open logic, where beginning is inclusive while the ending is exclusive.
;

Query with two parameters:

  • start-of-day moment
  • start-of-following-day moment

Using java.time classes in modern Java:

myPreparedStatement.setObject(  
    1 , 
    LocalDate.parse( "2013-03-15" )         // Represent entire day as a `LocalDate` object.
        .atStartOfDay(                      // Determine first moment of that date in a particular time zone, which may or may not be 00:00:00.
            ZoneId.of( "Asia/Kolkata" ) 
        )                                   // Returns a `ZonedDateTime` object. Your JDBC driver should be able to handle that smartly. If not, extract a `Instant` object in UTC by calling `ZonedDateTime::toInstant()`.
) ; 


myPreparedStatement.setObject( 
    2 , 
    LocalDate.parse( "2013-03-15" )        
        .plusDays( 1 )                     // Move to the following day.
        .atStartOfDay( 
            ZoneId.of( "Asia/Kolkata" ) 
        )
) ; 

Upon retrieval, adjust into any desired time zone.

myResultSet.getObject( … , Instant.class)  // Extract a `Instant` object from selected row.
    .atZone(                               // Apply a `ZoneId` to get a `ZonedDateTime` object.
        ZonedId.of( "America/Montreal" )
    )

Server default time zone irrelevant

Your server’s current default time zone should be irrelevant to your programming. You should be specifying the desired/expected time zone via optional arguments to the various date-time methods.

Ditto for Locale, by the way: Specify explicitly rather than rely on current default implicitly.

In my opinion, those arguments should be required rather than optional. Seems that a great many programmers ignore the issues of time zone and locale.

java.time

The modern approach uses java.time time classes.

With a JDBC driver compliant with JDBC 4.2 or later, you can directly exchange java.time types with your database.

For a moment in UTC, use Instant. For a date-only without a time-of-day and without a time zone, use LocalDate.

LocalDate ld = LocalDate.parse( "2013-03-15" ) ;

To search the database records holding a moment within the range of an entire day, we need to determine the first moment of that day and the first moment of the following day. Then we do a Half-Open query where the beginning is inclusive while the ending is exclusive.

Do not assume the day starts at 00:00:00. Anomalies such as Daylight Saving Time (DST) means the day may start at some other time such as 01:00:00. We need a time zone for this.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;  // Determine when that particular day begins in that particular zone.

And the following day. Call LocalDate::plusDays to move to the following day.

ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDays( z ) ;

If you want to see that same moment as UTC wall-clock time, extract an Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant start = zdtStart.toInstant();
Instant stop = zdtStop.toInstant() ;

Your SQL should look something like:

String sql = "SELECT * FROM tbl WHERE when >= ? AND when < ? ;" ; // Half-open logic, where beginning is inclusive while the ending is exclusive.

Pass values for the placeholders.

myPreparedStatement.setObject( 1 , start ) ; // You can exchange java.time object with JDBC 4.2 or later.
myPreparedStatement.setObject( 2 , stop ) ; 

And retrieval.

Instant instant = myResultSet.getObject( "when" , Instant.class ) ;

If you want to view that same moment through the lens of a wall-clock time used by the people of another region (time zone), apply a ZoneId to get a ZonedDateTime.

ZonedDateTime zdt = instant.atZone( ZoneId.of( "America/New_York" ) ) ;

UTC

Just a tip: Generally best to think, store, exchange, and log values in UTC. Adjust into a time zone only when the business logic or user interface demand it.

When at work programming or administrating, forget about your own parochial time zone and think in UTC instead. Keep a clock in UTC on your desk. Think of UTC as the One True Time™ and all other zones are but mere variations.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

With a JDBC driver complying with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings or java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154