Reputation: 476
I'm trying to convert midnight of one timezone to midnight of another time zone. Kotlin pretty much made it easy for the conversion of time zones but it does not work the same way when converting date and time to milliseconds.
Problem:
Indian Time: Mon Sep 28 00:00:00 GMT+5:30 2020
Vancouver Time: Sunday Sep 27 11:30:00 GMT-7:00 2020
What I need
Indian Time: Mon Sep 28 00:00:00 GMT+5:30 2020
Vancouver Time: Sunday Sep 27 11:30:00 GMT-7:00 2020
Here is what I tried:
val today = DateTime().withTimeAtStartOfDay().toDate() //current date and time converted to Date format
val dateOutputFormat = SimpleDateFormat("yyyy/MM/dd HH:mm:ss") // formatting the output as SimpleDateFormat
dateOutputFormat.setTimeZone(TimeZone.getTimeZone("America/Vancouver")) //Setting the timezone
Log.d("Datey2", "Before conversion ${today}") // Before conversion Mon Sep 28 00:00:00 GMT+5:30 2020
val Vancouver = Date(dateOutputFormat.format(today)).time //formatting the timezone
Log.d("Datey2", "After conversion $Vancouver") // After conversion Sun Sep 27 11:30:00 GMT+05:30 2020
val VancouverMnight = DateTime(Vancouver).withTimeAtStartOfDay().millis
Log.d("Datey2", "MidNight $VancouverMnight") // MidNight Sun Sep 27 00:00:00 GMT+05:30 2020
Output:
Before conversion Mon Sep 28 00:00:00 GMT+5:30 2020
After conversion Sun Sep 27 11:30:00 GMT+05:30 2020 // Note the GMT+5:30 in vacouver time
MidNight Sun Sep 27 00:00:00 GMT+05:30 2020
Then I convert these into milliseconds as follows
Log.d("Datey2", "After conversion {$VancouverMnight.time}") // using time function gives output in milliseconds
But when I convert those Vancouver outputs to milliseconds, I get the following:
1601186400000 // Sep 26 23:00:00 2020 - Goes 2 days before the given time
1601145000000 // Sep 26 11:30:00 2020
What I need:
Sep 27 11:30:00 2020
Sep 27 00:00:00 2020 (I need these in milliseconds)
Upvotes: 0
Views: 793
Reputation: 79095
The problem is that you are trying to write the java.util.Date
object directly which outputs the value of java.util.Date#toString
. Note that a date-time object is supposed to store the information about date, time, time-zone etc. but not about the formatting. The java.util.Date
object is not a real date-time object like the modern date-time classes; rather, it represents the milliseconds from the Epoch of January 1, 1970. When you print an object of java.util.Date
, its toString
method returns the date-time calculated from this milliseconds value. Since java.util.Date
does not have time-zone information, it applies the time-zone of your JVM and displays the same. If you need to print the date-time in a different time-zone, you will need to set the time-zone to SimpleDateFormat
and obtain the formatted string from it e.g.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ssZ z");
Date date = new Date();
// Date and time in India
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
// Output to be written to the log file
System.out.println(sdf.format(date));
// Date and time in Vancouver
sdf.setTimeZone(TimeZone.getTimeZone("America/Vancouver"));
// Output to be written to the log file
System.out.println(sdf.format(date));
}
}
Output:
2020/09/29 17:57:06+0530 IST
2020/09/29 05:27:06-0700 GMT-07:00
I recommend you switch from the outdated and error-prone java.util
date-time API and SimpleDateFormat
to the modern java.time
date-time API and the corresponding formatting API (package, java.time.format
). Learn more about the modern date-time API from Trail: Date Time. If your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Using the modern date-time API:
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ssZ z");
// Date and time in India
ZonedDateTime zdtNowIST = LocalDate.now().atStartOfDay((ZoneId.of("Asia/Calcutta")));
// Output in the default format
System.out.println(zdtNowIST);
// Output in the custom format
System.out.println(zdtNowIST.format(dtf));
// Date and time in Vancouver
ZonedDateTime zdtNowVancouver = zdtNowIST.withZoneSameInstant(ZoneId.of("America/Vancouver"));
// Output in the default format
System.out.println(zdtNowVancouver);
// Output in the custom format
System.out.println(zdtNowVancouver.format(dtf));
}
}
Output:
2020-09-29T00:00+05:30[Asia/Calcutta]
2020/09/29 00:00:00+0530 IST
2020-09-28T11:30-07:00[America/Vancouver]
2020/09/28 11:30:00-0700 GMT-07:00
I do not know Kotlin but I believe you should be able to use Java code directly in Kotlin. If not, at least you should be able to convert it using Kotlin syntax.
Upvotes: 2
Reputation: 86296
Since you are using Joda-Time, I recommend you either stick to that or move on to java.time, the modern Java date and time API. Stay away from Date
and SimpleDateFormat
. They are poorly designed and long outdated, and there is absolutely no reason why you should want to touch them.
For a Joda-Time solution in Java because this is what I can write and run:
DateTimeZone vancouverTimeZone = DateTimeZone.forID("America/Vancouver");
DateTimeFormatter dateOutputFormat = DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss")
.withZone(vancouverTimeZone);
DateTime today = new DateTime().withTimeAtStartOfDay();
System.out.println("Today: " + today);
System.out.println("Today as seen in Vancouver: " + today.toString(dateOutputFormat));
long millisBeforeConversion = today.getMillis();
System.out.println("Millis before conversion: " + millisBeforeConversion);
DateTime vancouverMidnight = today.withZone(vancouverTimeZone)
.withTimeAtStartOfDay();
long millisAfterConversion = vancouverMidnight.getMillis();
System.out.println("Millis after conversion: " + millisAfterConversion);
Output when running today in Asia/Kolkata time zone:
Today: 2020-09-29T00:00:00.000+05:30 Today as seen in Vancouver: 2020/09/28 11:30:00 Millis before conversion: 1601317800000 Millis after conversion: 1601276400000
A day has passed since you asked your questions, so you cannot compare the millisecond values from my output with your own from the question, but you can verify that they agree with what you would want for today (already September 29 in India).
Note that the count of milliseconds since the epoch is independent of time zone. So whether you get the milliseconds before or after conversion to America/Vancouver time zone makes no difference.
If you want to move on to java.time, follow the good answer by Arvind Kumar Avinash.
Upvotes: 2