Saving date time for all time zones in java - java

I have an application in which user creates questions and others can
see date time (when the question was created) with it. Now i get the
server date time and save it in db but the problem is app is used by
someone who live in a country with a 6-7 hour gap.
Well a small example would be that i live in some country and i create question at time 7:00pm but time in USA is 11am (just a guess). So user immediately retrieves question but for him question time should be 11am and not 7pm. So how can i save date time so it would be same for all time zones . I m kinda confused
so i need a little help . I know it's related to UTC date time but can
someone elaborate this a bit more :) . Thank u

Store into your database the difference, measured in milliseconds, between the current time and the epoch of midnight, January 1, 1970 UTC. that you can get by calling System.currentTimeMillis().
Once you have it you can provide the time in any Time Zone that you want, here is a simple code snippet that shows the time in all the time zones available on my machine.
This code uses the java.time framework built into Java 8 and later. Much of this functionality has also been back-ported to Java 6 & 7 and to Android.
long time = System.currentTimeMillis();
Instant instant = Instant.ofEpochMilli(time);
ZoneId.getAvailableZoneIds().stream().forEach(id -> {
ZoneId zId = ZoneId.of(id);
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zId);
System.out.printf(
"The current time in %s is %s%n",
zId, localDateTime.format(DateTimeFormatter.ISO_DATE_TIME)
);
}
);
Here is the equivalent for older versions of Java:
long time = System.currentTimeMillis();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
for (String id : TimeZone.getAvailableIDs()) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
formatter.setTimeZone(TimeZone.getTimeZone(id));
System.out.printf(
"The current time in %s is %s%n", id, formatter.format(cal.getTime())
);
}
Response Update:
As you want to keep the original TimeZone, you will also have to store the time zone Id into your database in the pseudo standard format GMT+/-mm:ss.
For this, first you need to get the delta compared to UTC time (in the code snippet below tz is my current TimeZone):
int offsetFromUTC = tz.getOffset(time);
Then from this you can convert this delta in milliseconds into the expected time zone id which can be done like this:
String timeZoneId = String.format(
"GMT%+02d:%02d", offsetFromUTC / (60 * 60 * 1000), offsetFromUTC / (60 * 1000) % 60
);
The value of timeZoneId is the second value that you have to store into the database. With these two values you can display the time in any expected format, for example:
Calendar cal = Calendar.getInstance();
// Here I use the time retrieved from the DB
cal.setTimeInMillis(time);
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
// Here I use the time zone id retrieved from the DB
TimeZone tz = TimeZone.getTimeZone(timeZoneId);
formatter.setTimeZone(tz);
System.out.printf("The current time in %s is %s%n", id, formatter.format(cal.getTime()));

So how can i save date time so it would be same for all time zones
You should use UTC to store your dates, so if someone is using your app in +1 timezone, you need to convert it to UTC first. Timezone should only be used to display the time to the users.

Related

Trying to write code that will start at beginning of next day

I'm trying to write code to run at 1 am. The idea is to find the amount of time to next day in milliseconds, then do a sleep on that time
I do this by getting the reminder of the current time divided by to days time.
remainder= current time % 8640000
where current time is gotten from Time.getTimeInMillis();
I got 61175831
to get days by divide it by (606024)
witch gives me 16 hours
It's 1pm so 13+16=30 or 6am next day not 1 am in morning
delayTime=24*60*60*1000; // i day
Calendar Time = Calendar.getInstance();
long delay=TimeToNumber%delayTime;
ling days=delay/1000;
days=days/60;
days=days/60
Got 16 for days
Without knowing more about your usage scenario, I can't really comment on whether your suggested approach is the best way to do the actual scheduling. However, I can answer the question of how to determine the number of milliseconds until 1:00 AM.
ZonedDateTime now = ZonedDateTime.now();
LocalTime targetTime = LocalTime.parse("01:00");
ZonedDateTime targetDateTime;
if (now.toLocalTime().isBefore(targetTime)) {
targetDateTime = now.with(targetTime);
} else {
targetDateTime = now.plusDays(1).with(targetTime);
}
long millis = Duration.between(now, targetDateTime).toMillis();
Explanation
The Calendar API is a legacy API that comes with a bunch of challenges and gotchas with using it. Additionally, by attempting to do the calculations yourself mathematically, you're missing the various nuances that are automatically handled for you by the libraries (such as daylight saving time shifts and the like). For these reasons, I strongly suggest using the newer java.time API.
For this particular question, you need to determine the number of milliseconds until the next 1:00 AM. If the time is before 1:00 in the current date, you want to return the current date's 1:00. If it's after 1:00, you want to return tomorrow's 1:00.
ZonedDateTime is a good choice to represent 1:00 today/tomorrow, since in addition to the date & time, a time zone is needed in order to correlate the datetime with a specific instant in time.
Retrieving the next 1:00 can be achieved by comparing the current LocalTime with a LocalTime of 1:00 AM:
ZonedDateTime now = ZonedDateTime.now();
LocalTime targetTime = LocalTime.parse("01:00");
ZonedDateTime targetDateTime;
if (now.toLocalTime().isBefore(targetTime)) {
targetDateTime = now.with(targetTime);
} else {
targetDateTime = now.plusDays(1).with(targetTime);
}
This is assuming you're using the system default time zone. If you want to use a different time zone, this can be specified in the call to ZonedDateTime.now():
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
With this ZonedDateTime representing the next 1:00 AM, you can use a Duration between the current time and that time, and then get the number of milliseconds in the duration:
long millis = Duration.between(now, targetDateTime).toMillis();

Why UTC timezone giving ahead time for System.currentTimeMillis in Java?

I am getting current time from Ruby on Rails webservice in Unix Timestamp format (ie. in seconds from 1 Jan 1970), the timezone on server is UTC.
In Java I am trying to convert local current time to UTC time. But every time it is giving 6+ minutes ahead time. I want to get the difference of UTC current time and the time returned from service. My Java code is -
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
Date utc_current = new Date(System.currentTimeMillis());
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
long serverTime = 1424936268000L;
long resTime = sdf.getCalendar().getTimeInMillis() - serverTime;
System.out.println("Time Diff : " + resTime);
Where serverTime is the time I am getting from webservice. And the value for resTime shows negative value which is approx 6+ minutes.
So my question is why UTC timezone giving ahead time for System.currentTimeMillis?
In contrast to the assumption in a comment of of #JB Nizet the expressions sdf.getCalendar().getTimeInMillis() and System.currentTimeMillis() are not equivalent. Proof:
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
System.out.println("date via System.currentTimeMillis()=" + f.format(utc_current));
System.out.println("date via sdf.getCalendar()=" + f.format(new Date(resTime)));
Output:
date via System.currentTimeMillis()=2015-02-26T12:19:09
date via sdf.getCalendar()=1889-12-31T04:41:21
If you carefully study the source code of SimpleDateFormat and DateFormat you will find within the initialization part code like:
private void initializeDefaultCentury() {
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add( Calendar.YEAR, -80 );
parseAmbiguousDatesAsAfter(calendar.getTime());
}
The conclusion is to strictly avoid the method getCalendar() on your DateFormat-object. It is only used as intermediate mutable object for internal format and parse processing. It is hard to say what you will really get as time this way. Instead use directly System.currentTimeMillis() to compare your local time with server time.
Another problem is the pattern you use. "dd-MM-yyyy hh:mm:ss" is probably not correct because it uses the clock hour of half day in range 1-12 but the information for am/pm is missing. Use better the pattern symbol HH. Check the documentation of webservice for the right format.
Make sure the the clock on the server and on the client machine are synchronized. The 6 minutes could simply be an offset between the two.

Java calendar in different time zone gives different values for same time

Hi in the below piece of code i am getting the output as 9 and 10 , Why is that happening ? Even though the calendars are of different time zones we are passing the same date to set the time . As far as I know the the time is calculated from the epoch as a relative value , so this relative value should be same no matter what is the time zone
I am facing a similar problem with my DB in one time zone and Server in another.
Date date = new Date ();
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("America/Los_Angeles"),Locale.US);
Calendar c1 = Calendar.getInstance();
c.setTime(date);
c1.setTime(date);
System.out.println(c.get(Calendar.HOUR));
System.out.println(c1.get(Calendar.HOUR));
when you pass in the date, its UTC timestamp is taken (so number of milliseconds since 01-01-1970 in GMT+0), you then set both calendars to that same time, and ask what hour it is.
obviously the hour is going to be different in different time zones - the L.A time zone and the time zone for the computer you run the code on, even though they have been initialized with the exact same UTC time.

Date difference includes Timezone offset, what's wrong?

I have this code:
Date now = new Date();
// the string is in UTC format, so a UTC date must be constructed, I don't know if that happens in this format
Date measure = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(utcDateTime);
long diff = now.getTime() - measure.getTime();
if (diff < 1000* 60 * 15) {
// measure is less then 15 minutes recent
do some work
}
When I get the diff, it includes the timezone. I know the Date object internally is UTC.
So what's wrong here?
While a Date object is indeed in UTC, your SimpleDateFormat may not be. I suspect it default's to the system time zone - that's certainly what experimentation would suggest. You can change this using DateFormat.setTimeZone. So if your text represents a UTC date/time, you should set the time zone of the formatter to UTC as well.
Or you could use Joda Time, which is a generally better date and time API :)

Get Time in London

How can I get the current local wall clock time (in number of millis since 1 Jan 1970) in London? Since my application can run on a server in any location, I think I need to use a TimeZone of "Europe/London". I also need to take Daylight Savings into account i.e. the application should add an hour during the "summer".
I would prefer to use the standard java.util libraries.
Is this correct?
TimeZone tz = TimeZone.getTimeZone("Europe/London") ;
Calendar cal = Calendar.getInstance(tz);
return cal.getTime().getTime() + tz.getDSTSavings();
Thanks
I'm not sure what this quantity represents, since the "number of millis since 1 Jan 1970" doesn't vary based on location or daylight saving. But, perhaps this calculation is useful to you:
TimeZone london = TimeZone.getTimeZone("Europe/London");
long now = System.currentTimeMillis();
return now + london.getOffset(now);
Most applications are better served using either UTC time or local time; this is really neither. You can get the UTC time and time in a particular zone like this:
Instant now = Instant.now(); /* UTC time */
ZonedDateTime local = now.atZone(ZoneId.of("Europe/London"));
Others have said that it may well not be a good idea to do this - I believe it depends on your situation, but using UTC is certainly something to consider.
However, I think you've missed something here: the number of seconds which have occurred since January 1st 1970 UTC (which is how the Unix epoch is always defined - and is actually the same as in London, as the offset on that date was 0) is obtainable with any of these expressions:
System.currentTimeMillis()
new Date().getTime()
Calendar.getInstance().getTime().getTime()
If you think about it, the number of milliseconds since that particular instant doesn't change depending on which time zone you're in.
Oh, and the normal suggestion - for a much better date and time API, see Joda Time.
To get the current time in London:
SimpleDateFormat f = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
f.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(f.format(GregorianCalendar.getInstance().getTime()));

Categories

Resources