Incorrect datetime conversion from UTC after DataSet.GetXml() - c#

My app pulls an object via a web service call, puts it in a typed dataset and sends the DataSet.GetXml() to a stored procedure for insert/update on the database.
The problem I'm facing is with two properties of the object : StartTime/EndTime. The web service sends these in UTC format. Eg. sample StartTime-> "2012-11-06T05:00:00Z"
The DataSet.GetXml() attempts to convert this UTC value into local time, and my app server is in EST. The resultant value should be reported as "2012-11-06T00:00:00-05:00" but instead it is "2012-11-06T05:00:00-05:00".
The offset value is being added but the time component is not changed.
Is there something incorrect with my understanding here? I'm finding it hard to digest that the GetXml() method could have such a bug, and I haven't found anyone else here complain of a similar problem yet.
Here's a stripped down version of the code:
public void SaveOrder(int intOrderID)
{
OrderDataSet objOrderDS = null;
OrderDataSet.OrdersRow objOrderRow = null;
ExternHandler handler = null;
Order objOrder;
Order objOrder = handler.GetOrder(intOrderID);
objOrderRow = objOrderDS.Orders.NewOrdersRow();
objOrderRow.OrderID = objOrder.OrderID;
objOrderRow.StartTime = objOrder.StartTime;
objOrderRow.EndTime = objOrder.EndTime;
objOrderDS.Orders.AddOrdersRow(objOrderRow);
if (objOrderDS.Orders.Rows.Count > 0)
{
objOrderDS.Namespace = string.Empty;
objMappingObjects.Add(new MappingObject("Table", "Orders"));
objSqlParams.Add(new SqlParameter("#pOrdersXml", objOrderDS.GetXml()));
objOrderDS.Clear();
objOrderDS.Merge(SqlHelper.ExecuteDataset(ConfigConnectionDB.Trim(), CommandType.StoredProcedure, "usp_InsertOrderMetaData", objMappingObjects.ToArray(), objSqlParams.ToArray()));
}
}

OK, I found why the UTC-time was being converted to "incorrect local time". The fields 'Startime'/'EndTime' in the typed dataset are of type 'DateTime'. There is a property associated with DataColumn of DateTime type called 'DateTimeMode' which is set to 'UnspecifiedLocal' by default.
http://msdn.microsoft.com/en-us/library/system.data.datasetdatetime.aspx
Basically, this option adds the offset to the datetime value without converting it. As a test, I changed the 'DateTimeMode' to 'Utc' and retried. The XML received from DataSet.GetXml() was able to convert the value correctly: "2012-11-06T05:00:00Z"
As a solution to my problem, I'm keeping the property to 'UnspecifiedLocal' as it is. Instead, while adding the value to the dataset I convert it to local time.
objOrderRow.EndTime = objOrder.EndTime.ToLocalTime();
(Note that this works for me because my app server and database server are in the same timezone and conversion to UTC is uncomplicated.)

Related

Recurring events lose automatic timezone conversion

I'm setting up a calendar invite email using ical.net. Sending out a non-recurring event seems to work perfectly: I set the start and end date like this
iCalEvent.DtStart = new CalDateTime(DateTime.SpecifyKind(model.EventTime.Value, DateTimeKind.Utc));
iCalEvent.DtEnd = new CalDateTime(DateTime.SpecifyKind(model.EventTime.Value.AddMinutes(model.DurationMins.Value), DateTimeKind.Utc));
when the email arrives, the time zone has been converted to the recipients timezone (The timezone is -7, the eventTime is 4pm and the duration is 3 hours)
However, when I take this same exact code and add this line to it
IRecurrencePattern recurrence = new RecurrencePattern(FrequencyType.Daily, 1)
{
Until = DateTime.SpecifyKind(model.endDate.Value.AddDays(1), DateTimeKind.Utc)
};
iCalEvent.RecurrenceRules = new List<IRecurrencePattern> { recurrence };
Suddenly my timezone is no longer converted when the email is received (The timezone is -7, the eventTime is 4pm and the duration is 3 hours. The endDate is on the 28th)
I need the DateTime to be displayed to the user in their own timezone and I need to display recurring events from the eventTime to the endDate
It may also be useful to note that I do not have a timezone property specified on Calendar as it was causing the sent email to show a "not supported calendar message" in outlook. Before I removed it, it looked like this
iCal.AddTimeZone(new VTimeZone("UTC"));
when I opened ical files that had this time zone specified, they seemed to work correctly for multi day events, but as I need them to appear in outlook with the accept/decline/tentative buttons, it is out of the question to add it back
i've also tried specifying datetimes like this
iCalEvent.DtStart = new CalDateTime(leEvent.EventTime.Value, "UTC");
but nothing changed
EDIT: I now understand that the issue is due to a recurring event needing a timezone as specified here, but I'm not quite sure where the timezone needs to be specified. I went back to adding the vTimeZone back in and validating it through this site, and it appears that the iCal file is missing the standard/daylight section inside of the timezone block
I have also tried specifying the timezone as GMT and specifying the timezone as "\"America/Phoenix\"" so that the tzid came out as TZID:"America/Phoenix" (with quotes in the ical file.
This is my code at the moment that causes the issue.
iCalEvent.DtStart = new CalDateTime(DateTime.SpecifyKind(model.EventTime.Value, DateTimeKind.Utc));
iCalEvent.DtEnd = new CalDateTime(iCalEvent.DtStart.Value.AddMinutes(model.DurationMins.Value));
if (model.EndDate.HasValue)
{
IRecurrencePattern recurrence = new RecurrencePattern(FrequencyType.Daily, 1)
{
Until = DateTime.SpecifyKind(model.MaxDate.Value, DateTimeKind.Utc).ToLocalTime()
};
iCalEvent.RecurrenceRules = new List<IRecurrencePattern> { recurrence };
iCalEvent.DtStart = new CalDateTime(iCalEvent.DtStart.Value.ToLocalTime(), "America/Phoenix");
iCalEvent.DtEnd = new CalDateTime(iCalEvent.DtEnd.Value.ToLocalTime(), "America/Phoenix");
iCal.AddTimeZone(new VTimeZone("America/Phoenix"));
}
I'm not quite sure what needs to happen to correct the standard/daylight ical error from this point.
FINAL EDIT:
after reading through this post, I found that this issue has already been solved as of last november. I checked the version we had in our project and it turned out some genius just copied the dll straight in without setting it up through nuget (and a version from several years ago no less). I grabbed the latest version and this time specifying the timezone caused no issues in outlook. I'm still experimenting with addTimeZone and addLocalTimeZone but I'm definitely on the right track. Thank you to rianjs for this extremely useful library. I don't know how I would possible work with this crazy calendar standard without it.
A recurring event is always relative to the sender's timezone (or rather to the event location), and not to the recipient's timezone, because of daylight saving changes which may happen at different time between the organiser and the various recipients.
So in most cases you want to use a meaningful timezone in the event (i.e. not UTC).
Then Outlook is simply showing that the event is indeed happening according to the given timezone. This is an indication that the event may not always be at the same time of day for the recipient.
Since this took me so long to figure out, I might as well share my solution in case anyone else runs into this problem and finds this.
I defined the DtStart/DtEnd with two datetimes that had kind utc
calendarEvent.DtStart = new CalDateTime(model.EventTime.Value);
calendarEvent.DtEnd = new CalDateTime(model.EventTime.Value.AddMinutes(model.DurationMins.Value));
which worked great for single day events, but with multidays I ended up doing this
if (model.EndDate.HasValue)
{
RecurrencePattern recurrence = new RecurrencePattern(FrequencyType.Daily, 1)
{
Until = model.EndDate.Value //has kind: Utc
};
var timezoneOffsetString = "Etc/GMT";
if (timezoneOffset > 0) //client time zone offset, calculated through js
{
timezoneOffsetString += "-" + timezoneOffset;
}
else if (timezoneOffset < 0)
{
timezoneOffsetString += "+" + (-1 * timezoneOffset);
}
calendar.AddTimeZone(timezoneOffsetString);
calendarEvent.DtStart = calendarEvent.DtStart.ToTimeZone(timezoneOffsetString);
calendarEvent.DtEnd = calendarEvent.DtEnd.ToTimeZone(timezoneOffsetString);
calendarEvent.RecurrenceRules = new List<RecurrencePattern> { recurrence };
}
It's not fullproof as some places may have weird dst problems, but nodatime was treating the "America/Phoenix" tzid as an LMT time, which was giving me a time that was like 28 minutes off... Besides, treating all dates as GMT is closer to the implementation we have in the rest of our app so it worked for my situation
This solution gave me the idea to piece together the Etc/GMT stuff.

Kendo DatePickerFor Error The value '09-16-2016' is not valid for Date:

I am using kendo datePickerFor
Code into model=====
[DataType(DataType.Date)]
[Display(Name = "Date:")]
[DisplayFormat(DataFormatString = "{0:MM-dd-yyyy}",
ApplyFormatInEditMode = true)]
public DateTime TransactionDate { set; get; }
Into view page====
#(Html.Kendo().DatePickerFor(m => m.TransactionDate)
.Format("MM-dd-yyyy")
.ParseFormats(new List<string>()
{
"MM-dd-yyyy"
})
)
Also use javascript====
$(function () {
kendo.culture("en-US");
})
My kendo DatePickerFor is inside a form.
when I submitting the form giving error - "The value '09-16-2016' is not valid for Date:."
My local machine date format is "dd-MM-yyyy".
When I set this format into datepicker,form submitted correctly.
But I want to set specific format which does no depend on local machine format
Please know me how to solved this problem.
Normally, you would want to match the cultures on the client and on the server:
http://docs.telerik.com/kendo-ui/aspnet-mvc/globalization#match-cultures
The server-side culture can be set, depending on the regional information provided in the browser's request.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language
If there is a valid reason not to do this, then you will have to manually take care of submitting the date value in the correct format, expected by the server.
I had similar problem - the best description I found (but not a solution) is here: https://blog.gerardbeckerleg.com/posts/kendo-ui-mvc-grid-datepicker-in-line-and-in-cell-edit-validation-error-the-value-is-not-valid/
My local machine culture date format is dd.MM.yyyy, in my multilanguage app I wanted to force always one date format: yyyy-MM-dd, so I added (to never show local date format)
#(Html.Kendo().DatePickerFor(m => m.TransactionDate)
.Format("yyyy-MM-dd"))
Problem occurred while saving changes only inside kendo grid when I used In-Line edition and only for my local machine culture, which does not allow format with month-first. When I input date in format yyyy-MM-dd, after accepting this change it somehow swapped month and day, and my date 2020-01-05- (january 5th) was saved as 2020-05-01 (may 1st). And when a day was > 12 same error as yours occured (e.g. for date 2020-12-31 - december 31st it couldn't change 31 info a month, and I got error: "The value 31.12.2020 is not valid for Date"
In error messsage a given format was exactly like my local machine culture (dd.MM.yyyy -> 31.12.2020) but error occured so the date was treated as MM.dd.yyyy and in this format 31.12.2020 is not valid indeed.
What was strange I noticed different behaviour when I ran same application from client machine (but same local culture as mine) and when I was debugging in VS on local machine (on a local machine I couldn't reproduce an error, only on client machine)
What I did?
I checked if I load proper kendo culture (I did): kendo.culture("pl-PL");
I changed kendo.culture.pl-PL.min.js date format info yyyy-MM-dd. To not change min.js file I did as an extension js method (notice the first true parameter!):
var customCulture = $.extend(true, kendo.culture(), {
calendars: {
standard: {
patterns: {
d: "yyyy-MM-dd",
g: "yyyy-MM-dd HH:mm",
G: "yyyy-MM-dd HH:mm:ss"
}
}
}
}
);
It forces takes given date formats and pushes (merges) them into currently loaded kendo.culture(), what does the trick. Because I always want to show yyyy-MM-dd format I is what I need.
The idea of solution was taken from here: https://www.telerik.com/forums/calendar-customization-764d6343160b

Converting Dates between Calendars in Xamarin.Android

I have the following snippet of Code for Convert Gregorian Date to Hijri Date.
public static string GregoriantoHijri(DateTime gregorianDate)
{
CultureInfo arCI = new CultureInfo("ar-SA");
var hijriCalendar = new HijriCalendar();
hijriCalendar.HijriAdjustment = App_Code.StoreRetrieveSettingsAssist.getHA();
arCI.DateTimeFormat.Calendar = hijriCalendar; //CODE FAILS HERE
string hijriDate = gregorianDate.ToString("dd-MM-yyyy", arCI);
return hijriDate;
}
This code runs perfectly for my Windows Mobile App which is also posted on Store.
However the same code is giving me issues in Xamarin.Android
The Error:
System.ArgumentOutOfRangeException:
Not a valid calendar for the given culture.
Parameter name: value
I don't understand why codes using same .NET base class have issues on different platforms. Can you suggest a workaround cause this doesn't seem to work.
You might want to consider NodaTime. It is supposedly more robust than the native .NET datetime handling, and is supposed to support Hijri.

SSRS DateTime Parameters DefaultValue Format

I have an asp.net application that allows users to create subscriptions for SSRS reports.
All my reports have #StartDate and #EndDate parameters which have default values of
=Today.AddDays(-14)
and
=Today
respectively.
My c# code takes checks the defaultvalue of the parameters when loading the subscription form, to pre-populate AspxDateEdit controls. This all works fine on my dev environment (NZ).
ItemParameter[] Parameters = _Rs.GetItemParameters(_ThisReportPath, null, true, null, null);
if (Parameters.Any())
{
foreach (ItemParameter Rp in Parameters)
{
if (Rp.ParameterTypeName == "DateTime" && Rp.PromptUser)
{
var MyDtControl = new ASPxDateEdit
{
ID = "dtParam" + MyTable.Rows.Count
};
DateTime MyFormattedDisplayDate = Convert.ToDateTime(Rp.DefaultValues[0], CultureInfo.CurrentCulture.DateTimeFormat);
MyDtControl.Date = MyFormattedDisplayDate.Date;
}
}
}
The initial website will be residing on a server in Australia, with subsequent rollouts to various countries around the world, so I need to keep the format of DateTimes dynamic (Culture specific).
When loading the subscription form for a report on the live system I get the error “String was not recognized as a valid DateTime.” Dumping the values of the Parameter.DefaultValues[0] shows that the default value on the AU server is in US form (MM/dd/yyyy) which is causing the errors. Logging code:
SQLReportsLogic.Log(MyLog, "(Line 599 - LoadParams)Default Param Value:" + Rp.DefaultValues[0] + "/ ServerDateFormatToday:" + DateTime.Now);
Resulting output:
(Line 599 - LoadParams)Default Param Value:3/24/2015 12:00:00 AM/ ServerDateFormatToday:24/03/2015 7:14:47 AM
The format is expected to align with the culture info of the server which would be dd/MM/yyyy.
- The report language is set to User!Language
- The Server System Locale is English(Australia)
- The Server Location is Australia
- The Server Datetime format is set to ShortDate=d/MM/yyyy LongDate=dddd, d MMMM yyyy
- The Server Language is set to English (Australia)
- The Reporting Services Service is running under Local System Account
- WWW is running under Local System Account
- SSRS is running in Native Mode
Where specifically does SSRS get the DateTime Format from when determining the format for =Today()? As I understand my research to date, this should be generating =Today() in the system assigned format of dd/MM/yyyy
I have also tried formatting the DefaultValue of the parameters to
- “yyyy/MM/dd hh:mm:ss” = The DefaultValue expression for the report parameter ‘StartDate’ contains an error: Input string was not in a correct format
- “yyyy/MM/dd hh:mm” = The DefaultValue expression for the report parameter ‘StartDate’ contains an error: Input string was not in a correct format
- “yyyy/MM/dd” = The DefaultValue expression for the report parameter ‘StartDate’ contains an error: Input string was not in a correct format
- DateFormat.ShortDate = The property ‘DefaultValue’ of report parameter ‘StartDate’ doesn’t have the expected type.
- DateFormat.LongDate = The property ‘DefaultValue’ of report parameter ‘StartDate’ doesn’t have the expected type.
- DateFormat.GeneralDate = The property ‘DefaultValue’ of report parameter ‘StartDate’ doesn’t have the expected type.
It would seem that unless I can resolve the way SSRS renders =Today() that my hands are tied. As I understand it I need to find the issue with the SSRS installation using the incorrect Culture? Is it looking it up in the registry somewhere?
I am using VS2012 (11.0.61030.00 Update 4) with SSDTBI Plugin (MSSQL Server Reporting Services Designers Version 11.0.3436.0)
Finally found the right search terms to use and found a solution after two days - to override the SSRS GetWebRequest as described here..
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/f147c641-d5c2-49e8-97f6-b654bec8366d/datetime-format-for-webservice-api-calls?forum=sqlreportingservices#0c223835-dd5c-4471-b736-1d9dad014144
public partial class ReportingService : DevReportService.ReportingService2010
{
/// <summary>
/// Gets or sets the culture that is used when generating the report.
/// </summary>
/// <value>The culture that is used when generating the report.</value>
public CultureInfo Culture { get; set; }
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest request = base.GetWebRequest(uri);
CultureInfo culture = this.Culture ?? CultureInfo.CurrentCulture;
request.Headers.Add(HttpRequestHeader.AcceptLanguage, culture.Name);
return request;
}
}

Datetime error in iis 7 server

I have screen in c# asp.net webapplication, where i add news on particular dates.And can edit those dates also.It workes in my local sytem.But shows datetime error when it was running in iis 7 server(Used sql database).And i knew that the short date and long date format in server was different from local system.So i changed date format in local system same as in iis.But still it is working properly.
Instead of guessing culture settings write code that sets one you need before reading from database/restore after unsing Thread.CurrentCulture property. Simialr to code below (need to also use CurrentUICulture, chose cuture you need and wrap code around setting/restoring into try/finally for real code)
var oldCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
// read from DB
...
Thread.CurrentThread.CurrentCulture = oldCulture;

Categories

Resources