安卓系统中的时区问题

12

我有一个以毫秒为单位的时间,并在我的应用程序中以 "MM/dd/yyyy HH:mm:ss" 格式显示该时间,它运作正常。

问题:如果我更改 Android 设备中的时区,则在我的应用程序中显示不同的时间,可能是因为某些时区计算。我想以任何时区中与数据库中相同的时间来显示时间。

我正在使用以下代码测试时区问题

Locale locale = new Locale("en", "IN");

TimeZone tz = TimeZone.getDefault();
System.out.println("Default timezon id :: " + tz.getID());
tz.setID("Asia/Calcutta");
String timezon = tz.getDisplayName(false, TimeZone.SHORT, locale);
System.out.println("Timezon id :: " + tz.getID() + " Timezon name :: " + timezon);
Calendar cal = Calendar.getInstance(tz, locale);

System.out.println("TImezon :: " + tz);
// "1319084400775" is the milliseconds of 10/20/2011 05:20:00 in MM/dd/yyyy HH:mm:ss format 
Date date = new Date(Long.parseLong("1319084400775"));
System.out.println("Date :: " + date.toGMTString());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", locale);

System.out.println("Start date :: " + format.format(date));
// "1319084400775" is the milliseconds of 10/20/2011 05:20:00 in MM/dd/yyyy HH:mm:ss format 
cal.setTimeInMillis(Long.parseLong("1319084400775"));

timezon = cal.getTimeZone().getDisplayName(false, TimeZone.SHORT, locale);
System.out.println("Calender's timezon :: " + timezon);
System.out.println("Start date :: yyyy-mm-dd hh:mm:ss " + cal.get(Calendar.YEAR) + "-" + cal.get(Calendar.MONTH) + "-" + cal.get(Calendar.DAY_OF_MONTH) + " " + cal.get(Calendar.HOUR_OF_DAY) + ":" + cal.get(Calendar.MINUTE));
// "1319084700776" is the milliseconds of 10/20/2011 05:25:00 in MM/dd/yyyy HH:mm:ss format 
cal.setTimeInMillis(Long.parseLong("1319084700776"));
System.out.println("End date :: " + cal.getTime());

输出 ::

如果我将时区设置为“太平洋/斐济”;

10-07 17:03:40.392: INFO/System.out(1193): Default timezon id :: Pacific/Fiji
10-07 17:03:40.392: INFO/System.out(1193): Timezon id :: Asia/Calcutta Timezon name :: GMT+05:30
10-07 17:03:40.406: INFO/System.out(1193): TImezon :: org.apache.harmony.luni.internal.util.ZoneInfo@7b42d3a7
10-07 17:03:40.422: INFO/System.out(1193): Date :: 20 Oct 2011 04:20:00 GMT
10-07 17:03:40.442: INFO/System.out(1193): Start date :: 2011-10-20 16:20:00
10-07 17:03:40.442: INFO/System.out(1193): Calender's timezon :: GMT+05:30
10-07 17:03:40.442: INFO/System.out(1193): Start date :: yyyy-mm-dd hh:mm:ss 2011-9-20 16:20
10-07 17:03:40.452: INFO/System.out(1193): End date :: Thu Oct 20 16:25:00 Pacific/Fiji 2011

如果我将时区设置为"America/Tijuana";

10-06 22:05:20.702: INFO/System.out(1193): Default timezon id :: America/Tijuana
10-06 22:05:20.712: INFO/System.out(1193): Timezon id :: Asia/Calcutta Timezon name :: GMT+05:30
10-06 22:05:20.712: INFO/System.out(1193): TImezon :: org.apache.harmony.luni.internal.util.ZoneInfo@1294e658
10-06 22:05:20.733: INFO/System.out(1193): Date :: 20 Oct 2011 04:20:00 GMT
10-06 22:05:20.742: INFO/System.out(1193): Start date :: 2011-10-19 21:20:00
10-06 22:05:20.742: INFO/System.out(1193): Calender's timezon :: GMT+05:30
10-06 22:05:20.752: INFO/System.out(1193): Start date :: yyyy-mm-dd hh:mm:ss 2011-9-19 21:20
10-06 22:05:20.752: INFO/System.out(1193): End date :: Wed Oct 19 21:25:00 America/Tijuana 2011

编辑

我现在有毫秒级别的时间,我正在将其以日期格式显示在我的应用程序中,但问题是当我在设备上更改时区时,我会根据该时区获取日期。


你能在打印行中添加(cal.get(Calendar.MONTH)+1)吗?还是我仍然不清楚你的问题是关于什么的? - jazz
@jazz 当我更改时区时,您可以看到输出不同,这不是我想要的,也就是说,我希望输出与我输入的日期和时间相同。 - Dharmendra
我遇到了一个问题,我从服务器检索到了一个时间,我需要在设备时区中显示它,而这个时区可能会动态变化。我使用了新的SimpleDateFormat("HH:mm", Locale.getDefault()); 但是当时区改变且应用程序已经启动时,它无法正确格式化。因此,我每次在实例化之前都设置时区,如下所示:<code> HOUR_MINUTE_FORMAT = new SimpleDateFormat("HH:mm", Locale.getDefault()); format.setTimeZone(TimeZone.getDefault()); </code> - Vishnu Prabhu
3个回答

13

日期仅是世界标准时间中的一个瞬间,没有时区的概念。可以将其视为“肯尼迪被杀时的时间”。

当使用SimpleDateFormat显示此时间时,该日期格式具有时区,并且您使用该时区显示此时间。因此,如果日期格式的时区为中央标准时间,则此时间将显示为12:30。如果时区为UTC,则将显示为18:30。

如果您希望某个日期始终以相同的方式显示,而不考虑时区,则只需选择特定的时区(例如UTC),并始终以该时区显示日期。因此,在对日期进行格式化之前,您必须在DateFormat上调用setTimeZone


但是如果我想要使用日历,那么我该如何解决这个问题呢?请帮帮我。 - Dharmendra
2
日历是日期的包装器。调用 getTime(),您将获得一个日期。 - JB Nizet
1
我只有在他们让我免于疯狂数小时后才会感恩。这是其中之一 ;) 非常感谢。 - Warpzit

4

在标准的 Java 中:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
sdf.setTimeZone(TimeZone.getTimeZone(<your timezone here>);

long millis = <your timestamp here>; //timestamps are not TZ dependent.
Date d = new Date(millis);
String toDisplay = sdf.format(d);
< p > SimpleDateFormat 中的时区是您要用于每个显示日期的固定时区,而不是设备的默认时区。 还要确保数据库中的时间戳列从与Java相同的时间点开始计数(1/1/1970,也称为Unix纪元),并具有相同的精度(毫秒)。

还有另一个 android.text.format.DateFormat 类,但我看不出使用它的任何意义。


SimpleDateFormat 使用时区。我检查了你的方法,但没有解决我的问题。 - Dharmendra
1
它必须正常工作。您必须设置一个固定的时区(始终相同)。例如,要在印度显示日期,请使用印度TZ。当设备TZ更改时,输出应保持不变。 - Mister Smith
是的,它可以工作,但如果我想使用日历,我该如何解决这个问题? - Dharmendra
使用Calendar.getInstance(<你的时区>)来获取一个Calendar实例。 - Mister Smith

3
我使用以下方法得到解决方案。
/**
     * Date time must be in milliseconds  
     * return Time in milliseconds
     */
    public static String getTimeInMilli(Context ctx, String datetime) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(Long.parseLong(datetime));
        //This will return daylight savings offset in milliseconds.You have to Subtract  this milliseconds from calendar
        int dayLightSaving  = cal.get(Calendar.DST_OFFSET);

        cal.setTimeInMillis(cal.getTimeInMillis() - dayLightSaving);

        TimeZone z = cal.getTimeZone();
        int offset = z.getRawOffset();
        int offsetHrs = offset / 1000 / 60 / 60;
        int offsetMins = offset / 1000 / 60 % 60;

        // Subtract offset of your current TimeZone
        cal.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
        cal.add(Calendar.MINUTE, (-offsetMins));

        cal.setTimeZone(TimeZone.getTimeZone("GMT"));

        //add offset of your TimeZone
        cal.add(Calendar.HOUR_OF_DAY, 5);
        cal.add(Calendar.MINUTE, 30);

        return String.valueOf(cal.getTimeInMillis());
    }

现在,如果我更改设备的时区,我的应用程序的日期将保持不变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接