问题描述
我正在尝试将一个时区的午夜转换为另一个时区的午夜。 Kotlin在很大程度上简化了时区的转换,但是在将日期和时间转换为毫秒时,它的工作方式不同。
问题:
Indian Time: Mon Sep 28 00:00:00 GMT+5:30 2020
Vancouver Time: Sunday Sep 27 11:30:00 GMT-7:00 2020
我需要什么
Indian Time: Mon Sep 28 00:00:00 GMT+5:30 2020
Vancouver Time: Sunday Sep 27 11:30:00 GMT-7:00 2020
这是我尝试过的:
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
输出:
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
然后我将其转换为毫秒,如下所示:
Log.d("Datey2","After conversion {$VancouverMnight.time}") // using time function gives output in milliseconds
但是当我将温哥华的输出转换为毫秒时,会得到以下信息:
1601186400000 // Sep 26 23:00:00 2020 - Goes 2 days before the given time
1601145000000 // Sep 26 11:30:00 2020
我需要什么:
Sep 27 11:30:00 2020
Sep 27 00:00:00 2020 (I need these in milliseconds)
解决方法
问题是您试图直接编写java.util.Date
对象,该对象输出java.util.Date#toString
的值。请注意,日期时间对象应该存储有关日期,时间,时区等的信息,但不存储格式信息。 java.util.Date
对象不是像modern date-time classes这样的真实日期时间对象;相反,它表示距1970年1月1日的毫秒数。打印java.util.Date
的对象时,其toString
方法将返回从该毫秒值计算出的日期时间。由于java.util.Date
没有时区信息,因此它将应用JVM的时区并显示相同的时区。如果您需要在其他时区中打印日期时间,则需要将时区设置为SimpleDateFomrat
,并从中获取格式化的字符串,例如
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));
}
}
输出:
2020/09/29 17:57:06+0530 IST
2020/09/29 05:27:06-0700 GMT-07:00
我建议您从过时且容易出错的java.util
日期时间API和SimpleDateFormat
切换到modern java.time
日期时间API和相应的格式化API (软件包java.time.format
)。从 Trail: Date Time 了解有关现代日期时间API的更多信息。如果您的Android API级别仍不符合Java-8,请检查Java 8+ APIs available through desugaring和How to use ThreeTenABP in Android Project。
使用现代的日期时间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));
}
}
输出:
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
我不了解Kotlin,但我相信您应该能够直接在Kotlin中使用Java代码。如果没有,至少您应该能够使用Kotlin语法进行转换。
,由于您使用的是Joda-Time,因此我建议您坚持使用或继续使用现代Java日期和时间API java.time。远离Date
和SimpleDateFormat
。它们的设计不佳且已过时,绝对没有理由要触摸它们。
对于Java的Joda-Time解决方案,因为这是我可以编写和运行的内容:
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);
今天在亚洲/加尔各答时区运行时的输出:
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
自您提出问题以来,已经过去了一天,因此您无法将我的输出中的毫秒值与问题中的毫秒值进行比较,但是您可以验证它们是否符合您今天想要的值(印度已经是9月29日) )。
请注意,自纪元以来的毫秒数与时区无关。因此,无论您转换为美国/温哥华时区之前还是之后的毫秒数都没有区别。
如果要继续使用java.time,请遵循Arvind Kumar Avinash的良好回答。