In my app, I am using SimpleDateFormat to convert the Date object to a string. But sometime when I change the time zone one by one to test whether the date I enter is the same as the date converted to a string, I found that it shows a different date. For example, suppose I have Thu Mar 15 00:00:00 GMT+08:00 2012 in my Date object, Now when I convert it to a string using SimpleDateFormat it works fine, but when I change the time zone one by one and check whether the date converted to string is same as it stored in Date object then in some cases it shows as 14-Mar-2012 instead of showing 15-Mar-2012. Why this happen? Can anyone please suggest me how to solve this out?
Code I have used:
SimpleDateFormat m_sdFormatter = new SimpleDateFormat("dd-MMM-yyyy");
String selected_date = m_sdFormatter.format(btnSelectedDt.getTime());
try this ,hope it may help you..
private String getDate(long timeStamp) {
DateFormat objFormatter = new SimpleDateFormat("dd-MM-yyyy");
objFormatter.setTimeZone(TimeZone.getDefault());
Calendar objCalendar = Calendar.getInstance(TimeZone.getDefault());
objCalendar.setTimeInMillis(timeStamp * 1000);
String result = objFormatter.format(objCalendar.getTime());
objCalendar.clear();
return result;
}
For example suppose i have Thu Mar 15 00:00:00 GMT+08:00 2012 in my Date object,
You haven't got that (even though that's no doubt what toString displays). A Date object doesn't contain a time zone. It contains an instant in time, which can be interpreted as different dates and times based on the calendar and time zone you use to interpret it. So that's midnight in once specific time zone - but the Date object itself is just a number of milliseconds since the unix epoch.
It's not clear exactly what you're doing, but you shouldn't be surprised that changing the time zone used in SimpleDateFormat will change the date written out. If you can describe in more detail what the larger goal is, we may be able to help you more. Note that if you can use Joda Time instead, that's a much better date/time API - but I know that it's quite large for use in an Android app.
In your SimpleDateFormat, mention the locale,
DateFormat objFormatter = new SimpleDateFormat("dd-MM-yyyy", locale);
where locale is of your choice. For eg, I use Locale.ENGLISH as it contains the date format that I require. Otherwise when you change ure locale in the device, the simpledateformat changes to current locale and you end up getting the wrong date.
Related
I'm working on an app where users can timestamp themselves IN or OUT from their workplace. At the moment I'm trying to get the localization of the timestamps done. For example when I make a timestamp in UTC +02:00 at 08:00 02.01.2020, it works correctly and shows the time as 08:00 and right date as well. But when I change to UTC +01:00 in my phone settings, and do the same timestamp, the time becomes 07:00 and date becomes 01.01.2020.
The code I have so far for "parsing" the time looks like this:
String formattedTime = "";
String datetime2 = "1970-01-01T" + returntime;
Log.v("DATE", datetime2);
OffsetDateTime odt2 = OffsetDateTime.parse(datetime2);
Date date2 = Date.from(odt2.toInstant());
SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm",Locale.getDefault());
formattedTime = sdf2.format(date2);
Log.v("FORMTIME", formattedTime);
I'm using a similar code snippet for "parsing" the date as well.
The output for the two logs (when in UTC +01:00):
V/DATE: 1970-01-01T15:00:00+02:00
V/FORMTIME: 14:00 //SHOULD BE 15:00
V/DATE: 1970-01-01T08:00:00+02:00
V/FORMTIME: 07:00 //SHOULD BE 08:00
V/DATE: 1970-01-01T08:00:00+02:00
V/FORMTIME: 07:00 //SHOULD BE 08:00
It seems like the change in UTC from +02:00 to +01:00 reduce the time and date also with 1...
So is it wrong to use the OffsetDateTime class and "toInstant" (Instant class) for what I'm trying to achieve? What would be the right solution?
OffsetTime
I don’t understand what that offset of +02:00 in your string signifies. In particular it confuses me what you want to do when the offset changes. In any case java.time, the modern Java date and time API, parses and formats your time pretty easily. Let’s first define the formatter that describes your desired output format:
private static final DateTimeFormatter timeFormatter
= DateTimeFormatter.ofPattern("HH:mm");
With this in place you may do:
String returntime = "15:00:00+02:00";
OffsetTime time = OffsetTime.parse(returntime);
String formattedTime = time.format(timeFormatter);
System.out.println(formattedTime);
Output:
15:00
The offset is parsed, but is not used for anything. The output time will always be the same as the time in the string.
I take it that the date 1970-01-01 that you used in your code is arbitrary and without significance. The OffsetTime that I am using hasn’t got a date, so saves us from choosing a date for processing the time.
Word use: There isn’t any localization going on here. Localization is when for an American audience you print 3:00 PM instead of 15:00, for example.
EDIT:
If your string contains a date too, OffsetDateTime is the right class to use, and again we need no explicit formatter for parsing (only for formatting). Your code in the comment is fine (except that you had accidentally reversed the order of day, month and year in the string).
String returnDate1 = "2020-12-05T00:00+02:00";
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
OffsetDateTime dateTime = OffsetDateTime.parse(returnDate1);
String formattedDate = dateTime.format(dateFormatter);
System.out.println(formattedDate);
05-12-2020
What went wrong in your code?
It seems you were over-complicating things. In particular you were mixing old and modern date-time classes. The old ones, Date and SimpleDateFormat, are poorly and confusingly designed, which no doubt contributed to your unexpected results. And when mixing, you are going to need conversions that are not really needed for your job, again just making your code more complicated than needed.
Your sdf2 was using your default time zone for printing the time. You had got offset +02:00 in the string, so when you set the phone to UTC+01:00, a conversion takes place. When the time is 08:00 at offset +02:00, it is only 07:00 at offset +01:00. So this was the result you got. This in turn means that if the user’s time zone was at offset +01:00 on 1970-01-01, then you were getting the correct times for that time zone.
I tried to remove minute from given time, but some how it is converting time to my local time zone
String timeStamp="20180623 05:58:15" ;
dateFormat inputFormatter = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
Date date = inputFormatter.parse(timeStamp);
date.setMinutes(-2);
logger.info("Before converting : "+date);
DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
Here it is converting to my local time and subtracting 2 minutes from given time, but I don`t want to check the time zone here instead, what ever time I give it should just subtract 2 minutes.
Start with understanding into how Date works. When you do...
logger.info("Before converting : "+date);
The Date class uses it's toString method to format the the date/time information represented by the Date class into a human readable format. It doesn't "convert" the date/time value in anyway
So taking your code from above (and reworking it so it works), it outputs...
Before converting : Sat Jun 23 04:58:15 AEST 2018
20180623 04:58:15
on my machine - why are the values the same? Because the input doesn't have any time zone information, so the time is likely been treated as been in the machines local timezone (and the value is simply been formatted for output).
Date is just a container for the number of milliseconds since the Unix Epoch, it's format agnostic - meaning it carries not formatting information.
Date is also effectively deprecated - not to mention that setDate is also very much deprecated
A better (starting point) overall is to make use the newer date/time API introduced in Java 8 (and which has back port support for earlier versions of the API)
String timeStamp = "20180623 05:58:15";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss", Locale.ENGLISH);
LocalDateTime ldt = LocalDateTime.parse(timeStamp, formatter);
ldt = ldt.minusMinutes(2);
System.out.println(ldt);
System.out.println(ldt.format(formatter));
This will output...
2018-06-23T05:56:15
20180623 05:56:15
The input and the output are still consider as been in the machines local time zone.
but I don`t want to check the time zone here instead, what ever time I give it should just subtract 2 minutes
Just remember, the API still needs to have some concept of time zone, weather it's the local time zone or UTC/GMT, but since your input doesn't provide any kind of information, you need to make a choice over "how" best to handle that issue. The example above just "assumes" local time, but you could use ZonedDateTime and convert it to "common" time zone from which your operations are executed or, better yet, make all your strings carry time zone information
Oh, and for the love of my sanity, stop managing date/time values in String format - get them into an appropriate container as soon as possible and manage them from there - I've spent a week wrangling inappropriately formatted date strings and I'm not happy Jan, not happy
I am trying to get my current system date and am formatting it into Etc/UTC and then into this "dd.MM.yyyy HH:mm z" format. The problem is this that the format function after formatting the date returns a string instead of date. Here is the code spinet below
final Date currentDate = new Date();
final SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy HH:mm z");
dateFormatter.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String finalDateTime= dateFormatter.format(currentDate);
System.out.println(finalDateTime);
Is there any alternative solution which allows me to format the date by keeping me within this date object because I have researched every date library after java 8 and before java 8, it seems like if I want to format any type of date or dateTime, I have to use a formatter which converts the given date into string.
Any Alternative solutions or it is not possible?
Date represents a single point in time. That's it, nothing more, nothing less. It does not contain any information about time zones.
Wed Jun 06 12:38:15 BST 2018 is the same Date (instant) as Wed Jun 06 11:38:15 GMT 2018, just in a different time zone. It's like the words "humans" and "homo sapians". They refer to the same species, they are just kind of in a different "format".
So you don't need to change the date in any way. You just need to format it differently. This is why formatters return Strings. Only Strings can represent one particular format of a date.
I'm having trouble parsing a date format that I'm getting back from an API and that I have never seen (I believe is a custom format). An example of a date:
/Date(1353447000000+0000)/
When I first encountered this format it didn't take me long to see that it was the time in milliseconds with a time zone offset. I'm having trouble extracting this date using SimpleDateFormat though. Here was my first attempt:
String weirdDate = "/Date(1353447000000+0000)/";
SimpleDateFormat sdf = new SimpleDateFormat("'/Date('SSSSSSSSSSSSSZ')/'");
Date d1 = sdf.parse(weirdDate);
System.out.println(d1.toString());
System.out.println(d1.getTime());
System.out.println();
Date d2 = new Date(Long.parseLong("1353447000000"));
System.out.println(d2.toString());
System.out.println(d2.getTime());
And output:
Tue Jan 06 22:51:41 EST 1970
532301760
Tue Nov 20 16:30:00 EST 2012
1353447000000
The date (and number of milliseconds parsed) is not even close and I haven't been able to figure out why. After some troubleshooting, I discovered that the way I'm trying to use SDF is clearly flawed. Example:
String weirdDate = "1353447000000";
SimpleDateFormat sdf = new SimpleDateFormat("S");
Date d1 = sdf.parse(weirdDate);
System.out.println(d1.toString());
System.out.println(d1.getTime());
And output:
Wed Jan 07 03:51:41 EST 1970
550301760
I can't say I've ever tried to use SDF in this way to just parse a time in milliseconds because I would normally use Long.parseLong() and just pass it straight into new Date(long) (and in fact the solution I have in place right now is just a regular expression and parsing a long). I'm looking for a cleaner solution that I can easily extract this time in milliseconds with the timezone and quickly parse out into a date without the messy manual handling. Anyone have any ideas or that can spot the errors in my logic above? Help is much appreciated.
Take the milliseconds value in the string:
/Date(1353447000000+0000)/
and pass that value as a long into the Date constructor:
Date date = new Date(1353447000000);
and format the date object using SimpleDateFormat.
Even though it's pretty much what you're doing now, I don't think there's much wrong with the manual method - other than it's a shame you have to go there!
I don't believe you can do it solely with SDF.
This will give you a date reasonably 'elegantly':
Date date = new Date(Long.parseLong(weirdDate.split("[^\\d]")[6]));
I'm sure you've already considered it, but have you spoken to the producer of the API to see why they are outputting this value in such an odd format? If the interface is not public and/or not widespread they may consider changing it to something a bit more conventional.
I've tried a million different ways of doing this, but with no avail. Any help would be much appreciated.
long millis = getMillisFromServer();
Date date = new Date(millis);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
String formatted = format.format(date);
The above doesn't work.
basically, what I want to do is, get the epoch time and convert it to Australian time. My local time is +05.30 but of course I don't want this to be a factor which contributes to this conversion.
EDIT-
Output when I run your exact code,
epoch 1318388699000
Wed Oct 12 08:34:59 GMT+05:30 2011
12/10/2011 03:04:59
12/10/2011 14:04:59
EDIT: Okay, so you don't want your local time (which isn't Australia) to contribute to the result, but instead the Australian time zone. Your existing code should be absolutely fine then, although Sydney is currently UTC+11, not UTC+10.. Short but complete test app:
import java.util.*;
import java.text.*;
public class Test {
public static void main(String[] args) throws InterruptedException {
Date date = new Date(1318386508000L);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String formatted = format.format(date);
System.out.println(formatted);
format.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
formatted = format.format(date);
System.out.println(formatted);
}
}
Output:
12/10/2011 02:28:28
12/10/2011 13:28:28
I would also suggest you start using Joda Time which is simply a much nicer date/time API...
EDIT: Note that if your system doesn't know about the Australia/Sydney time zone, it would show UTC. For example, if I change the code about to use TimeZone.getTimeZone("blah/blah") it will show the UTC value twice. I suggest you print TimeZone.getTimeZone("Australia/Sydney").getDisplayName() and see what it says... and check your code for typos too :)
Here’s the modern answer (valid from 2014 and on). The accepted answer was a very fine answer in 2011. These days I recommend no one uses the Date, DateFormat and SimpleDateFormat classes. It all goes more natural with the modern Java date and time API.
To get a date-time object from your millis:
ZonedDateTime dateTime = Instant.ofEpochMilli(millis)
.atZone(ZoneId.of("Australia/Sydney"));
If millis equals 1318388699000L, this gives you 2011-10-12T14:04:59+11:00[Australia/Sydney]. Should the code in some strange way end up on a JVM that doesn’t know Australia/Sydney time zone, you can be sure to be notified through an exception.
If you want the date-time in your string format for presentation:
String formatted = dateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
Result:
12/10/2011 14:04:59
PS I don’t know what you mean by “The above doesn't work.” On my computer your code in the question too prints 12/10/2011 14:04:59.
Please take care that the epoch time is in second and Date object accepts Long value which is in milliseconds.
Hence you would have to multiply epoch value with 1000 to use it as long value .
Like below :-
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
Long dateLong=Long.parseLong(sdf.format(epoch*1000));