Part of an on premise app I am moving to the cloud, displays TV Scheduling information from a json source. The core data uses an offset in seconds from a start date to get it's start times which is all fine as these are all int UTC format.
The problem arises in the movement to the cloud.
The on premise app was situated in the UK so the locale is UntedKingdom and the TV times were correctly output using
return programmeStart.AddHours(programmeStart.IsDaylightSavingTime() ? 1 : 0);
However, having now moved to the cloud, the functionality for IsDaylightSavingTime, no longer returns true due to data centers being BST Agnostic.
Been racking my brains for a way to try and sort this.
Is there a quick and easy way to set what locale your hosted service runs under in Azure, or is the best solution to create an extension method that reads the boundries of when BST runs from and to, and then return true or false from there for example
public static class DateTimeExtension
{
public static bool IsMyDaylightSavingTime(this DateTime timeToTest)
{
if(timeToTest >= GetConfig("bstStart") && timeToTest <= GetConfig("bstFinish"))
{
return true;
}
return false;
}
}
And the maintaing the config values of bst changing as they move?
Thanks
You can't change the timezone of the Azure servers - there's lots going on that assumes UTC is the current setting.
You should be able to get hold of the UK timezoneinfo by string, e.g.:
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
After you've done that, then you can use the framework method TimeZoneInfo.IsDaylightSavingTime http://msdn.microsoft.com/en-us/library/bb460642.aspx
tzi.IsDaylightSavingTime(DateTime.Now);
Why can't you simply return UTC and let the client translate that per their locale?
Edit: Here is code
var offset = TimeZoneInfo.GetSystemTimeZones()
.Where(z => z.Id == "GMT Standard Time")
.Single()
.GetUtcOffset(DateTime.UtcNow)
Related
I need to analyse one http event value which should not be greater than 30mins. & 95% event should belong to this bucket. If it fails send the alert.
My first concern is to get the right metrics in /actuator/prometheus
Steps I took:
As in every http request event, I am getting one integer value called eventMinute.
Using micrometer MeterRegistry, I tried below code
// MeterRegistry meterRegistry ...
meterRegistry.summary("MINUTES_ANALYSIS", tags);
where tag = EVENT_MINUTE which receives some integer value in each
http event.
But this way, it floods the metrics due to millions of event.
Guide me a way please, i am beginner to this. Thanks!!
The simplest solution (which I would recommend you start with) would be to just create 2 counters:
int theThing = //getTheThing()
if(theThing > 30) {
meterRegistry.counter("my.request.counter.abovethreshold").inc()
}
meterRegistry.counter("my.request.counter.total").inc()
You would increment the counter that matches your threshold and another that tracks all requests (or reuse another meter that does that for you).
Then it is simple to setup a chart or alarm:
my_request_counter_abovethreshold/my_request_counter_total < .95
(I didn't test the code. It might need a tiny bit of tweaking)
You'll be able to do a similar thing with DistributionSummary by setting various SLOs (I'm not familiar with them to be able to offer one), but start with something simple first and if it is sufficient, you won't need the other complexity.
There are certain ways to solve this problem
1 ; here is a function which receives tags, name of metrics and a value
public void createOrUpdateHistogram(String metricName, Map<String, String> stringTags, double numericValue)
{
DistributionSummary.builder(metricName)
.tags(tags)
//can enforce slo if required
.publishPercentileHistogram()
.minimumExpectedValue(1.0D) // can take this based on how you want your distibution
.maximumExpectedValue(30.0D)
.register(this.meterRegistry)
.record(numericValue);
}
then it produce metrics like
delta_bucket{mode="CURRENT",le="30.0",} 11.0
delta_bucket{mode="CURRENT", le="+Inf",} 11.0
so as infinte also hold the less than value, so subtract the le=30 from le=+Inf
Another ways could be
public void createOrUpdateHistogram(String metricName, Map<String, String> stringTags, double numericValue)
{
Timer.builder(metricName)
.tags(tags)
.publishPercentiles(new double[]{0.5D, 0.95D})
.publishPercentileHistogram()
.serviceLevelObjectives(new Duration[]{Duration.ofMinutes(30L)})
.minimumExpectedValue(Duration.ofMinutes(30L))
.maximumExpectedValue(Duration.ofMinutes(30L))
.register(this.meterRegistry)
.record((long)timeDifference, TimeUnit.MINUTES);
}
it will only have two le, the given time and +inf
it can be change based on our requirements also it gives us quantile.
I have an excel document with times listed as "02:30" ... however, when iterating through them using NPOI, the DateCellValue flips to "02:29:59" ... This first happens on 1/1/2019 (which correctly stores as "02:30") but then on 1/2/2019 it flips to "02:29:59" ... Does anyone know how to have it simply get the value of the cell without trying to do any voodoo to it? It's obviously taking into account perhaps a leap second, or something? It is, however, clear as day in Excel as "02:30", and at my breakpoint with:
[Model].DepartureDttm = row.GetCell(j).DateCellValue [1/2/2019 2:29:59 AM]
You're not the only one that have faced this problem. Here's a good answer.
You can use the DateUtil.GetJavaDate coming with NPOI to resolve this issue . You can create this basic extension method:
public static class Extensions
{
public static DateTime DateCellValueRounded(this ICell cell)
{
return DateUtil.GetJavaDate(cell.NumericCellValue, false, TimeZone.CurrentTimeZone, true);
}
}
Then use it like this:
DateTime date = row.GetCell(index).DateCellValueRounded;
GetJavaDate signature (the last parameter set to true does the job):
public static DateTime GetJavaDate(double date, bool use1904windowing, TimeZone tz, bool roundSeconds);
I have a web application where my users are in NYC but admins are spread across the world. The use case is simple. Admins click on a date and add some notes. Users when they log in to the app , click on the same date and sees the note
Problem is timezone. When an Admin from India adds data on January 1 2019 his data is getting added to Dec 31 2018 as the server is converting the incoming IST to EST. This is breaking the application.
I cant handle individual timezone. So I want to ensure that the frontend is always passing the date in EST irrespective of the local timezone
private normalizeDate(d)
{
let noTime = moment(d).format("L");
let m = moment(noTime).tz("America/New_York");
alert("no time :"+noTime);
alert("normalized :"+m.format("L"));
}
I tried this function where i get the date in local timezone (d) and remove all information. Convert into a string and then parse it back to my EST timezone.
Evidently whenever I call . moment().tz() it is converting the timezone again.
Any idea what is the best solution ?
Eventually I used this to resolve the problem
public static NormalizeDate(d, timezone = "America/New_York")
{
var a = moment(d);
var b = a.clone();
return b.tz(timezone, true).startOf("day");
}
Background:
The company I work for has a regular SharePoint list with a custom ContentType (that does not inherit from a calendar list item) that it uses for Events. It then shows these using a calendar view. Seems simple enough.
We have the need to allow the user to choose a timezone for the event (different from their regional setting) that they are adding and to add the information to sharepoint such that it will show the correct time for each user looking at it world wide (based on their regional setting of course).
I added a list to SharePoint that is used to lookup SystemTimeZones (basically a SharePoint List representation of TimeZoneInfo.GetSystemTimeZones())
SPList timeZonesList = thisWeb.Lists.TryGetList("SystemTimeZones");
if(timeZonesList == null)
{
string title = "SystemTimeZones";
string description = "SharePoint List representation of TimeZoneInfo.GetSystemTimeZones() used for lookup.";
Guid newListId = thisWeb.Lists.Add(title, description, SPListTemplateType.GenericList);
timeZonesList = thisWeb.Lists.GetList(newListId, true);
timeZonesList.Fields.Add("SystemTimeZoneId", SPFieldType.Text, true);
timeZonesList.Fields.Add("SystemTimeZoneName", SPFieldType.Text, true);
SPView defaultTimeZonesView = timeZonesList.DefaultView;
defaultTimeZonesView.ViewFields.Add("SystemTimeZoneId");
defaultTimeZonesView.ViewFields.Add("SystemTimeZoneName");
defaultTimeZonesView.Update();
foreach (TimeZoneInfo timeZone in TimeZoneInfo.GetSystemTimeZones())
{
SPListItem temp = timeZonesList.AddItem();
temp["SystemTimeZoneId"] = timeZone.Id;
temp["SystemTimeZoneName"] = timeZone.DisplayName;
temp.Update();
}
}
I'm using this list for the lookup item for EventTimeZone in my custom add and edit forms for this list. The forms are direct copies of what SharePoint Designer would create (in that they are using the SharePoint:FormField's) they are just in Visual Studio bc I needed code-behind. I wanted to allow the users to see the events in their Regional TimeZone however when they edit them I wanted to show them in the TimeZone they were entered. (IE my regional timezone is Central so when I look at a Mountain meeting it will show me 10-11am but when I edit that same meeting it will say it is 9-10am). So on page load of edit I adjust the times:
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);
}
All day events were strange but I was able to make it work by just writing test cases and see what happened (as you can see from my comments).
Then I tie into the list event receivers ItemAdded and ItemUpdated to "fix" the times since SharePoint is going to save them based on the user's regional setting and not the timezone the user chose. (Of course I'm slightly new to SharePoint -- not c# -- so I may have very much over complicated this, but I have been able to fine little documentation online). In the end I end up setting:
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;
}
It still gets reset on Update(). So when you view the recurring item in a Calendar View the item spans the entire week instead of showing once a day.
I have all but pulled my hair out trying to figure this out. Any guidance would be wonderful. I understand Duration is a calculated field but I can't understand why calling listItem.Update() would ignore the fact that it is indeed properly marked as a recurring event and not calculate the Duration correctly. This honestly seems like a bug with SP 2010.
Thanks in advance!
**
EDIT: Additional info after comments below...
**
This SharePoint env has a server in pacific time and users across all US TimeZones, London, Tokyo, Abu Dabi, etc. Users in one timezone need to be able to create events in other timezones. Since nothing in the user's profile (for us anyway) will tell us what timezone they would like to see everything in, we added code to our master page to look at the local machine's timezone and always set their regional setting accordingly.
Example: I am in Nashville and I want to create an event that will happen in LA:
The data in ItemAdded shows that StartDate is what I entered 9am. So I'm creating a date that has PST at the end of it:
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);
Then to "trick" SharePoint I'm converting that PST time into the users regional time (so the user doesn't have to know anything about their regional setting nor do they have to think). So 9am PST is 7am CST (bc that's what SharePoint expects the time to be in since that's my regional setting). Here's the converstion from the correct time+timezone to the user regional timezone:
addedItem["StartDate"] = regionalTimeZone.UTCToLocalTime(correctedEventStart.ToUniversalTime());
addedItem["EndDate"] = regionalTimeZone.UTCToLocalTime(correctedEventEnd.ToUniversalTime());
I don't know if this makes sense to anyone outside of my world. But SharePoint obviously expects the times to be in the user's regional (or the web's) timezone. That's obvious my from unit testing. If there is an OOB way for me to allow a user in Central Time to create a meeting from 9-10am Pacific Time in a custom list I would LOVE to be able to use that. But I haven't been able to find anything.
Again, all of this works great... until you come to Recurring Events. And actually it works for recurring events until you try to view said event in a Calendar View. Then it looks like this:
Notice that "Recurring 8" is recurring the way it's supposed to, daily for 2 instances. However, the "span" or "duration" of the recurrence is 2 days rather than 1 hour. Where as "Recurring 15" shows correctly. The only difference in field values between the two when output to debug is the "Duration" field. Recurring 8 had it's start and end date's updated in ItemAdded and Recurring 15 went through ItemAdded but the ListItem.Update() was commented out. Per documentation SharePoint is supposed to calculate Duration differently for recurring items than it does for single items. The fact that the start and end dates are changed using the object model should not negate that.
Ok, so the way I ended up handling this is as follows. I decided to back out of the list event receiver because it really does appear to be a SharePoint bug in the recalculation of Duration for recurring events now working correctly. I opted to tie into the save event on the form and changing the values before they are even sent. This seems to work so far in all scenarios. All of my math is the same as before. So in my New2.aspx (new item form for this list)
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();
}
}
This updates the times as my previous approach does but it will also calculate the duration correctly.
SharePoint handles displaying the correct time based on the user's regional settings (or web if the user hasn't set it) and displaying the correct times in calendar views. I did have to change the Edit form to have the correct values on edit:
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);
}
}
}
The Edit form has the same OnInit and SaveHandler as New.
I think you are running afoul of the shennagins that SharePoint uses for reccuring events. Essentially the events are stored in a single list item and expanded at query time. This makes the storage of events quite counter intuitive to how you expect.
From that post it looks like the EventDate and EndDate fields are used differently depending on the recurrence or not.
Also be aware the SharePoint stores dates in UTC 'under the hood' and converts back to the users (or websites) timezone on display. You may be able to use this knowledge to optimise some of the date logic.
More information
http://fatalfrenchy.wordpress.com/2010/07/16/sharepoint-recurrence-data-schema/
Share point 2010 ItemAdding insert Recurrence data on calendar
http://blog.tylerholmes.com/2012/02/how-sharepoint-deals-with-time-and-time.html
Here is the code I used to create an occuring event in another timezone (note: I did not explicitly set the duration)
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();
}
So I convert from users "local" to UTC and then back to the web local.
The UID is necessary or there is an error when you click on the event.
If you want a recurrence of 13 say... the code is:
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);
Whereas no end date is :
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);
It might be quite old, but my answer may help someone.
You just have to explicitly put EventType = 1 in update as well.
SPListItem.GetFormattedValue seems to have a strange behavior for DateTime fields.
It retrieves the DateTime value through SPListItem's indexer which according to this MSDN article returns local time.
Here's a snippet from Reflector
public string GetFormattedValue(string fieldName)
{
SPField field = this.Fields.GetField(fieldName);
if (field != null)
{
return field.GetFieldValueAsHtml(this[fieldName]);
}
return null;
}
So it uses SPListItem's indexer to retrieve the value and than SPFields.GetFieldValueAsHtml to format the value. GetFieldValueAsHtml seems to assume the date is in UTC and convert it to local time no matter what kind it is. (Reflector shows that it uses GetFieldValueAsText which uses value.ToString() but for some reason it assumes the time to be UTC.)
The end result is that the string representation on a time field obtained trough listItem.GetFormattedValue() (at least in my case) is incorrect, being local time + (local time - UTC).
Have anybody encountered the same issue with SPListItem.GetFormattedValue() and what was your workaround?
Converting the date back to universal time before calling GetFieldValueAsHtml works just fine.
DateTime localTime = (DateTime)item["DueDate"];
// this is local time but if you do localDateTime.Kind it returns Unspecified
// treats the date as universal time..
// let's give it the universal time :)
DateTime universalTime = SPContext.Current.Web
.RegionalSettings.TimeZone.LocalTimeToUTC(localTime);
string correctFormattedValue =
item.Fields["DueDate"].GetFieldValueAsHtml(universalTime);
I have had a recognised bug with the date conversion from UTC in SharePoint. It was fixed in SP1.