SharePoint中的重复事件-不正确;“持续时间”;
背景: 我工作的公司有一个常规的SharePoint列表,该列表具有用于事件的自定义ContentType(不从日历列表项继承)。然后使用日历视图显示这些内容。看起来很简单。 我们需要允许用户为他们正在添加的事件选择一个时区(不同于他们的区域设置),并将信息添加到sharepoint中,以便在全球范围内显示每个用户观看事件的正确时间(当然基于他们的区域设置)。 我向SharePoint添加了一个用于查找系统时区的列表(基本上是TimeZoneInfo.GetSystemTimeZones()的SharePoint列表表示形式) 我将此列表用于此列表的自定义添加和编辑表单中EventTimeZone的查找项。这些表单是SharePoint Designer将创建的内容的直接副本(因为它们使用的是SharePoint:FormField),它们位于Visual Studio bc中,我需要代码隐藏。我想让用户在他们的区域时区中查看事件,但是当他们编辑事件时,我想在输入的时区中显示它们。(即我所在的地区时区是中心时区,因此当我观看山区会议时,它会显示上午10-11点,但当我编辑同一会议时,它会显示上午9-10点)。因此,在编辑页面加载时,我会调整时间:SharePoint中的重复事件-不正确;“持续时间”;,sharepoint,sharepoint-2010,calendar,Sharepoint,Sharepoint 2010,Calendar,背景: 我工作的公司有一个常规的SharePoint列表,该列表具有用于事件的自定义ContentType(不从日历列表项继承)。然后使用日历视图显示这些内容。看起来很简单。 我们需要允许用户为他们正在添加的事件选择一个时区(不同于他们的区域设置),并将信息添加到sharepoint中,以便在全球范围内显示每个用户观看事件的正确时间(当然基于他们的区域设置)。 我向SharePoint添加了一个用于查找系统时区的列表(基本上是TimeZoneInfo.GetSystemTimeZones()的S
SPListItem thisEvent = eventsList.GetItemById(savebutton1.ItemId);
if (thisEvent != null)
{
bool isAllDayEvent = false;
if (thisEvent["fAllDayEvent"] != null)
{
isAllDayEvent = (bool)thisEvent["fAllDayEvent"];
}
if (!isAllDayEvent)
{
SPFieldLookupValue lookupValue = new SPFieldLookupValue(thisEvent["Event Time Zone"].ToString());
TimeZoneInfo eventTimeZone = GetEventTimeZoneByListItemId(lookupValue.LookupId, rootWeb);
SPTimeZone regionalTimeZone = GetRegionalTimeZone(rootWeb);
DateTime regionalStartDateTime = Convert.ToDateTime(thisEvent["StartDate"]);
DateTime originalStartDateTime = TimeZoneInfo.ConvertTimeFromUtc(regionalTimeZone.LocalTimeToUTC(regionalStartDateTime), eventTimeZone);
ff3.ListItemFieldValue = originalStartDateTime;
DateTime regionalEndDateTime = Convert.ToDateTime(thisEvent["EndDate"]);
DateTime originalEndDateTime = TimeZoneInfo.ConvertTimeFromUtc(regionalTimeZone.LocalTimeToUTC(regionalEndDateTime), eventTimeZone);
ff4.ListItemFieldValue = originalEndDateTime;
}
else
{
// for some reason with all day events, sharepoint saves them
// as the previous day 6pm. but when they show up to any user
// they will show as 12am to 1159pm and show up correctly on the calendar
// HOWEVER, when it comes to edit, the start date isn't corrected on the
// form, so continuing to save without fixing it will continue to decrease
// the start date/time by one day
DateTime regionalStartDateTime = Convert.ToDateTime(thisEvent["StartDate"]);
ff3.ListItemFieldValue = regionalStartDateTime.AddDays(1);
}
整天发生的事情都很奇怪,但我能够通过编写测试用例并查看发生了什么(正如您从我的评论中看到的)
然后,我将事件接收者ItemAdded和ItemUpdate绑定到列表中,以“修复”时间,因为SharePoint将根据用户的区域设置而不是用户选择的时区来保存它们。(当然,我对SharePoint有点陌生——不是c#——所以我可能把这件事复杂化了很多,但我能够在网上处理一些文档)。最后,我设置了:
addedItem["StartDate"] = regionalTimeZone.UTCToLocalTime(correctedEventStart.ToUniversalTime());
addedItem["EndDate"] = regionalTimeZone.UTCToLocalTime(correctedEventEnd.ToUniversalTime()); TADA!! It saves and display perfectly! I was so excited! Until... I tried to save a recurring event. All of my recurring events save wonderfully, it's not the recurring part that's messed up. For some reason, after I change the StartDate and EndDate on a recurring event and call addedItem.Update() it is recalculating the "Duration" as if it is a single even instead of a recurring event. Example: I have an event that happens for a week daily from 9-10. When I first enter ItemAdded my Duration is 3600 (1 hour) as it should be bc Duration is treated differently for recurring events. However after I adjust the times and call Update() the duration spans the entire week :( If I manually set the Duration:
if (isRecurrence)
{
addedItem["Duration"] = (correctedEventEnd.TimeOfDay - correctedEventStart.TimeOfDay).TotalSeconds;
}
它仍然会在更新()时重置。因此,当您在日历视图中查看定期项目时,该项目将跨越整个星期,而不是每天显示一次
为了弄明白这一点,我几乎把头发拔了出来。任何指导都会很好。我知道Duration是一个计算字段,但我不明白为什么调用listItem.Update()会忽略这样一个事实,即它确实被正确地标记为重复事件,并且无法正确计算Duration。老实说,这似乎是SP 2010的一个bug
提前谢谢
**
编辑:以下评论后的其他信息。。。
**
此SharePoint env在太平洋时间有一台服务器,用户跨越所有美国时区、伦敦、东京、阿布达比等。一个时区的用户需要能够在其他时区创建事件。由于用户配置文件中没有任何内容(无论如何,对我们来说)会告诉我们他们希望在哪个时区查看所有内容,因此我们在母版页中添加了代码以查看本地机器的时区,并始终相应地设置其区域设置
示例:我在纳什维尔,我想创建一个将在洛杉矶发生的事件:
ItemAdded中的数据显示StartDate是我在上午9点输入的。因此,我正在创建一个日期,该日期末尾有PST:
DateTime correctedEventStart = DateTime.Parse(addedItem["StartDate"] + " " + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Hours + ":" + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Minutes);
DateTime correctedEventEnd = DateTime.Parse(addedItem["EndDate"] + " " + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Hours + ":" + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Minutes);
然后,为了“欺骗”SharePoint,我将PST时间转换为用户的区域时间(因此用户不必知道任何有关其区域设置的信息,也不必思考)。所以太平洋标准时间上午9点是中央标准时间上午7点(卑诗省),这是SharePoint预计的时间,因为这是我的区域设置。下面是从正确的时间+时区到用户区域时区的对话:
addedItem["StartDate"] = regionalTimeZone.UTCToLocalTime(correctedEventStart.ToUniversalTime());
addedItem["EndDate"] = regionalTimeZone.UTCToLocalTime(correctedEventEnd.ToUniversalTime());
我不知道这对我以外的人来说是否有意义。但SharePoint显然希望时间在用户的区域(或web)时区内。从单元测试中可以明显看出这一点。如果我有一种OOB方式,允许中央时间的用户在太平洋时间上午9点到10点在自定义列表中创建会议,我希望能够使用它。但我什么也没找到
再一次,所有这些都非常有效。。。直到你遇到重复发生的事情。实际上,它适用于重复发生的事件,直到您尝试在日历视图中查看所述事件。然后看起来是这样的:
请注意,“重复8”按预期方式重复,每天重复2次。然而,复发的“跨度”或“持续时间”是2天而不是1小时。其中“重复15”正确显示。输出到调试时,这两个字段值之间的唯一区别是“持续时间”字段。定期8在ItemAdded中更新了其开始和结束日期,定期15在ItemAdded中进行了更新,但ListItem.Update()被注释掉。根据文档,SharePoint应该以与单个项目不同的方式计算重复项目的持续时间。使用对象模型更改开始和结束日期的事实不应否定这一点。我认为您与SharePoint用于记录事件的shennagins相冲突。基本上,事件存储在一个数据库中。这使得事件的存储方式与您所期望的完全相反 从那篇文章来看,EventDate和EndDate字段的使用似乎有所不同,这取决于是否重复 “在引擎盖下”,并转换回显示的用户(或网站)时区。您可以利用这些知识优化某些日期逻辑 更多信息 下面是我用来在另一个时区创建发生事件的代码(注意:我没有明确设置持续时间)
public void AddRecurringItemGTM8Perth(SPList列表)
{
string recData=“su2013-02-20T01:00:00Z”;
SPListItem newitem=list.Items.Add();
newitem[“Title”]=“Perth”+DateTime.Now.ToString();
newitem[“RecurrenceData”]=recData;
newitem[“EventType”]=1;
DateTime correctedEventStart=新日期时间(2013,2,3,12,0,0);
//注意dat
addedItem["StartDate"] = regionalTimeZone.UTCToLocalTime(correctedEventStart.ToUniversalTime());
addedItem["EndDate"] = regionalTimeZone.UTCToLocalTime(correctedEventEnd.ToUniversalTime());
public void AddRecurringItemGTM8Perth(SPList list)
{
string recData = "<recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><daily dayFrequency=\"1\" /></repeat><windowEnd>2013-02-20T01:00:00Z</windowEnd></rule></recurrence>";
SPListItem newitem = list.Items.Add();
newitem["Title"] = "Perth " + DateTime.Now.ToString();
newitem["RecurrenceData"] = recData;
newitem["EventType"] = 1;
DateTime correctedEventStart = new DateTime(2013, 2, 3, 12, 0, 0);
//note that date is end of event and time is event end to calculate duration
DateTime correctedEventEnd = new DateTime(2013, 2, 20, 13, 0, 0);
SPTimeZone spTz = SPRegionalSettings.GlobalTimeZones[74]; //perth
correctedEventStart = spTz.LocalTimeToUTC(correctedEventStart);
correctedEventEnd = spTz.LocalTimeToUTC(correctedEventEnd);
correctedEventStart = list.ParentWeb.RegionalSettings.TimeZone.UTCToLocalTime(correctedEventStart);
correctedEventEnd = list.ParentWeb.RegionalSettings.TimeZone.UTCToLocalTime(correctedEventEnd);
newitem["Start Time"] = correctedEventStart;
newitem["End Time"] = correctedEventEnd;
newitem["Recurrence"] = true;
newitem["fAllDayEvent"] = false;
newitem["WorkspaceLink"] = false;
newitem["UID"] = Guid.NewGuid();
newitem.Update();
list.Update();
}
string recData = "<recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><daily dayFrequency=\"1\" /></repeat><repeatInstances>13</repeatInstances></rule></recurrence>";
DateTime correctedEventEnd = new DateTime(2013, 2, 3, 13, 0, 0).AddDays(13);
string recData = "<recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><daily dayFrequency=\"1\" /></repeat><repeatForever>FALSE</repeatForever></rule></recurrence>";
DateTime correctedEventEnd = new DateTime(2013, 2, 3, 13, 0, 0).AddDays(998);
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if ((SPContext.Current.FormContext.FormMode == SPControlMode.New) || (SPContext.Current.FormContext.FormMode == SPControlMode.Edit))
{
SPContext.Current.FormContext.OnSaveHandler += new EventHandler(SaveHandler);
}
}
protected void SaveHandler(object sender, EventArgs e)
{
Page.Validate();
if (Page.IsValid)
{
// fix times
SPFieldLookupValue lookupValue = new SPFieldLookupValue(ff5.Value.ToString());
TimeZoneInfo eventTimeZone = GetEventTimeZoneByListItemId(lookupValue.LookupId, SPContext.Current.Web);
SPTimeZone regionalTimeZone = GetRegionalTimeZone(SPContext.Current.Web);
bool isAllDayEvent = Convert.ToBoolean(ff6.Value);
bool isRecurrence = Convert.ToBoolean(ff11.Value);
DateTime correctedEventStart = DateTime.MinValue;
DateTime correctedEventEnd = DateTime.MinValue;
if (!isAllDayEvent && eventTimeZone != null && regionalTimeZone != null)
{
correctedEventStart = DateTime.Parse(ff3.Value.ToString() + " " + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Hours + ":" + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Minutes);
correctedEventEnd = DateTime.Parse(ff4.Value.ToString() + " " + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Hours + ":" + eventTimeZone.GetUtcOffset(DateTime.UtcNow).Minutes);
ff3.ItemFieldValue = regionalTimeZone.UTCToLocalTime(correctedEventStart.ToUniversalTime());
ff4.ItemFieldValue = regionalTimeZone.UTCToLocalTime(correctedEventEnd.ToUniversalTime());
}
SPContext.Current.ListItem.Update();
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
try
{
using (SPWeb rootWeb = SPContext.Current.Site.RootWeb)
{
SPList eventsList = rootWeb.Lists.TryGetList("Events");
if (eventsList != null)
{
SPListItem thisEvent = eventsList.GetItemById(savebutton1.ItemId);
if (thisEvent != null)
{
bool isAllDayEvent = false;
if (thisEvent["fAllDayEvent"] != null)
{
isAllDayEvent = (bool)thisEvent["fAllDayEvent"];
}
if (!isAllDayEvent)
{
SPFieldLookupValue lookupValue = new SPFieldLookupValue(thisEvent["Event Time Zone"].ToString());
TimeZoneInfo eventTimeZone = GetEventTimeZoneByListItemId(lookupValue.LookupId, rootWeb);
SPTimeZone regionalTimeZone = GetRegionalTimeZone(rootWeb);
DateTime regionalStartDateTime = Convert.ToDateTime(thisEvent["StartDate"]);
DateTime originalStartDateTime = TimeZoneInfo.ConvertTimeFromUtc(regionalTimeZone.LocalTimeToUTC(regionalStartDateTime), eventTimeZone);
ff3.ListItemFieldValue = originalStartDateTime;
DateTime regionalEndDateTime = Convert.ToDateTime(thisEvent["EndDate"]);
DateTime originalEndDateTime = TimeZoneInfo.ConvertTimeFromUtc(regionalTimeZone.LocalTimeToUTC(regionalEndDateTime), eventTimeZone);
ff4.ListItemFieldValue = originalEndDateTime;
}
else
{
// for some reason with all day events, sharepoint saves them
// as the previous day 6pm. but when they show up to any user
// they will show as 12am to 1159pm and show up correctly on the calendar
// HOWEVER, when it comes to edit, the start date isn't corrected on the
// form, so continuing to save without fixing it will continue to decrease
// the start date/time by one day
DateTime regionalStartDateTime = Convert.ToDateTime(thisEvent["StartDate"]);
ff3.ListItemFieldValue = regionalStartDateTime.AddDays(1);
}
}
}
}
}
catch (Exception ex)
{
DebugLogger.WriteLine(ex);
}
}
}