对于 GMT +x 区域,Android 日历全天活动日期提前一天

Posted

技术标签:

【中文标题】对于 GMT +x 区域,Android 日历全天活动日期提前一天【英文标题】:Android Calendar All Day event dates are off by one day for GMT +x Areas 【发布时间】:2012-12-26 19:09:32 【问题描述】:

我使用官方网站上的教程编写了一个简单的代码来将全天事件插入日历。 http://developer.android.com/guide/topics/providers/calendar-provider.html

    ContentResolver cr = context.getContentResolver();
    ContentValues values = new ContentValues();
    values.put(Events.DTSTART, dueDate.getTime());
    values.put(Events.ALL_DAY, true);   
    values.put(Events.DTEND, dueDate.getTime());
    values.put(Events.TITLE, "Some Event");
    values.put(Events.CALENDAR_ID, mCalID);
    TimeZone tz = TimeZone.getDefault();
    values.put(Events.EVENT_TIMEZONE, tz.getID());
   Uri uri = cr.insert(Events.CONTENT_URI, values);

我发现当我在运行 4.03 的 Acer 设备上打开 Google 日历应用程序时,输入的日期已向后移动 1 天。我的本地时区是悉尼,即 GMT+10。

所以我去设置将本地时区更改为美国东部 (GMT -5) 并运行相同的代码,并且日期没有变化。然后我将时区更改为 GMT+2,伊斯坦布尔,日期发生了变化。然后我改到伦敦格林威治标准时间 0,没有班次。

当我进行非全天活动时,无论时区如何,日历中都会输入正确的时间。

我发现的最接近的错误报告是这个 http://code.google.com/p/android/issues/detail?id=14051

我是否在代码中遗漏了什么,或者其他人也遇到过这种情况。

编辑 使用内容解析器读取事件数据时的进一步检查

  ContentResolver cr = context.getContentResolver();
Uri uri =  CalendarContract.Events.CONTENT_URI; 
String selection =CalendarContract.Events._ID + "=?";
String [] selectionArgs = new String[]String.valueOf(eventID); 

转换为日期时的 long 值是正确的日期和时间,例如。 2013 年 2 月 14 日 12.00 AEST(悉尼时间)。所以问题一定出在谷歌日历读取这些值的方式上。当我从 Android 中的日历应用程序手动添加全天事件并使用内容解析器读取时间时,它是 AEST(悉尼时间)的日期和上午 11 点,对应于悉尼的 +11 GMT 关闭时间。 因此,需要在 GMT 中输入全天事件以避免这种情况,但文档中没有提及这一点。

所以现在我正在转移时间,以避免这个问题。

【问题讨论】:

【参考方案1】:

几个想法:

    全天事件的时区“独立性”(视为具有 GMT)[1] [2] 国际日期变更线

[1]"如果 allDay 设置为 1,则 eventTimezone 必须为 TIMEZONE_UTC,并且时间必须对应于午夜边界。"

[2]http://developer.android.com/reference/android/provider/CalendarContract.Events.html

【讨论】:

为什么全天事件时区独立?为什么即使在查询 Instances 表时它们也与时区无关?这根本没有意义。 当我添加全天事件来设计日历 android 它显示时区是加尔各答前一天请帮助我 我也遇到了同样的问题。可以给我它的代码吗? @Harsha 你有解决问题的办法吗?【参考方案2】:

如果我的活动是全天活动,我会将其转换为当地时间。这使得全天活动保持在正确的日期。如果不是一整天,我就照常离开。我不认为这是一个很好的解决方案,但它确实有效,如果有人发现它有问题,请告诉我。

        var startDate = yourCalendarEvent.StartDate;
        if (yourCalendarEvent.IsAllDay)
        
            startDate = startDate.ToLocalTime();
        
        Java.Util.GregorianCalendar calStartDate = new Java.Util.GregorianCalendar(startDate.Year, startDate.Month - 1, startDate.Day, startDate.Hour, startDate.Minute, startDate.Second);
        intent.PutExtra(CalendarContract.ExtraEventBeginTime, calStartDate.TimeInMillis);

【讨论】:

【参考方案3】:

CalendarContract.EventsColumns 的文档声明“如果 allDay 设置为 1,则 eventTimezone 必须为 TIMEZONE_UTC,并且时间必须对应于午夜边界。”

我确保在查询 API 后返回预期日期的解决方案是 a) 将开始和结束事件值设置为与 UTC 对齐的日期。 b) 调整查询后返回的时间,考虑设备时区和夏令时。

一)

@Before
public void setup()
    ...
    mJavaCalendar = Calendar.getInstance();
    mInputStart = getUtcDate(
            mJavaCalendar.get(Calendar.YEAR),
            mJavaCalendar.get(Calendar.MONTH),
            mJavaCalendar.get(Calendar.DAY_OF_MONTH));


private long getUtcDate(int year, int month, int day)
    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    calendar.set(year, month, day,0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTimeInMillis();


@Test
public void jCalAlldayTzDflt0000To2400()
    mTodayEvent.setEventStart(mInputStart);
    mTodayEvent.setEventEnd(mTodayEvent.getEventStart() +  DateUtils.DAY_IN_MILLIS);
    mTodayEvent.setAllDay(true);
    ...

b)

public static long getTzAdjustedDate(long date)
    TimeZone tzDefault = TimeZone.getDefault();
    return date - tzDefault.getOffset(date);


public void getCorrectDate(cursor)
    isAllDay() == 1 ? DateTimeUtils.getTzAdjustedDate(cursor.getLong(INST_PROJECTION_BEGIN_INDEX)) :
            cursor.getLong(INST_PROJECTION_BEGIN_INDEX));

我希望这会有所帮助。

【讨论】:

以上是关于对于 GMT +x 区域,Android 日历全天活动日期提前一天的主要内容,如果未能解决你的问题,请参考以下文章

GoogleMap(Android)投影可见区域在方向更改后未更新?

对于时间序列图,如何将x轴设置为没有周末的日历时间

给定的工件包含一个字符串文字,其中包含无法安全重写的包引用“android.support.v4.content”。对于 androidx

【Android图标拖到】怎样实现长按某个图标或图片等控件,拖曳到一个特定的区域。判断它落在那个区域?

Android中Native ELF的反汇编与破解的一些经验

android 屏幕划分