Reputation: 143
Why are the outputs are not the same?
Date currentTrueSystemDate = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kuwait"));
String newConvertedDate = sdf.format(currentTrueSystemDate.getTime());
System.out.println(newConvertedDate);
try {
Date newConvertedDate2 = sdf.parse(newConvertedDate);
System.out.println(newConvertedDate2);
} catch (ParseException e) {
System.out.println(e.getLocalizedMessage());
}
output:
I/System.out: 27-Sep-2018 09:16:52
I/System.out: Thu Sep 27 07:16:52 GMT+01:00 2018
The reason I am converting "newConvertedDate" from a string to date because I want to use the .before
and .after
functions on it. I don't understand why parsing a string into date changes the time?
Upvotes: 3
Views: 1854
Reputation: 5542
I don't understand why parsing a string into date changes the time?
format()
will convert a date(which has no timezone, it is the number of milliseconds passed since 1970-01-01 00:00:00 UTC) into a string representation in the timezone you specified, in this case, Kuwait.
So the first time you get a String in Kuwait timezone and just print it. This is just a string with no time zone info. But the time is Kuwait time.
Then you convert the string into a date using parse() which is assuming that the date is in Kuwait time as sdf instance is same. Now this string is converted to a date and System.out.println prints it in your local timezone.
Thing to note is that both time are same just different timezones.
If you want same times, you need to create a new instance of SimpleDateFormat and pass the date string to it. So that it would assume that this is the local time zone date and parse to return a date which when printed will again give the same value. However note that this date isn’t the same as previous one, just the time is same.
Do like this
Date currentTrueSystemDate = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kuwait"));
String newConvertedDate = sdf.format(currentTrueSystemDate.getTime());
System.out.println(newConvertedDate);
try {
sdf = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
Date newConvertedDate2 = sdf.parse(newConvertedDate);
System.out.println(newConvertedDate2);
} catch (ParseException e) {
System.out.println(e.getLocalizedMessage());
}
Upvotes: 1
Reputation: 338181
Use modern java.time classes.
Here is a brief but nonsensical example of going from current moment in a time zone to text in your desired format without zone/offset, and then back again to a moment in a time zone.
LocalDateTime.parse( // Represent a date and time-of-day without a time zone or offset-from-UTC. **NOT* a moment, but represents potential moments along a range of about 26-27 hours.
ZonedDateTime.now( ZoneId.of( "Asia/Kuwait" ) ) // Represents a moment, a point on the timeline, a date and time-of-day with an assigned time zone.
.format( DateTimeFormatter.ofPattern( "dd-MMM-yyyy HH:mm:ss" , Locale.US ) ) // Generate a `String` with text representing the value of our `ZonedDateTime` object.
,
DateTimeFormatter.ofPattern( "dd-MMM-yyyy HH:mm:ss" , Locale.US ) // Specify `Locale` to determine the human language and cultural norms used in localizing such as parsing the name of the month.
) // Returns a `LocalDateTime` object.
.atZone( ZoneId.of( "Asia/Kuwait" ) ) // Assign a time zone to the `LocalDateTime` to determine a moment, to generate a `ZonedDateTime` object.
You are using terrible old date-time classes that were supplanted years ago by the java.time classes.
Also, I suspect you meant HH
for 24-hour clock rather than lowercase hh
for 12-hour clock.
First, get the current moment.
ZoneId z = ZoneId.of( "Asia/Kuwait" ); // FYI, `Asia/Kuwait` is an alias of `Asia/Riyadh`.
ZonedDateTime zdt = ZonedDateTime.now( z );
zdt.toString(): 2018-09-27T22:41:45.314343+03:00[Asia/Kuwait]
Next, generate text in your desired format to represent the value of our ZonedDateTime
. Important: Notice that your string format is incomplete, lacking the fraction-of-second and lacking any indicator of time zone or offset-from-UTC.
Define a formatting pattern. Specify a Locale
to determine:
- The human language for translation of name of day, name of month, and such.
- The cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.
Get a DateTimeFormatter
object.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MMM-yyyy HH:mm:ss" , Locale.US );
Generate text.
String output = zdt.format( f );
27-Sep-2018 22:41:45
Going back the other direction is trickier because your desired format for this string lacks any indicator of time zone or offset-from-UTC. Such a string does not represent a moment. Taken at face value, it could be any of many potential moments along a range of 26-27 hours (the range of time zones around the globe). I know, and you know, that the string is intended to be a moment in the time zone Asia/Kuwait
with an offset-from-UTC of three hours ahead. But the string does not literally say that.
So we must first parse the string as a LocalDateTime
, having no zone/offset.
LocalDateTime ldt = LocalDateTime.parse( output , f );
ldt.toString(): 2018-09-27T22:41:45
Then we inject the intended zone to determine a moment.
ZonedDateTime zdt2 = ldt.atZone( z );
zdt2.toString(): 2018-09-27T22:41:45+03:00[Asia/Kuwait]
To close the circle, let’s compare our second ZonedDateTime
object with the first. To do fairly, we must lop off the fraction-of-second omitted from your desired text format.
boolean sameZdt = zdt.truncatedTo( ChronoUnit.SECONDS ).isEqual( zdt2 );
true
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
Upvotes: 1
Reputation: 86148
If by “changes the time” you mean the point in time, formatting and parsing does not change that.
First you format the time using a formatter that uses Kuwait time (Arabia Standard Time, equal to UTC+03:00). We see that when tis happened, the time in Kuwait was 09:16:52.
Next you print a Date
object that is (close to) equal to the first one. System.out.println
implicitly calls newConvertedDate2.toString
to find out what to print. Date.toString
uses your JVM’s default time zone — GMT+01:00 — to render the string to print. When the time in Kuwait is 09:16:52, it is just 07:16:52 at UTC+01:00. So you are really getting the same time again.
Other tips:
SimpleDateFormat
and Date
— are long outdated and the former in particluar notoriously troublesome. Instead of using those consider adding the ThreeTenABP library to you Android project so you may use java.time, the modern Java date and time API. It is so much nicer to work with, and among other things much clearer about time zones.hh
is for hour with AM or PM from 01 through 12. You need uppercase HH
for hour of day from 00 through 23.Date
into a String
and parsing it back into a Date
. You may just as well use .before
and .after
on currentTrueSystemDate
.java.time
.Upvotes: 1
Reputation: 1
Date currentTrueSystemDate = Calendar.getInstance().getTime();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kuwait"));
String newConvertedDate = sdf.format(currentTrueSystemDate.getTime());
System.out.println(newConvertedDate);
try {
Date newConvertedDate2 = sdf.parse(newConvertedDate);
System.out.println(newConvertedDate2);
// Format the Date back to String here
System.out.println(sdf.format(newConvertedDate2));
} catch (ParseException e) {
System.out.println(e.getLocalizedMessage());
}
output: 27-Sep-2018 10:03:41 Thu Sep 27 03:03:41 EDT 2018 27-Sep-2018 10:03:41
Upvotes: 0