Formatting a Calendar object and not a Date object? - java

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

Related

Java: Fix incorrect timezone in date object

An external API returns an object with a date.
According to their API specification, all dates are always reported in GMT.
However, the generated client classes (which I can't edit) doesn't set the timezone correctly. Instead, it uses the local timezone without converting the date to that timezone.
So, long story short, I have an object with a date that I know to be GMT but it says CET. How can I adjust for this mistake withouth changing my local timezone on the computer or doing something like this:
LocalDateTime.ofInstant(someObject.getDate().toInstant().plus(1, ChronoUnit.HOURS),
ZoneId.of("CET"));
Thank you.
tl;dr ⇒ use ZonedDateTime for conversion
public static void main(String[] args) {
// use your date here, this is just "now"
Date date = new Date();
// parse it to an object that is aware of the (currently wrong) time zone
ZonedDateTime wrongZoneZdt = ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("CET"));
// print it to see the result
System.out.println(wrongZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// extract the information that should stay (only date and time, NOT zone or offset)
LocalDateTime ldt = wrongZoneZdt.toLocalDateTime();
// print it, too
System.out.println(ldt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// then take the object without zone information and simply add a zone
ZonedDateTime correctZoneZdt = ldt.atZone(ZoneId.of("GMT"));
// print the result
System.out.println(correctZoneZdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
}
Output:
2020-01-24T09:21:37.167+01:00[CET]
2020-01-24T09:21:37.167
2020-01-24T09:21:37.167Z[GMT]
Explanation:
The reason why your approach did not just correct the zone but also adjusted the time accordingly (which is good when desired) is your use of a LocalDateTime created from an Instant. An Instant represents a moment in time which could have different representations in different zones but it stays the same moment. If you create a LocalDateTime from it and put another zone, the date and time are getting converted to the target zone's. This is not just replacing the zone while keeping the date and time as they are.
If you use a LocalDateTime from a ZonedDateTime, you extract the date and time representation ignoring the zone, which enables you to add a different zone afterwards and keep the date and time as it was.
Edit: If the code is running in the same JVM as the faulty code, you can use ZoneId.systemDefault() to get the same time zone as the faulty code is using. And depending on taste you may use ZoneOffset.UTC instead of ZoneId.of("GMT").
I am afraid you will not get around some calculations here. I'd strongly suggest to follow an approach based on java.time classes, but alternatively you might use the java.util.Calendar class and myCalendar.get(Calendar.ZONE_OFFSET) for those calculations:
https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#ZONE_OFFSET

How to change time zone in calendar without changing my time format in java?

I have a problem in java. I have a calendar in my java program and I want to set time zone to my local time zone.
I was able do do this and it works very well. My problem is when I change time zone in calendar time format in calendar change to 12H from 24H and i don't want this!
my question is How to change time zone in calendar without changing my time format in java?
this is my code for time zone change :
public static Calendar setTimeZoneToTehran(Calendar calendar) {
TimeZone timeZoneOfTehran = TimeZone.getTimeZone("Asia/Tehran");
calendar.setTimeZone(timeZoneOfTehran);
return calendar;
}
Just a quick thought, in case you are using time format to read/parse purpose you can use SimpleDateFormat to the desired format.
Date date = calendar.getTime();
System.out.println(format.format(date));
As #devilpreet already said, formatting in Calendar is only additional, bonus feature. This class is designed to keep info about date and time, formatting of date is encapuslated in SimpleDateFormat class.
Moreover, consider using Joda Time or java.time(from Java 8) instead of java.util.Calendar(in some circles using java.util.Calendar and Date is considered a bad practice).

Getting the exact time and date for my log track

Good day Lovely people
Please help a brother out. Well I'm a master in visual basic but in java let me rather not say.
In VB here are my methods:
System.DateTime.Now.ToLongTimeString()
System.DateTime.Now.ToString() + "/" + System.DateTime.Now.Month.ToString() + "/" + System.DateTime.Now.Year.ToString()
The first method will return the exact time e.g = 12:08:36 AM
And the second method will return the exact date e.g = 2012/09/26
I want to get the very same results but using java.How do i go about doing that.
Oooh Thanks in advance.
In .NET, DateTime.Now gives you the local date and time, in your local time zone.
If you use new Date() or the like in Java, it will give you a value which has no awareness of time zones. To take time zones into account, you should either create a Calendar which has the right time zone, or if you want to create an appropriate string you should use SimpleDateFormat - again, set to the right time zone before formatting. For example:
SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd", Locale.US);
format.setTimeZone(...); // Whichever time zone you want
String text = format.format(new Date()); // "now"
Also note that Joda Time is a much better Java API for date/time than the built-in Calendar and Date classes.
Finally, your second piece of sample code in .NET is buggy - you should only evaluate DateTime.Now once; ideally just passing in a format string e.g. DateTime.Now.ToString("yyyy/MM/dd"). Even if you want to convert each bit to a string separately, however, you fetch the value once to a local variable and then reuse it. Otherwise, if you execute that code around midnight, the date can change - so for example, if you executed it just before the start of 2013, you could end up with a string of "2012/12/1" or "2012/1/1" neither of which would be correct.
Use java.text.SimpleDateFormat class to format date and new java.util.Date() will create an instance system date default.
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
SimpleDateFormat dateFormat1 = new SimpleDateFormat("hh:mm:ss a");
System.out.println(dateFormat.format(new Date)); //2012/09/26
System.out.println(dateFormat1.format(new Date)); //12:08:36 AM
To get the object representing the current date, you can use just new Date(), to format it, use SimpleDateFormat.

how to deal with international time?

i build a new website.but the host is in USA.i am not in USA.
i need get the time on the website page to compare with one local Variable.
But because of time difference,it has 8 hous difference。how to solve this problom?
my code
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
java.util.Date currentTime = new java.util.Date();
String dateString = formatter.format(currentTime); `
how to revise these code ?
java.util.Date does not support timezones. You should pass the TimeZone to the formatter instead, by calling formatter.setTimeZone(tz).
joda-time is considered a better choice when working with dates. Note that for the sake of formatting it is fine to use Date, but it is a general advise not to rely on it when it comes to i18n. (Note the many deprecated methods there)
Then make each user set his timezone. Ideally suggest / assume the timezone based on his browser locale. See here
And always store the dates in a fixed timezone - preferably GMT/UTC.
In order to handle timezones, Java includes the Olson timezone database. Find the city in the database that is in the same time zone as you are.
First, you need to get a TimeZone object for the timezone you want. Then, get a Calendar object with the current date and time (or the date and time you wish to use). You can format that with a SimpleDateFormat object.
TimeZone local = TimeZone.getTimeZone("Asia/Tokyo");
Calendar now = Calendar.getInstance(local); // gets time in the current timezone
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
formatter.setTimeZone(local)
String dateString = formatter.format(now.getTime());
Though if you're doing a lot of time manipulation, like Bozho says, go for joda-time. The Java date/time system is confusing and rather poorly designed.
In such cases I always change timezone in Linux:
mv /etc/localtime /etc/localtime-backup
ln -sf /usr/share/zoneinfo/Europe/Amsterdam /etc/localtime
It also can be helpful for reading log files for example (I always see my local time instead of calculating it each time when I need to dig into them)
I think you need to use a Calendar (they are more useful generally than just Date objects). If you create a Calendar, initialised with your locale and timezone, you can do calendar.setDate() using the date you created. If you create another Calendar object with the fields that were entered, you can then do comparisons between the two Calendar objects.

How to make Date locale-independent?

I have a db, that stores dates in OleDateTime format, in GMT timezone. I've implemented a class, extending Date in java to represent that in classic date format. But my class is locale-dependent (I'm in GMT+2). Therefore, it converts the date in the db as date - 2 hours. How do I make it convert the date correctly? I want my class to be locale-independent, always using GMT timezone. Actually, the question is:
class MyOleDateTime extends Date {
static {
Locale.setDefault(WhatGoesHere?)
}
// ... some constructors
// ... some methods
}
Well, it's better to use the Calendar object like suggested in other answers. However, if you really want to set global timezone, you can use TimeZone.setDefault(TimeZone.getTimeZone("UTC")); early in your application code. There is also user.timezone Java system property.
Also (just fun to know), it appears that the only country actually living by GMT/UTC time (without daylight saving changes) is Liberia.
In fact, Date objects per se are always locale- and timezone-independent. Its getTime() method will always return the number of milliseconds passed since January 1, 1970 00:00:00 (not counting leap seconds) in UTC. But if you want to get something else than milliseconds, you have to use Calendar, which is timezone-dependent. But it is the right way to go. You don't use that deprecated methods in Date class, do you?
As Michael Borgwardt has already said, the Java Date object does not know anything about timezones. It's just a wrapper for a number of milliseconds since 01-01-1970 00:00:00 UTC.
You start dealing with timezones only when you for example convert the Date object to a String using a DateFormat. You set the timezone on the DateFormat to specify in which timezone you want to see the Date.
DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss Z");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
String text = df.format(date); // text will contain date represented in UTC
A Date is locale-independent, always using GMT timezone. It's just a wrapper around a millisecond timestamp in GMT (more correctly: UTC).
The only things in Date that are timezone dependant are the deprecated methods like getDay() - that's why they're deprecated. Those use the default time zone. The correct thing to do is to avoid using those deprecated methods - not to set the default timezone to UTC! That could cause problems elsewhere, and you can't prevent other parts of the code from setting the default timezone to something else.
Use a Calendar object:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"),
locale);
Here's a snippet I used to calculate the GMT offset from the Calendar instance and format it. I appreciate all the help I've gotten from this site, its nice to contribute. I hope this helps someone somewhere. Enjoy.
Calendar calInst = Calendar.getInstance();
//calculate the offset to keep calendar instance GMT
int gmtOffsetMilli = calInst.get(Calendar.ZONE_OFFSET);
long gmtOffsetHr = TimeUnit.HOURS.convert(gmtOffsetMilli, TimeUnit.MILLISECONDS);
calInst = Calendar.getInstance(TimeZone.getTimeZone("GMT " + gmtOffsetHr));

Categories

Resources