Convert time represented as String containing timezone names ('z') to UTC time - java

I want to convert Strings like "20000603163334 GST" or "20000603163334 -0300" to UTC time. The problem is that time zones in my strings can be 'general time zones', I mean they can be strings as CET, GST etc. etc. And I don't know how to convert these ones.
Because of these string time zones I can not use Joda Time's DateTimeFormat.forPattern("yyyyMMddhhmmss z").withZone(DateTimeZone.UTC);, because according to the documentation: "Time zone names ('z') cannot be parsed".
So, one question I have is if you know a method to go around this limitation in Joda Time? I would prefer to use Joda Time, if possible, instead of the standard Java API.
Another in which I thought I can solve this problem with time zone's names is to use the Java's SimpleDateFormat.
So I make something like:
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddhhmmss z");
//f.setTimeZone(TimeZone.getTimeZone("UTC"));
f.setCalendar(new GregorianCalendar(TimeZone.getTimeZone("UTC")));
Date time = f.parse("20000603163334 GST");
The SimpleDateFormat parses the String (I don't care here about the problem that there are multiple time zones with the same name - what this class parses it's good for me).
The problem is that I don't know how to convert it from here to UTC. How can I do this?
The fact that I set the f's time zone to UTC (in both the two ways from above) doesn't help. I hope someone can help me fix this, I read a lot of questions and answers on this theme here, on stackoverflow, but I haven't found a solution yet.

I found two solutions to your problem. The first was to set the default time zone to UTC:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
I'm not sure what other side effect this might have.
The second solution I found was to use a different SimpleDateFormat for output.
SimpleDateFormat f = new SimpleDateFormat("yyyyMMddhhmmss z");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
Date time = f.parse("20000603163334 GST");
System.out.println(time);
System.out.println("(yyyyMMddhhmmss z): " + f.format(time));
SimpleDateFormat utc = new SimpleDateFormat("yyyyMMddhhmmss z");
utc.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("(yyyyMMddhhmmss z): " + utc.format(time));
Using two SimpleDateFormat objects allowed the output to be put in UTC Time. Here is the output from running this code:
Sat Jun 03 08:33:34 EDT 2000
(yyyyMMddhhmmss z): 20000603043334 GST
(yyyyMMddhhmmss z): 20000603123334 UTC
Here may be the reason why Joda does not support 3 letter zone ids. This is from the TimeZone ( http://download.oracle.com/javase/6/docs/api/java/util/TimeZone.html ) JavaDoc. As far as Joda goes, I didn't see a workaround, but I'm not very familiar with that library.
Three-letter time zone IDs For
compatibility with JDK 1.1.x, some
other three-letter time zone IDs (such
as "PST", "CTT", "AST") are also
supported. However, their use is
deprecated because the same
abbreviation is often used for
multiple time zones (for example,
"CST" could be U.S. "Central Standard
Time" and "China Standard Time"), and
the Java platform can then only
recognize one of them.

Related

How to find epoch format current time of GMT using java

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();

What is the right way to format Time between different timezones?

I want to format time like 19:19:00 to different time zones. If I use SimpleDateFormat it always takes into account the start of the epoch: 1970.01.01.
Some timezones have different offsets on the start of the epoch and now. For example, the default offset from Europe/Kiev now is UTC+0200 but in 1970 it was UTC+0300. That means if I run my server under Europe/Kiev the client which login under Europe/Berlin(UTC+0100) will see three hours different instead of two.
I can solve this problem by writing a custom formatter for java.sql.Time. But I want to ask maybe there are some common approach or Java tools/libraries which can solve it.
Another solution can be using joda-time:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Kiev"));
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Kiev"));
DateTimeFormat.forPattern("HH:mm:ss.SSS")
.withZone(DateTimeZone.forID("Europe/Berlin"))
.print(Time.valueOf("19:00:00").getTime());
You can't format just a time to different time zones. You need a date.
If you want to assume that the date of that time is today, you can try this code:
ZoneId originalZone = ZoneId.of("Europe/Kiev");
ZoneId targetZone = ZoneId.of("Europe/Berlin");
LocalTime originalTime = LocalTime.parse("19:19:00");
LocalTime convertedTime = LocalDate.now(originalZone)
.atTime(originalTime)
.atZone(originalZone)
.withZoneSameInstant(targetZone)
.toLocalTime();
System.out.println(convertedTime);
Is java.time.instant an alternative for you? It handles all Timestamps internally as UTC-Time.
One way to parse it from a string is Instant.parse("2018-05-30T19:00:00")
If you want to have the time for a specific timezone you can get it with myInstant.atZone("Zone")
ZoneId originalZone = ZoneId.of("Europe/Kiev");
ZoneId targetZone = ZoneId.of("Europe/Berlin");
LocalDate assumedDate = LocalDate.now(originalZone);
String formattedTime = assumedDate.atTime(LocalTime.parse("19:19:00"))
.atZone(originalZone)
.withZoneSameInstant(targetZone)
.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
System.out.println(formattedTime);
Today this printed:
18:19:00
When you know the date, you should of course use that instead of just today. In the case of Kyiv and Berlin I think they follow the same rules for summer time (DST), so the precise date may not be important. If converting between zones that don’t use the same transitions, or between a time zone that uses summer time and one that doesn’t, it’s suddenly crucial. And who knows in which of those two countries the politicians will change the rules next year? Better be safe.
Link: Oracle tutorial: Date Time explaining how to use java.time.

Unexpected result when using SimpleDateFormatter with a timezone

My goal is to parse a date string with the format yyyy-MM-dd hh:mm:ss.SSS for a given timezone, using only Java 6 without any external libraries. My first approach was to configure a SimpleDateFormatter with a timezone. However, I'm not able to understand the results. Have a look at the following code:
List<String> zones = Arrays.asList("UTC", "CET", "Europe/London", "Europe/Berlin");
for(String zone: zones) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
df.setTimeZone(TimeZone.getTimeZone(zone));
Date result = df.parse("1970-01-01 00:00:00.000");
System.out.println(zone + ": " + result.getTime());
}
The output is as follows:
UTC: 0
CET: -3600000
Europe/London: -3600000
Europe/Berlin: -3600000
The first two results are as expected. In UTC, the unix epoch starts at exactly zero milliseconds, and there is a one hour difference to CET.
What I don't understand are the values for London and Berlin. Since the milliseconds for London equal the milliseconds for CET instead of UTC, I first assumed that daylight savings time is taken into account (since it's currently summer on the northern hemisphere and summertime in London is UTC+1, which equals CET). However, why is the value for Berlin the same? Shouldn't it be UTC+2 (or CET+1 if you want)?
My questions:
What's the explanation for the results? Is DST really taken into account?
Is there a better way for doing the conversion in Java 6?
The results are correct, because that's the offsets used by London and Berlin in 1970 (both used +01:00).
It's not related to Daylight Saving Time, because nowadays it happens during March and October in these countries. Actually one could argue that London was in a "long" DST period, from 1968 to 1971, because the offset was +01:00 during this whole period.
It's just the nature of timezones: they're defined by governments and laws, and the respective politicians can change the offsets used by their countries for whatever reasons they have.
In the same links above, you can see that Berlin adopted DST only in 1980, and London changed the offset to zero (GMT) in 1971.
PS: as discussed in the comments, short names like CET are ambiguous and not standard (for lots of them, there's more than one timezone that uses the same abbreviation). Always prefer to use IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Some names (such as CET) are recognized and set to arbitrary defaults - mainly due to retro-compatibility (or bad design) issues - but it's usually done in unexpected ways. Avoid such short names if you can: names like Europe/Berlin are much more clear and have no ambiguities.

in java I need define date in this format 1999-05-31T13:20:00-05:00 [duplicate]

This question already has an answer here:
Java how to set 2011-11-06T14:34:16.679+02:00 into XMLGregorianCalendar
(1 answer)
Closed 5 years ago.
I need to define date in this format 1999-05-31T13:20:00-05:00
I am using below code
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'hh:mm:ssZ");
sdf.setTimeZone(TimeZone.getTimeZone("EST"));
String date = sdf.format(new Date());
System.out.println(date);
but it is generating date in format 2017-04-117T08:28:46-0500 (missing semicolon in timezone)
After defining the date I have to create an instance of XMLGregorianCalendar with same date.
I was surprised you didn’t find the answer when searching for it. Anyway, it’s easy. Two words of caution first, though:
Skip the three-letter time zone abbreviations. Many are ambiguous. While I think EST only means Eastern Standard Time, this isn’t a full time zone, since (most of?) that zone is on EDT now, which does not make it very clear what result you want.
If there’s any way you can, skip the old-fashioned classes SimpleDateFormat, TimeZone and Date. The new classes in java.time are generally much nicer to work with.
The format you are asking for is exactly what DateTimeFormatter.ISO_OFFSET_DATE_TIME is giving you. If you meant to have the time formatted suitably for a user in the Eastern time zone, use:
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"))
.truncatedTo(ChronoUnit.SECONDS);
System.out.println(now.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
Note the use of the unambiguous time zone ID and of the mentioned formatter. The format will print milliseconds (and even smaller) if there are any, which you didn’t ask for. So I have cheated a bit: I am truncating the time to whole seconds. Now this prints something like:
2017-04-27T10:11:33-04:00
If instead you wanted the offset -05:00, that’s even easier:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.ofHours(-5))
.truncatedTo(ChronoUnit.SECONDS);
System.out.println(now);
This prints something in the same format, but with the desired offset:
2017-04-27T09:11:33-05:00
The toString method of OffsetDateTime gives you the format you want. Of course, if you prefer, you can use the same formatter as before.
If truncating to seconds is a bit too much cheating for your taste, you may of course use a formatter without milliseconds:
DateTimeFormatter isoNoSeconds = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
System.out.println(now.format(isoNoSeconds));
This will work with both a ZonedDateTime and an OffsetDateTime, that is, with both of the above snippets.

android java time

i'm building an android application which have a chat.
in this chat i each message to have its time sent signature.
my question is as follow:
lets say that the time in my country is X. my friend is abroad and his time is X minus 7 hours.
i'm sending him a message at 16:00 local time.
i want to avoid the situation that he will get at 09:00 a message which it signature will be 16:00 (which is a time in future if you're looking in the eyes of that friend in his country).
is there a way that in my phone the message will be written as 16:00 and in his phone it will be written as 09:00 ? i there a way to convert a time to a local time ?
System.currentTimeMillis() does give you the number of milliseconds since January 1, 1970 00:00:00 UTC. Date object does not save your local timezone.
You can use DateFormats to convert Dates to Strings in any timezone:
DateFormat df = DateFormat.getTimeInstance();
df.setTimeZone(TimeZone.getTimeZone("gmt"));
String gmtTime = df.format(new Date());
linked response
You should keep all time communications using UTC time. Then localize it for display based on the devices current timezone setting.
Use a long to save your time information as milliseconds since "epoch" (which is January 1, 1970, 00:00:00 GMT). It can be retreived with the Date.getTime() method and new Date objects are easily created using the Date(long millis) constructor. The Date objects are then displayed using the local timezone settings on each device.
EDIT:
Epoch is a defined point in time which is expressed differently in different time zones: 1970-01-01 00:00:00 GMT but
1969-12-31 19:00:00 EST. The timestamp is just the number of milliseconds elapsed since that time. So, for example the timestamp 1341169200 corresponds to 2012-07-01 19:00:00 GMT and 2012-07-01 14:00:00 EST.
You will need to save the time zone which your message will be saved in, and transfer it (or send the unix epoch time) and then on the other side make sure you read it in with the Locale time (using the Android documentation for things like http://developer.android.com/reference/java/util/Calendar.html can help).
Take a look at the answer over here:
https://stackoverflow.com/a/6094475/346232
You need to change the time to UTC and then convert on the device to the timezone.
Avoid java.util.Date/.Calendar
The java.util.Date/.Calendar classes bundled with Java (and Android) are notoriously troublesome, flawed in both design and implementation.
Joda-Time
The Joda-Time library is the way to go. This library inspired the java.time package now built into Java 8 (not available on Android).
UTC
As other answers suggested, the best practice (generally) is to keep your business logic and data storage/communication in UTC time zone (which some think of as no time zone or an "anti" time zone). Adjust to a specific time zone only when expected by the user or data-consumer.
Time Zone
The DateTime class in Joda-Time represents a date-time value along with an assigned time zone.
Note that it is best to specify a time zone in all your operations. Otherwise you will be implicitly relying on the JVM’s current default time zone. This is risky because that zone can change – even at runtime at any moment by any code in any thread of any app running within your app’s JVM. And use proper time zone names, never the 3-4 letter codes.
Example Code
Example code in Joda-Time 2.7.
DateTime sent = DateTime.now( DateTimeZone.getDefault() ) ;
DateTime sentUtc = nowMine.withZone( DateTimeZone.UTC ) ; // Generally, use this for your work, including communicating to other threads and apps and such.
When ready to display to the other user, adjust to the expected time zone.
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ) ; // Or DateTimeZone.getDefault() if you want to rely on their JVM’s current default. To be absolutely sure of expected time zone, you really must ask the user.
DateTime sentMontréal = sentUtc.withZone( zone );
To generate a textual representation of those date-time objects, search the many Questions and Answers on StackOverflow.com on that subject. Search for terms like "joda" and "DateTimeFormatter" and "DateTimeFormat".

Categories

Resources