java Date problem

B

Big Jim

Hi, I've an app where swing clients run all over the globe and a java server
and sybase DB is in the UK.

The users trype in dates "mm/ydd/yyyy" for a "deal" object and these get
translated to a long, sent to the server and stored in the DB. Any user in
any location can look at the deals in their own client and I want to make
sure they all see the same date, (times aren't important).
I want to store the dates as midnight GMT in the DB (datetime col).

Can anyone give me the standard procedure for this? my current effort ain't
working,

I reckon there's 4 steps: (c = Calendar.getInstance())

In the client:
1.translating from the user entered java.util.Date to the long to send
to the server, currently I'm using:
longDate = d.getTime() + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET)

2.translating the long sent from the server to the date to display:
date = new date(long + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET))

On the server:
1.translating the long sent from the client to a date to insert into the
DB:
java.sql.Timestamp stamp = new java.sql.Timestamp(long)

2. translating the date in the DB to a long to send to the client
long = stamp.getTime()

problems:
Sometimes dates go into the DB as midnight and sometimes as 1am, sometimes
certain dates get displayed a day early on the client. Do I need to take
offset/dst into account on the server too?

Cheers for any help,
Richard.
 
M

Missaka Wijekoon

Big said:
Hi, I've an app where swing clients run all over the globe and a java server
and sybase DB is in the UK.

The users trype in dates "mm/ydd/yyyy" for a "deal" object and these get
translated to a long, sent to the server and stored in the DB. Any user in
any location can look at the deals in their own client and I want to make
sure they all see the same date, (times aren't important).
I want to store the dates as midnight GMT in the DB (datetime col).

Can anyone give me the standard procedure for this? my current effort ain't
working,

I reckon there's 4 steps: (c = Calendar.getInstance())

In the client:
1.translating from the user entered java.util.Date to the long to send
to the server, currently I'm using:
longDate = d.getTime() + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET)

2.translating the long sent from the server to the date to display:
date = new date(long + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET))

On the server:
1.translating the long sent from the client to a date to insert into the
DB:
java.sql.Timestamp stamp = new java.sql.Timestamp(long)

2. translating the date in the DB to a long to send to the client
long = stamp.getTime()

problems:
Sometimes dates go into the DB as midnight and sometimes as 1am, sometimes
certain dates get displayed a day early on the client. Do I need to take
offset/dst into account on the server too?

Cheers for any help,
Richard.

Big Jim,

On our systems where we have people using the our service across the US
and the globe, we store all time as unix time (i.e num seconds since Jan
1, 1970, UTC). Java lets you get a similar value as a long in terms of
milliseconds (Calendar.get/setTimeInMillis) and you can store that if
you wish. The Date and Calendar classes will let you get and set this
number from the users' local timezone, time and mm/dd/yyyy settings.
The conversion back is just as easy.

Hope this helps,
Missaka
 
B

Big Jim

Missaka Wijekoon said:
Big Jim,

On our systems where we have people using the our service across the US
and the globe, we store all time as unix time (i.e num seconds since Jan
1, 1970, UTC). Java lets you get a similar value as a long in terms of
milliseconds (Calendar.get/setTimeInMillis) and you can store that if you
wish. The Date and Calendar classes will let you get and set this number
from the users' local timezone, time and mm/dd/yyyy settings. The
conversion back is just as easy.

Hope this helps,
Missaka

Cheers Missaka that's exactly what I'm trying to do but it's not working.
I'm looking for someone to verify my client conversions (I'm not sure if I
should be adding or subtracting) and am asking whether I need to do any
further conversion on the server before storing in the DB.
The server is in London which means that sometimes it's GMT and sometimes
BST. The longs it recieves from clients should already be in GMT and I'm
wondering if the "new Date(long)" on the server is not returning the correct
date as on some occasions it could be in BST i.e what (if any) conversion do
I need to perform there?
 
M

Missaka Wijekoon

Big Jim wrote:
snip
Cheers Missaka that's exactly what I'm trying to do but it's not working.
I'm looking for someone to verify my client conversions (I'm not sure if I
should be adding or subtracting) and am asking whether I need to do any
further conversion on the server before storing in the DB.
The server is in London which means that sometimes it's GMT and sometimes
BST. The longs it recieves from clients should already be in GMT and I'm
wondering if the "new Date(long)" on the server is not returning the correct
date as on some occasions it could be in BST i.e what (if any) conversion do
I need to perform there?
Most of the methods in the Date class have been deprecated and I did not
see a facility to set/get the time zone. Try using Calendar class
instead, which have the ability to set time zones. Instantiate a new
Calendar object corrent timezone and locale and then set its utc using
setTimeInMillis(). This way you ought to be able to retrieve the
correct time for the end user, and vice versa.
 
B

Big Jim

Roedy Green said:
see BigDate if you want a pure date. You can store a signed ordinal
days since 1970-01-01
see http://mindprod.com/products1.html#COMMON11

The other way to do it is to use SimpleDateFormat.parse with a UTC
timezone. Then you get a long out the end.

See http://mindprod.com/jgloss/calendar.html

I'd love to but afraid I can't use any 3rd party libs, think I've worked out
how to get it into the DB as GMT properly taking into account that the
server could be in GMT or BST:

Converting "date" to a long in the client:

GregorianCalendar c = new GregorianCalendar(date.getYear(), date.getMonth(),
date.getDate());
gmtLong = date.getTime() + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET)

Converting "long" to a date in the server before DB insert:

Date utilDate = new Date(long);
GregorianCalendar c = new GregorianCalendar(date.getYear(), date.getMonth(),
date.getDate());
Date sqlDate = new Date(long - (c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET));
 
B

Big Jim

Big Jim said:
I'd love to but afraid I can't use any 3rd party libs, think I've worked
out how to get it into the DB as GMT properly taking into account that the
server could be in GMT or BST:

Converting "date" to a long in the client:

GregorianCalendar c = new GregorianCalendar(date.getYear(),
date.getMonth(), date.getDate());
gmtLong = date.getTime() + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET)

Converting "long" to a date in the server before DB insert:

Date utilDate = new Date(long);
GregorianCalendar c = new GregorianCalendar(date.getYear(),
date.getMonth(), date.getDate());
Date sqlDate = new Date(long - (c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET));
and retrieving from the DB in the server and converting to a long to pass to
the client:

c = new GregorianCalendar(dbTimestamp.getYear(),
dbTimestamp.getMonth(), dbTimestamp.getDate());
gmtLongTpPassToClients ts.getTime() + c.getCalendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET);

and displaying the dates in the clients from the long they are passed:

Date date = new Date(longPassedIn);
GregorianCalendar c = new GregorianCalendar(date.getYear(),
date.getMonth(), date.getDate());
Date localDate = new Date(date.getTime() - (c.get(Calendar.ZONE_OFFSET)
+ c.get(Calendar.DST_OFFSET)));

I think I was getting confused before because not only some of the dates to
be saved/retrieved would be subject to DST but the server itself was also
subject to this and needed to convert to GMT before saving the dates or
passing them out to client.
Blimey, not good with times, I even get confused when I go on holiday ...
 
O

Oliver Wong

Big Jim said:
Hi, I've an app where swing clients run all over the globe and a java
server and sybase DB is in the UK.

The users trype in dates "mm/ydd/yyyy" for a "deal" object and these get
translated to a long, sent to the server and stored in the DB. Any user in
any location can look at the deals in their own client and I want to make
sure they all see the same date, (times aren't important).
I want to store the dates as midnight GMT in the DB (datetime col).

Can anyone give me the standard procedure for this? my current effort
ain't working,

I reckon there's 4 steps: (c = Calendar.getInstance())

In the client:
1.translating from the user entered java.util.Date to the long to send
to the server, currently I'm using:
longDate = d.getTime() + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET)

Notice that if you do this, midnight GMT might not be on the same day as
the day the user entered in. Let's say I live somewhere where it's
GMT-04:00. Let's say it's Monday, April 3rd, 2006, 21:00. If you "convert"
this to GMT via the addition, you'll get Tuesday, April 4th, 2006, 01:00
store in the DB, i.e. the wrong day.

Rather than storing a date in some particular time zone, why don't you
just store number of seconds elapsed since the Unix epoch? The number of
seconds that has elapsed since a given event does not vary based on time
zones, thus allowing you to avoid this whole mess. You send and receive
these numbers of seconds, and only at the client do you then try to "render"
the value into a locale-specific, time-zone-specific String to be displayed.

- Oliver
 
B

Big Jim

Oliver Wong said:
Notice that if you do this, midnight GMT might not be on the same day
as the day the user entered in. Let's say I live somewhere where it's
GMT-04:00. Let's say it's Monday, April 3rd, 2006, 21:00. If you "convert"
this to GMT via the addition, you'll get Tuesday, April 4th, 2006, 01:00
store in the DB, i.e. the wrong day.

Rather than storing a date in some particular time zone, why don't you
just store number of seconds elapsed since the Unix epoch? The number of
seconds that has elapsed since a given event does not vary based on time
zones, thus allowing you to avoid this whole mess. You send and receive
these numbers of seconds, and only at the client do you then try to
"render" the value into a locale-specific, time-zone-specific String to be
displayed.

- Oliver
Unfortunately I'm working with an existing DB where this is stored as a
date.
I'm trying to do the next best thing i.e. I do the conversion on the client
as you suggest but I have to store the dates somehow. In effect, by storing
all the dates as GMT I am storing the number of seconds from epoch as you
suggest. It's the conversion to this number of seconds (on the server)
before sending them to the client that's a pain.
However, by taking the zone and DST into account when doing this conversion
at least I'm not limiting my (CORBA) server to being in one location i.e. I
can scale geograpically. It's just disappointing that the java conversion
doesn't seem to work properly (see my later post about timezones)
 
O

Oliver Wong

Big Jim said:
Unfortunately I'm working with an existing DB where this is stored as a
date.
I'm trying to do the next best thing i.e. I do the conversion on the
client as you suggest but I have to store the dates somehow. In effect, by
storing all the dates as GMT I am storing the number of seconds from epoch
as you suggest. It's the conversion to this number of seconds (on the
server) before sending them to the client that's a pain.
However, by taking the zone and DST into account when doing this
conversion at least I'm not limiting my (CORBA) server to being in one
location i.e. I can scale geograpically. It's just disappointing that the
java conversion doesn't seem to work properly (see my later post about
timezones)

Okay, but I noticed in your code that you seem to be doing addition on
the number of seconds since the epoch! You shouldn't be doing this. The Unix
epoch represents a specific point in time, independent of time zones. For
example, if I decided to shout right now, everyone could agree exactly when
it was that I shouted (for simplicity, ignore the theory of relativity).
Even if you're living in a different time zone than me, if you had a
telescope and could observe me, we'd both agree that I shouted, for example,
exactly 20 seconds ago. It's not like I would say "it was 20 seconds ago",
and you would say "no, I disagree, it was 1 hour and 20 seconds ago."

So when you get the number of milliseconds since the epoch, and then
start adding values to it, you're messing up the timestamp. You're saying
"Well, I know Java claims that the epoch occured 1144093110 second ago, but
since I live in a different time zone, I disagree and think it occured
1144096710 seconds ago."

- Oliver
 
B

Big Jim

Oliver Wong said:
Okay, but I noticed in your code that you seem to be doing addition on
the number of seconds since the epoch! You shouldn't be doing this. The
Unix epoch represents a specific point in time, independent of time zones.
For example, if I decided to shout right now, everyone could agree exactly
when it was that I shouted (for simplicity, ignore the theory of
relativity). Even if you're living in a different time zone than me, if
you had a telescope and could observe me, we'd both agree that I shouted,
for example, exactly 20 seconds ago. It's not like I would say "it was 20
seconds ago", and you would say "no, I disagree, it was 1 hour and 20
seconds ago."

So when you get the number of milliseconds since the epoch, and then
start adding values to it, you're messing up the timestamp. You're saying
"Well, I know Java claims that the epoch occured 1144093110 second ago,
but since I live in a different time zone, I disagree and think it occured
1144096710 seconds ago."

- Oliver
but when a user in Tokyo types in 6th March 2006 (defaulting to midnight),
and in his client that gets converted to seconds from the epoch (to send it
to the server), when the server converts this long to a date it'll get 5th
March because (and this is my point):

midnight on 6th March in Tokyo is a different number of seconds from the
epoch than midnight 6th March in London.

Hence the client needs to convert to GMT before sending the long hence the
correction. The server has no idea what timezone the client was in so it
can't do this conversion.

e.g if you do:

new java.util.Date(61081516800000L)
new java.util.Date(61092403200000L)

in London you'll get: Aug 7th 1am Dec 11th midnight
in Tokyo you'll get: Aug 7th 9am Dec 11th 9am

So then the server then needs to convert this long to a date, new
Date(long), to store it in the DB and again it has to take account of where
it is (as java takes the timezone into account when it does this conversion
and I want to make sure the DB val is the date/time the user typed in but in
GMT) and it also has to take into account whether the date it's converting
has had daylight savings applied - as can be seen in the example that also
changes the difference.

Please correct me if I'm wrong (I'd like it to be simpler!) but I've tried
the straight epoch time and it doesn't work i.e. I don't get the date in the
DB that was entered in the client. I know that the epoch time doesn't change
but these are dates typed in by the user which need to appear the same in
all timezones and the same dates in different timezones don't have the same
epoch value.
 
A

Alex Buell

Please correct me if I'm wrong (I'd like it to be simpler!) but I've tried
the straight epoch time and it doesn't work i.e. I don't get the date in the
DB that was entered in the client. I know that the epoch time doesn't change
but these are dates typed in by the user which need to appear the same in
all timezones and the same dates in different timezones don't have the same
epoch value.

Which is why a decent system should use UTC (that's GMT to us Brits)
internally, and convert to local time zone before showing to users.
Much less trouble to do it that way.
 
B

Big Jim

Alex Buell said:
Which is why a decent system should use UTC (that's GMT to us Brits)
internally, and convert to local time zone before showing to users.
Much less trouble to do it that way.

--
which is what I'm doing
 
S

steve

Hi, I've an app where swing clients run all over the globe and a java server
and sybase DB is in the UK.

The users trype in dates "mm/ydd/yyyy" for a "deal" object and these get
translated to a long, sent to the server and stored in the DB. Any user in
any location can look at the deals in their own client and I want to make
sure they all see the same date, (times aren't important).
I want to store the dates as midnight GMT in the DB (datetime col).

Can anyone give me the standard procedure for this? my current effort ain't
working,

I reckon there's 4 steps: (c = Calendar.getInstance())

In the client:
1.translating from the user entered java.util.Date to the long to send
to the server, currently I'm using:
longDate = d.getTime() + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET)

2.translating the long sent from the server to the date to display:
date = new date(long + c.get(Calendar.ZONE_OFFSET) +
c.get(Calendar.DST_OFFSET))

On the server:
1.translating the long sent from the client to a date to insert into the
DB:
java.sql.Timestamp stamp = new java.sql.Timestamp(long)

2. translating the date in the DB to a long to send to the client
long = stamp.getTime()

problems:
Sometimes dates go into the DB as midnight and sometimes as 1am, sometimes
certain dates get displayed a day early on the client. Do I need to take
offset/dst into account on the server too?

Cheers for any help,
Richard.

don't do it this way, I never take times from clients, for my database work

you have a number of problems.

1. is the users clock accurate
2. have they fiddled with the clock deliberately
3. have they set the correct time zone on their machine.
4. some platforms are broken for time reporting.


instead do it server side.
if you must, get the client to report their TIME-ZONE info ONLY (GMT+- 0-24)
then take your systems Date & time and do the calculation LOCALLY, or store
your GMT time and their +-offset (accounting for summertime etc)

you gain several advantages from this.
1. discount most the above problems (apart from 3)
2. you know how accurate YOUR clock is.
( Australia will not bugger you up, when they extend summer time for the
Games)( sun had to issue a java patch)


Just ensure your server is synced to an atomic clock over the internet.


Steve
 
B

Big Jim

steve said:
don't do it this way, I never take times from clients, for my database
work

you have a number of problems.

1. is the users clock accurate
2. have they fiddled with the clock deliberately
3. have they set the correct time zone on their machine.
4. some platforms are broken for time reporting.


instead do it server side.
if you must, get the client to report their TIME-ZONE info ONLY (GMT+-
0-24)
then take your systems Date & time and do the calculation LOCALLY, or
store
your GMT time and their +-offset (accounting for summertime etc)

you gain several advantages from this.
1. discount most the above problems (apart from 3)
2. you know how accurate YOUR clock is.
( Australia will not bugger you up, when they extend summer time for the
Games)( sun had to issue a java patch)


Just ensure your server is synced to an atomic clock over the internet.


Steve

Cheers Steve, that sounds like the best plan.

Unfortunately this is an urgent fix to let "deals" be entered globally and
the extra info passing would require changing IDL etc. so I'm stuck with the
client conversion to long mess for now. Next proper release I think I'll
take your suggestion.
 
P

P.Hill

Big said:
Cheers Steve, that sounds like the best plan.

Unfortunately this is an urgent fix to let "deals" be entered globally and
the extra info passing would require changing IDL etc. so I'm stuck with the
client conversion to long mess for now. Next proper release I think I'll
take your suggestion.

As Oliver suggested, please, get rid of the hand calculation subtracting
off the local offset. As he says, this contains a bug.

Do what you stated the problem is:
"The users [types] in dates "mm/dd/yyyy" for a "deal" object and these
get translated to a long, [...]
I want to store the dates as midnight GMT in the DB (datetime col).
simple, the API does do that (really it does)"

Okay, let's try.

String userInput = "04/03/06";

String FORMAT_INPUT = "dd/MM/yy";
String FORMAT_EVERYTHING = "dd/MM/yy HH:mm.ss zzz (ZZZ)";

SimpleDateFormat sdfGMT = new SimpleDateFormat(FORMAT_INPUT);
sdfGMT.setTimeZone(TimeZone.getTimeZone("GMT"));

SimpleDateFormat sdfGMTLots = new SimpleDateFormat(FORMAT_EVERYTHING);
sdfGMTLots.setTimeZone(TimeZone.getTimeZone("GMT"));

SimpleDateFormat sdfLocalLots = new SimpleDateFormat(FORMAT_EVERYTHING);

Date d = sdfGMT.parse(userInput);

System.out.println( "Let's see what is in the Date as GMT: " +
sdfGMTLots.format(d));
System.out.println( "Let's see what is in the Date in local time: " +
sdfLocalLots.format(d));

System.out.println( "As a long it is : " + d.getTime());

Results in:
Let's see what is in the Date as GMT: 04/03/06 00:00.00 GMT (+0000)
Let's see what is in the Date in local time: 03/03/06 16:00.00 PST (-0800)
As a long it is : 1141430400000

No hand calculations required, no setting of calendars, just
using SimpleDateFormats that do what you want.


Let's talk some more, if you don't have access to code which get
the users input from the GUI and converts to a java.util.Date.

Note: the warnings about users with poorly set machines still
applies when you do this on the client. Typical problems are
valid TZs but mis-set times (I move from NYC to Berlin, but reset
my clock instead of resetting the timezone), or a variation which
is surprisingly common running on GMT timezone, but setting the clock
to display local time.

Another problem, you particular choice of format for input -- using
slashes -- is exactly the one that varies from country to country.

If you have separate fields on your GUI then set the TZ of a calendar
object (set the time to zero to zero all fields) then push the right
field values in do a cal.getTime() (use a sdf as above to test that your
are doing the right things to the value)

HTH,
-Paul
 
M

Monique Y. Mudama

Note: the warnings about users with poorly set machines still
applies when you do this on the client. Typical problems are valid
TZs but mis-set times (I move from NYC to Berlin, but reset my clock
instead of resetting the timezone), or a variation which is
surprisingly common running on GMT timezone, but setting the clock
to display local time.

Running on GMT and setting the timezone as a configuration
option is the preferred approach on *nix machines. It's one way in
which dual-booting with Windows can get annoying. I'm not sure why
this is, but I suspect it might have to do with the idea of multiple
simultaneous users on different parts of the planet.
 
J

Jacques-Olivier Haenni

Hello,

Personally, I would consider creating my own very simple Data class.
This can be (almost) as simple as:
class Date {
private int day;
private int month;
private int year;
...
}

Just add setters/getters, constructors, and conversion methods (e.g. a
toLong() method if you need to,...)

This simply avoids all the timezone issues when transmitting the date
over the network.

Cheers,

Jacques-Olivier
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top