Reputation: 4717
I have the below code
public Long getEpochTime(String dateToGetItsEpoch) throws ParseException
{
TimeZone timeZone = TimeZone.getTimeZone("UTC");
final String REQUEST_DATE_FORMAT = "dd/MM/yyyy h:m";
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date localDate = format.parse(dateToGetItsEpoch);
Calendar cal = Calendar.getInstance(timeZone);
cal.setTime(localDate);
format.setTimeZone(timeZone);
final String utcTime = format.format(cal.getTime());
Date d = cal.getTime();
return d.getTime();
}
If I change the locale of my device to whatever, I always get the UTC time as the return value. Which is correct, however I want to know how is this happening ? How does the device know Which timezone is the date I am giving to it so that it calculates accordingly ?
Upvotes: 1
Views: 241
Reputation: 338875
The Answer by Jon Skeet is correct. Here is some code updated to use the modern java.time classes that have supplanted the troublesome legacy date-time classes.
Define a formatting pattern to match your inputs.
By the way, yours is a poor choice of formats. Instead I recommend using the standard ISO 8601 formats designed for exchanging date-time values as text.
Your input data or formatting pattern has a flaw. You used lowercase h
which means one or two digits for an hour in the 12-hour clock (rather than 24-hour clock, which is uppercase H
or HH
). So your input makes no sense unless you add some indicator of AM
or PM
. I will assume you mistakenly omitted this from your Question's code.
Locale locale = Locale.US ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu h:m a" ).withLocale( locale ) ;
LocalDateTime
Parse such strings as LocalDateTime
objects, as they lack an indicator of the intended time zone or offset-from-UTC.
String input = "23/01/2020 4:5 PM" ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
ldt.toString(): 2020-01-23T16:05
The LocalDateTime
object we obtained above does not represent a moment, is not a point on the timeline. We have a time of around 4 PM on the 23rd. But we cannot know if this was meant to be 4 PM in Tokyo, Toulouse, or Toledo — all very different moments several hours apart.
To determine a moment, we must know for certain the intended time zone. Then apply that zone as a ZoneId
to get a ZonedDateTime
. Then we have arrived at a moment.
Locale
is not a time zonelocale of my device to whatever
A Locale
has nothing to with time zone. A Locale
is used for localizing generated text representing a date-time object.
To localize, specify:
FormatStyle
to determine how long or abbreviated should the string be.Locale
to determine:
Example:
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.JAPAN, etc.
DateTimeFormatter f =
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( l )
;
String output = myZonedDateTime.format( f );
You could have an engineer from Québec who uses the Locale.CANADA_FRENCH
for human language and cultural norms, but while visiting in Japan uses Asia/Tokyo
time zone for scheduling appointments.
ZonedDateTime
Back to your LocalDateTime
object. If you are certain it was meant to represent a moment as seen in the wall-clock time in Tunisia, then apply a time zone of Africa/Tunis
.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
You asked:
How does the device know Which timezone is the date I am giving to it so that it calculates accordingly ?
You were using terrible date-time classes that failed to account for the concept of a date-time lacking an indicator of time zone or offset-from-UTC. So technically, your code is a mess, a hack, unavoidable in those days before Joda-Time and its successor, java.time.
I suggest spending no effort on trying to understand that behavior of Date
& Calendar
. Just move on to using java.time, the industry-leading date-time handling framework.
Upvotes: 1
Reputation: 1501163
A Date
doesn't have a time zone at all. A SimpleDateFormat
does as a default for parsing and formatting; a Calendar
does too; a Date
doesn't.
Given this sequence of operations:
TimeZone timeZone = TimeZone.getTimeZone("UTC");
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date localDate = format.parse(dateToGetItsEpoch);
Calendar cal = Calendar.getInstance(timeZone);
cal.setTime(localDate);
format.setTimeZone(timeZone);
final String utcTime = format.format(cal.getTime());
... you're initially parsing the string using the default time zone of the device, then you're formatting it in UTC. Note that the Calendar
part is irrelevant here - you'd get the same result with:
TimeZone timeZone = TimeZone.getTimeZone("UTC");
DateFormat format = new SimpleDateFormat(REQUEST_DATE_FORMAT);
Date date = format.parse(dateToGetItsEpoch);
format.setTimeZone(timeZone);
final String utcTime = format.format(date);
I would personally recommend using Joda Time where possible for date/time work in Java, mind you. It's a much cleaner API than Calendar
/Date
.
Upvotes: 3