I'm trying to get the epoc time adjusted for the local timezone (i.e. GMT-7, but it displays GMT). I'm fairly sure this should work, but it's not...
Calendar localTime = new GregorianCalendar(TimeZone.getDefault());
Date dd = localTime.getTime();
long t = dd.getTime()/1000;
System.out.printf("%d\n",t);
But it still outputs the epoc time based on GMT, not GMT-7 (my timezone). After playing around for some time I did get this to work...
Date ddd = new Date();
long t = ddd.getTime() + TimeZone.getDefault().getOffset( ddd.getTime() );
t = t/1000;
But why isn't the first block working?
A Date object simply wraps the UTC time in milliseconds since the epoch. This is how all time is represented 'under the hood' in Java. This also makes it consistent to work with. Whenever you want to print something out, apply the TimeZone offset and DST offset to it.
This is why the SimpleDateFormat class accepts a TimeZone but there is no TimeZone setter on the Date class.
Obligatory: I have heard Joda Time is a much easier to use datetime API.
Also, have a look at this post on the standard date and time libraries in Java.
Related
I have written below code which is running, and giving output. But I'm not sure It's a right one.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date = new Date();
sdf.setTimeZone(TimeZone.getTimeZone("GMT-7"));
String value = sdf.format(date);
System.out.println(value);
Date date2 = sdf.parse(value);
long result = date2.getTime();
System.out.println(result);
return result;
The above code what I'm trying is, I just need to get the current time of GMT time zone and convert it as epoch format which is gonna used in Oracle db.
Can someone tell me that format, and the above code is right?
First, you should not store time since the epoch as a timestamp in your database. Look into the date-time datatypes that your DMBS offers. In Oracle I think that a date column will be OK. For most other DBMS you would need a datetime column. timestamp and timestamp with timezone may be other and possibly even sounder options depending on your exact requirements.
However, taking your word for it: Getting the number of milliseconds since the epoch is simple when you know how:
long millisecondsSinceEpoch = System.currentTimeMillis();
System.out.println(millisecondsSinceEpoch);
This just printed:
1533458641714
The epoch is defined in UTC, so in this case we need to concern ourselves with no other time zones.
If you needed seconds rather than milliseconds, it’s tempting to divide by 1000. However, doing your own time conversions is a bad habit since the libraries already offers them, and using the appropriate library methods gives clearer, more explanatory and less error-prone code:
long secondsSinceEpoch = Instant.now().getEpochSecond();
System.out.println(secondsSinceEpoch);
1533458641
You said:
I just need to get the current time of GMT time zone…
Again taking your word:
OffsetDateTime currentTimeInUtc = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(currentTimeInUtc);
long millisecondsSinceEpoch = currentTimeInUtc.toInstant().toEpochMilli();
System.out.println(millisecondsSinceEpoch);
2018-08-05T08:44:01.719265Z
1533458641719
I know that GMT and UTC are not exactly the same, but for most applications they can be (and are) used interchangeably.
Can someone tell me (if) the above code is right?
When I ran your code just now, its output agreed with mine except the milliseconds were rounded down to whole thousands (whole seconds):
1533458641000
Your code has some issues, though:
You are using the old, long out-dated and poorly designed classes SimpleDateFormat, Date and TimeZone. The first in particular has a reputation for being troublesome. Instead we should use java.time, the modern Java date and time API.
Bug: In your format pattern string you are using lowercase hh for hour of day. hh is for hour within AM or PM, from 1 through 12, so will give you incorrect results at least half of the day. Uppercase HH is for hour of day.
Don’t use GMT-7 as a time zone. Use for example America/Los_Angeles. Of course select the time zone that makes sense for your situation. Edit: You said:
I just want to specify the timezone for sanjose. GMT-7 is refer to
sanjose current time.
I believe many places are called San Jose. If you mean San Jose, California, USA, you are going to modify your program to use GMT-8 every time California goes back to standard time and opposite when summer time (DST) begins?? Miserable idea. Use America/Los_Angeles and your program will work all year.
Since you ask for time in the GMT time zone, what are you using GMT-7 for at all?
There is no point that I can see in formatting your Date into a string and parsing it back. Even if you did it correctly, the only result you would get would be to lose your milliseconds since there are no milliseconds in your format (it only has second precision; this also explained the rounding down I observed).
Links
Oracle tutorial: Date Time explaining how to use java.time, the modern Java date and time API.
San Jose, California on Wikipedia
Why not use Calendar class?
public long getEpochTime(){
return Calendar.getInstance(TimeZone.getTimeZone("GMT-7")).getTime().getTime()/1000; //( milliseconds to seconds)
}
It'll return the current Date's Epoch/Unix Timestamp.
Based on Harald's Comment:
public static long getEpochTime(){
return Clock.system(TimeZone.getTimeZone("GMT-7").toZoneId() ).millis()/1000;
}
Here is a solution using the java.time API
ZonedDateTime zdt = LocalDateTime.now().atZone(ZoneId.of("GMT-7"));
long millis = zdt.toInstant().toEpochMilli();
I have time 12:00:00 in format HH:mm:ss.
I know that this time comes from server witch is setup with +3 offset.
If i use SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");, it parses time with regard to device, which can be in a different timezone.
Is there another way to parse it with regard to +3 offset except adding it to the original string?
First, should your server rather send the time in UTC? If clients are everywhere, this would seem more time zone neutral and standardized. However, the way to handle it in code wouldn’t be much different. In any case the server offset form UTC could be constant:
private static final ZoneOffset serverOffset = ZoneOffset.ofHours(3);
In real code you will probably want to make it configurable somehow, though. To parse:
OffsetTime serverTime = LocalTime.parse("12:00:00").atOffset(serverOffset);
System.out.println(serverTime);
This prints
12:00+03:00
Since your time format agrees with LocalTime’s default (ISO 8601), we need no explicit formatter. If a representation of the time with offset is all you need, we’re done. If you need to convert to the user’s local time, to do that reliably you need to decide both a time zone and a date:
LocalTime clientTime = serverTime.atDate(LocalDate.of(2018, Month.JANUARY, 25))
.atZoneSameInstant(ZoneId.of("Indian/Maldives"))
.toLocalTime();
System.out.println(clientTime);
With the chosen day and zone we get
14:00
Please substitute your desired time zone and date.
Just hypothetically, if you knew the user’s offset from UTC, you could use just that:
LocalTime clientTime = serverTime.withOffsetSameInstant(ZoneOffset.of("-08:45"))
.toLocalTime();
The example yields 00:15. However, no one knows when the politicians introduce summer time (DST) or other anomalies in the user’s time zone, so I discourage relying on an offset alone.
And yes, I too am using java.time. SimpleDateFormat is not only long outdated, it is also notoriously troublesome, so java.time is what I warmly recommend.
Set the timezone on your SimpleDateFormat object:
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT+03:00"));
I recommend you use the Java 8 date and time API (package java.time) instead of the old API, of which SimpleDateFormat is a part.
Using the Java 8 DateTime API:
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("HH:mm:ss");
LocalTime clientLocalTime = LocalTime
.parse("12:00:00", formatter)
// Create an OffsetTime object set to the server's +3 offset zone
.atOffset(ZoneOffset.ofHours(3))
// Convert the time from the server timezone to the client's local timezone.
// This expects the time value to be from the same day,
// otherwise the local timezone offset may be incorrect.
.withOffsetSameInstant(ZoneId.systemDefault().getRules().getOffset(Instant.now()))
// Drop the timezone info - not necessary
.toLocalTime();
I am running my code in EST timezone.
Using Instant.now() in my code and it returns time in UTC.
But, I am trying to test a method which gets data from DB as Date not Instant and hence trying to convert this to Date using
Date.from(Instant.now())
Since, I am running this in EST, this Date gives me time in EST.
Actual code,
final Optional<Date> dbTime = dbService.getUpdatedTime();
final Instant lastInstant = dbTime.orElseGet(() -> Date.from(Instant.now())).toInstant();
Test Code,
final Date dbTime = Date.from(Instant.now().minusSeconds(36000));
when(dbService.getUpdatedTime().thenReturn(Optional.of(dbTime));
Here, the dbTime gets converted to EST time. I can make that to return UTC time by setting TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Is there any other better way? Is this ok to set TimeZone.setDefault(TimeZone.getTimeZone("UTC")); in the main Application class so that it will always be treated as UTC?
First recommendation, since you can use the modern Java date and time API, use it as much as you can and minimize the use of the outdated Date class. Best will be if you can modify getUpdatedTime() to return an Optional<Instant> rather than an Optional<Date> (a modern JDBC driver can give you the datetime from your database as an Instant directly). Since an Instant prints in UTC, this should wipe away all of your issue and your question.
In this answer I am assuming that you either cannot do that or don’t want to do it just yet. You can still get close, though:
final Optional<Instant> dbTime = dbService.getUpdatedTime().map(Date::toInstant);
final Instant lastReconInstant = dbTime.orElseGet(Instant::now);
Avoid TimeZone.setDefault(). Since the JVM only has one global time zone setting, this may unintentionally change the behaviour of other parts of your program or other programs running in the same JVM.
A detail, in your stub code I recommend to make it explicit that you subtract 10 hours. Two options are
final Date dbTime = Date.from(Instant.now().minus(10, ChronoUnit.HOURS));
final Date dbTime = Date.from(Instant.now().minus(Duration.ofHours(10)));
All of this said, it still seems to me that you didn’t have a problem in the first place. A Date does not have a time zone in it. Its toString method just grabs the JVM’s default time zone and uses it for rendering the date and time. This has fooled many and is just one of the reasons to avoid that class when you can.
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.
I am trying to format a calendar string to indicate a time zone offset other than my local one. I am aware I could create a simple formatting string and use the Calendar.get(int) method to fill in all the values, but this does not feel like the right way to do this.
Java has a DateFormat, specifically I am trying to use the SimpleDateFormat. The problem is that the format() method of these classes expects a Date object.
I am primarily working with Calendar objects since I believe those are the recommended structure in Java. So, when I go to format my result time, I call Calendar.getTime() which returns a Date object which can be passed into the SimpleDateFormat object.
Until now, I thought this was perfectly simple, but here is where the problem comes in.
Whenever one calls the Calendar.getTime() method, the Date returned is always in the local time zone, regardless of the time zone of the Calendar.
So, I always get the time printed in the local time zone when I pass it to my SimpleDateFormat, which is not what I want. All the research I have done so far says it can't be done and all the examples I have seen simply use the Calendar.get(int) method to fill in some blanks. This seems terrible, why have a DateFormat class if it is going to be so useless?
Here is some example code so you can see what I mean, paste this into your favourite test class:
private static final SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
private static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
public static void main(String[] args)
{
try
{
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
cal.setTimeInMillis(parser.parse("2012-10-09T22:01:49.108-0700").getTime());
System.out.println(formatter.format(cal.getTime()));
}
catch(ParseException e)
{
e.printStackTrace();
}
}
Output produced (because I am running in Central Time Zone): 2012-10-10T00:01:49-0500
Output expected (should not matter what time zone it is run from): 2012-10-10T01:01:49-0400
To summarize question: Is there a way to make the DateFormat in java accept a Calendar, or a way to get a Date that is not in the local timezone, or is there another class I should be using altogether for this formatting?
Whenever one calls the Calendar.getTime() method, the Date returned is always in the local time zone, regardless of the time zone of the Calendar.
No, it's not. Date doesn't have a time zone. It's just the number of milliseconds since the Unix epoch. Its toString() method does convert it to the local time zone, but that's not part of the information in the Date object.
All you need to do is set the time zone of the formatter to be the same as the time zone of the calendar.
formatter.setTimeZone(calendar.getTimeZone());
... or just set the calendar to be used entirely:
formatter.setCalendar(calendar);
(It's not immediately clear to me whether the latter approach will mean that the calendar can lose its value... basically the Java classes mix "calendar system", "time zone" and "value within the calendar" in a single type, which is very unfortunate.)
I agree with Ian though, in terms of Joda Time being a far more pleasant API to use.
I would give up on the built in java date and time classes for this and use joda time instead. It is designed to handle ISO8601 format strings properly and does the right thing with timezones.
Date is not having any TimeZone, its just the number of milliseconds since Epoch time, represented in a human readable format. We can use "DateFormat" class.
TimeZone tz = TimeZone.getTimeZone("America/Buenos_Aires");
Calendar cal = Calendar.getInstance(tz);
Date d = cal.getTime();
DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm aaa");
df.setTimeZone(tz);
String s = df.format(cal.getTime());
System.out.println(s);