如何解析Google日历Feed,包括.net中的重复活动

时间:2012-07-11 06:29:01

标签: parsing google-calendar-api recurring-events

我需要解析Google日历中的重复事件值。我可以解析除重复对象值之外的其余值。以下是我试图在我的asp.net MVC(C#)应用程序中从Google日历中提取事件的代码:

GOAuthRequestFactory authFactory = new GOAuthRequestFactory("cl", "MyApp");
authFactory.ConsumerKey = ConfigurationManager.AppSettings["GConsumerKey"].ToString();
authFactory.ConsumerSecret = ConfigurationManager.AppSettings["GConsumerKeySecret"].ToString();
authFactory.Token = "myGoogleToken";
authFactory.TokenSecret = "myGoogleTokenSecret";
Google.GData.Calendar.CalendarService service = new Google.GData.Calendar.CalendarService(authFactory.ApplicationName);
service.RequestFactory = authFactory;

Uri postUri = new Uri("https://www.google.com/calendar/feeds/default/private/full");

EventQuery myQuery = new EventQuery(postUri.ToString());
myQuery.StartTime = DateTime.Now;

EventFeed myResultsFeed = service.Query(myQuery);
if (myResultsFeed.Entries.Count > 0)
{
    foreach (EventEntry eve in myResultsFeed.Entries)
    {
        #region Declaration
        string w = string.Empty; string desc = string.Empty;                        
        #endregion

        #region Title / Description
        //Title
        if (eve.Title != null)
        {
            AtomTextConstruct _construct = eve.Title;
            if (_construct != null)
            {
               w = _construct.Text;
            }
        }
        //Description
        if (eve.Content != null)
        {
           AtomContent _content = eve.Content;
           if (_content.Content != null)
           {
               desc = Utility.GetValueFromMaxLength(_content.Content, 1000);
           }
        }
        #endregion

        if (eve.Recurrence != null)
        {
             Recurrence _recurrence = eve.Recurrence;
             if (_recurrence != null && !string.IsNullOrEmpty(_recurrence.Value))
             {

             }
         }
     }
}

复发的价值是:

DTSTART;TZID=America/New_York:20120710T090000
DTEND;TZID=America/New_York:20120710T093000
RRULE:FREQ=WEEKLY;BYDAY=TU
BEGIN:VTIMEZONE
TZID:America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE

我如何解析此Recurrence元素值?请建议。

1 个答案:

答案 0 :(得分:0)

我意识到这是一个非常古老的问题,但也许这可以帮助那些遇到同样问题的人。

首先,我有一个小类来解析一般的iCalendar数据:

using System.Collections;

namespace ICalendarHelpers
{
    public class Parser
    {
        /// <summary>
        /// Gets a hashtable representing an entire iCalendar object.
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static Hashtable Fields(string data)
        {
            Hashtable table = new Hashtable();

            string[] unfolded = Unfold(data);

            foreach (string entry in unfolded)
            {
                int index = entry.IndexOf(':');
                string key = entry.Remove(index);
                string value = entry.Substring(index + 1);

                if (!table.ContainsKey(key))    // Avoid duplicate entries
                    table.Add(key, value);
            }

            return table;
        }

        /// <summary>
        /// Gets a hashtable representing the value of a field in an iCalendar object.
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public static Hashtable Values(string field)
        {
            Hashtable table = new Hashtable();

            string[] split = field.Split(';');

            foreach (string entry in split)
            {
                int index = entry.IndexOf('=');
                string key = entry.Remove(index);
                string value = entry.Substring(index + 1);

                if (!table.ContainsKey(key))    // Avoid duplicate entries
                    table.Add(key, value);
            }

            return table;
        }

        private static string[] Unfold(string data)
        {
            ArrayList split = Split(data, "\r\n");
            int size = split.Count;

            for (int i = 0; i < size; i++)
            {
                string each = (string)split[i];

                if (each[0] == ' ')
                {
                    split[i - 1] += each.Substring(1);
                    split.RemoveAt(i);
                    i--;
                    size--;
                }
            }

            return (string[])split.ToArray(typeof(string));
        }

        private static ArrayList Split(string data, string delimiter)
        {
            ArrayList list = new ArrayList();

            int index = data.IndexOf(delimiter);

            while (index != -1)
            {
                list.Add(data.Remove(index));
                data = data.Substring(index + 2);
                index = data.IndexOf(delimiter);
            }

            if (!string.IsNullOrWhiteSpace(data))
                list.Add(data);

            return list;
        }
    }
}

因此,您在重复数据中首先注意到的是一堆时区数据:

DTSTART;TZID=America/New_York:20120710T090000
DTEND;TZID=America/New_York:20120710T093000

要将Olson时间(“America / New_York”)转换为Windows时区(“东部标准时间”),我使用以下功能:

private static Dictionary<string, string> windowsOlsonTimes = new Dictionary<string, string>()
{
    { "W. Central Africa Standard Time", "Africa/Bangui" },
    { "Egypt Standard Time", "Africa/Cairo" },
    { "Morocco Standard Time", "Africa/Casablanca" },
    { "South Africa Standard Time", "Africa/Harare" },
    { "Greenwich Standard Time", "Africa/Monrovia" },
    { "E. Africa Standard Time", "Africa/Nairobi" },
    { "Namibia Standard Time", "Africa/Windhoek" },
    { "Alaskan Standard Time", "America/Anchorage" },
    { "Argentina Standard Time", "America/Argentina/San_Juan" },
    { "Paraguay Standard Time", "America/Asuncion" },
    { "Bahia Standard Time", "America/Bahia" },
    { "SA Pacific Standard Time", "America/Bogota" },
    { "Venezuela Standard Time", "America/Caracas" },
    { "SA Eastern Standard Time", "America/Cayenne" },
    { "Central Standard Time", "America/Chicago" },
    { "Mountain Standard Time (Mexico)", "America/Chihuahua" },
    { "Central Brazilian Standard Time", "America/Cuiaba" },
    { "Mountain Standard Time", "America/Denver" },
    { "Greenland Standard Time", "America/Godthab" },
    { "Central America Standard Time", "America/Guatemala" },
    { "Atlantic Standard Time", "America/Halifax" },
    { "US Eastern Standard Time", "America/Indianapolis" },
    { "SA Western Standard Time", "America/La_Paz" },
    { "Pacific Standard Time", "America/Los_Angeles" },
    { "Mexico Standard Time", "America/Mexico_City" },
    { "Montevideo Standard Time", "America/Montevideo" },
    { "Eastern Standard Time", "America/New_York" },
    { "UTC-02", "America/Noronha" },
    { "US Mountain Standard Time", "America/Phoenix" },
    { "Canada Central Standard Time", "America/Regina" },
    { "Pacific Standard Time (Mexico)", "America/Santa_Isabel" },
    { "Pacific SA Standard Time", "America/Santiago" },
    { "E. South America Standard Time", "America/Sao_Paulo" },
    { "Newfoundland Standard Time", "America/St_Johns" },
    { "Central Asia Standard Time", "Asia/Almaty" },
    { "Jordan Standard Time", "Asia/Amman" },
    { "Arabic Standard Time", "Asia/Baghdad" },
    { "Azerbaijan Standard Time", "Asia/Baku" },
    { "SE Asia Standard Time", "Asia/Bangkok" },
    { "Middle East Standard Time", "Asia/Beirut" },
    { "India Standard Time", "Asia/Calcutta" },
    { "Sri Lanka Standard Time", "Asia/Colombo" },
    { "Syria Standard Time", "Asia/Damascus" },
    { "Bangladesh Standard Time", "Asia/Dhaka" },
    { "Arabian Standard Time", "Asia/Dubai" },
    { "North Asia East Standard Time", "Asia/Irkutsk" },
    { "Israel Standard Time", "Asia/Jerusalem" },
    { "Afghanistan Standard Time", "Asia/Kabul" },
    { "Kamchatka Standard Time", "Asia/Kamchatka" },
    { "Pakistan Standard Time", "Asia/Karachi" },
    { "Nepal Standard Time", "Asia/Katmandu" },
    { "North Asia Standard Time", "Asia/Krasnoyarsk" },
    { "Arab Standard Time", "Asia/Kuwait" },
    { "Magadan Standard Time", "Asia/Magadan" },
    { "N. Central Asia Standard Time", "Asia/Novosibirsk" },
    { "West Asia Standard Time", "Asia/Oral" },
    { "Myanmar Standard Time", "Asia/Rangoon" },
    { "Korea Standard Time", "Asia/Seoul" },
    { "China Standard Time", "Asia/Shanghai" },
    { "Singapore Standard Time", "Asia/Singapore" },
    { "Taipei Standard Time", "Asia/Taipei" },
    { "Georgian Standard Time", "Asia/Tbilisi" },
    { "Iran Standard Time", "Asia/Tehran" },
    { "Tokyo Standard Time", "Asia/Tokyo" },
    { "Ulaanbaatar Standard Time", "Asia/Ulaanbaatar" },
    { "Vladivostok Standard Time", "Asia/Vladivostok" },
    { "Yakutsk Standard Time", "Asia/Yakutsk" },
    { "Ekaterinburg Standard Time", "Asia/Yekaterinburg" },
    { "Armenian Standard Time", "Asia/Yerevan" },
    { "Azores Standard Time", "Atlantic/Azores" },
    { "Cape Verde Standard Time", "Atlantic/Cape_Verde" },
    { "Cen. Australia Standard Time", "Australia/Adelaide" },
    { "E. Australia Standard Time", "Australia/Brisbane" },
    { "AUS Central Standard Time", "Australia/Darwin" },
    { "Tasmania Standard Time", "Australia/Hobart" },
    { "W. Australia Standard Time", "Australia/Perth" },
    { "AUS Eastern Standard Time", "Australia/Sydney" },
    { "UTC", "Etc/GMT" },
    { "UTC-11", "Etc/GMT+11" },
    { "Dateline Standard Time", "Etc/GMT+12" },
    { "UTC+12", "Etc/GMT-12" },
    { "W. Europe Standard Time", "Europe/Amsterdam" },
    { "GTB Standard Time", "Europe/Athens" },
    { "Romance Standard Time", "Europe/Brussels" },
    { "Central Europe Standard Time", "Europe/Budapest" },
    { "FLE Standard Time", "Europe/Helsinki" },
    { "GMT Standard Time", "Europe/London" },
    { "E. Europe Standard Time", "Europe/Minsk" },
    { "Russian Standard Time", "Europe/Moscow" },
    { "Central European Standard Time", "Europe/Sarajevo" },
    { "Mauritius Standard Time", "Indian/Mauritius" },
    { "Samoa Standard Time", "Pacific/Apia" },
    { "New Zealand Standard Time", "Pacific/Auckland" },
    { "Fiji Standard Time", "Pacific/Fiji" },
    { "Central Pacific Standard Time", "Pacific/Guadalcanal" },
    { "West Pacific Standard Time", "Pacific/Guam" },
    { "Hawaiian Standard Time", "Pacific/Honolulu" },
    { "Tonga Standard Time", "Pacific/Tongatapu" }
};

/// <summary>
/// Converts a Windows time zone ID to an Olson time zone ID.
/// </summary>
/// <param name="tzInfo">A Windows time zone ID.</param>
/// <returns>
/// The string corresponding to the Windows time zone ID, 
/// or null if you passed in an invalid Windows time zone ID.
/// </returns>
/// <remarks>
/// See http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html
/// </remarks>
public static string TimeZoneInfoToOlsonTimeZone(TimeZoneInfo tzInfo)
{
    string olsonTimeZoneId = default(string);

    if (windowsOlsonTimes.TryGetValue(tzInfo.StandardName, out olsonTimeZoneId))
        return olsonTimeZoneId;

    return null;
}

以下函数使用它(Appointment是我自己的类,rValue是重复数据):

Appointment appointment = new Appointment();
Hashtable fields = Parser.Fields(rValue);

if (fields.ContainsKey("DTSTART;VALUE=DATE"))
{
    string dtstart = (string)fields["DTSTART;VALUE=DATE"];
    string dtend = (string)fields["DTEND;VALUE=DATE"];
    appointment.StartDate = SplitDateString(dtstart);
    appointment.EndDate = SplitDateString(dtend);
    appointment.AllDay = true;
}
else
{
    string tzid = (string)fields["TZID"];

    if (fields.ContainsKey("DTSTART;TZID=" + tzid))
    {
        string dtstart = (string)fields["DTSTART;TZID=" + tzid];
        string dtend = (string)fields["DTEND;TZID=" + tzid];

        string tzoffset = (string)fields[CalendarHelpers.IsDst(DateTime.Now) ? "TZOFFSETTO" : "TZOFFSETFROM"];
        TimeSpan offset = SplitTimeString(tzoffset);

        appointment.StartDate = DateTime.ParseExact(dtstart, "yyyyMMddTHHmmss", CultureInfo.InvariantCulture).Subtract(offset).ToLocalTime();
        appointment.EndDate = DateTime.ParseExact(dtend, "yyyyMMddTHHmmss", CultureInfo.InvariantCulture).Subtract(offset).ToLocalTime();
    }
    else
    {
        string dtstart = (string)fields["DTSTART"];
        string dtend = (string)fields["DTEND"];

        if (dtstart.EndsWith("Z"))
            appointment.StartDate = DateTime.ParseExact(dtstart, "yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture).ToLocalTime();
        else
            appointment.StartDate = DateTime.ParseExact(dtstart, "yyyyMMddTHHmmss", CultureInfo.InvariantCulture);

        if (dtend.EndsWith("Z"))
            appointment.EndDate = DateTime.ParseExact(dtend, "yyyyMMddTHHmmssZ", CultureInfo.InvariantCulture).ToLocalTime();
        else
            appointment.EndDate = DateTime.ParseExact(dtend, "yyyyMMddTHHmmss", CultureInfo.InvariantCulture);
    }

    appointment.AllDay = false;
}

然后我使用DDay.iCalhttp://sourceforge.net/projects/dday-ical/)来解析RRULE属性:

string rrule = (string)fields["RRULE"];
RecurrencePattern pattern = new RecurrencePattern(rrule);

从那里,您只需要弄清楚如何在应用程序中存储重复数据,并从RecurrencePattern提供的字段进行转换。

请注意,我没有发明一堆上面的代码,但是很久以前我就知道了我不记得这些代码。此外,由于我仍在开发我的应用程序,上面的一些代码可能有错误。