Xamarin C# DateTime.ConvertTime() wrong working - datetime

I am writing Xamarin.iOS app using C#.
I am trying to convert EST timezone time to local timezone time using following code, but it is never converted.
TimeZoneInfo eastZone = TimeZoneInfo.FindSystemTimeZoneById ("EST");
DateTime convertedDate = TimeZoneInfo.ConvertTime (estDate, eastZone, TimeZoneInfo.Local);
convertedDate is always same as estDate.
Of course, I am not in EST timezone.
I checked ConvertTime() definition, and found it assumes first parameter is local timezone.
public static DateTime ConvertTime (DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone)
{
if (sourceTimeZone == null) {
throw new ArgumentNullException ("sourceTimeZone");
}
if (destinationTimeZone == null) {
throw new ArgumentNullException ("destinationTimeZone");
}
if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone != TimeZoneInfo.Local) {
throw new ArgumentException ("Kind property of dateTime is Local but the sourceTimeZone does not equal TimeZoneInfo.Local");
}
if (dateTime.Kind == DateTimeKind.Utc && sourceTimeZone != TimeZoneInfo.Utc) {
throw new ArgumentException ("Kind property of dateTime is Utc but the sourceTimeZone does not equal TimeZoneInfo.Utc");
}
if (sourceTimeZone.IsInvalidTime (dateTime)) {
throw new ArgumentException ("dateTime parameter is an invalid time");
}
if (dateTime.Kind == DateTimeKind.Local && sourceTimeZone == TimeZoneInfo.Local && destinationTimeZone == TimeZoneInfo.Local) {
return dateTime;
}
DateTime dateTime2 = TimeZoneInfo.ConvertTimeToUtc (dateTime);
if (destinationTimeZone != TimeZoneInfo.Utc) {
dateTime2 = TimeZoneInfo.ConvertTimeFromUtc (dateTime2, destinationTimeZone);
if (dateTime.Kind == DateTimeKind.Unspecified) {
return DateTime.SpecifyKind (dateTime2, DateTimeKind.Unspecified);
}
}
return dateTime2;
}
.Net System.dll has wrong code?

I am also seeing problems with TimeZoneInfo.ConvertTime except on Android.
I filed bug 25942 for this on Xamarin's site: https://bugzilla.xamarin.com/show_bug.cgi?id=25942

Related

Removing deprecation warning from momentjs

I'm using momentjs to work with dates in my project for when a user enters a date in M/D/YYYY format to revert to MM/DD/YYYY format (e.g. 2/5/2017 to 02/05/2017). I am also converting any invalid dates or dates greater than today to be reset back to today's date.
element.on("blur", function() {
var currentDate = moment().format('MM/DD/YYYY');
var formattedInput;
if (ctrl.$modelValue !== undefined && ctrl.$modelValue !== "") {
if(moment(ctrl.$modelValue, "MM/DD/YYYY", true).isValid()) {
formattedInput = moment(ctrl.$modelValue);
formattedInput.format('MM/DD/YYYY');
if (formattedInput.isAfter(currentDate)) {
ctrl.$setViewValue(currentDate);
ctrl.$render();
}
} else if (moment(ctrl.$modelValue, "M/D/YYYY", true).isValid()) {
formattedInput = moment(ctrl.$modelValue);
formattedInput.format('MM/DD/YYYY');
if (formattedInput.isAfter(currentDate)) {
ctrl.$setViewValue(currentDate);
ctrl.$render();
} else {
ctrl.$setViewValue(formattedInput.format('MM/DD/YYYY'));
ctrl.$render();
}
} else {
ctrl.$setViewValue(currentDate);
ctrl.$render();
}
}
});
As far as I can tell, this is all working fine with the code I have above. But regardless of working functionality, I am receiving the deprecation warning for non-ISO dates. My thoughts are the use of MM/DD/YYYY format, however this is unchangeable due to business requirements. Is there a way to remedy this issue in a non-cumbersome way?
The problem is with formattedInput = moment(ctrl.$modelValue) here you are using moment parsing without format with non-ISO dates. To remove the Deprecation warning, just use moment(ctrl.$modelValue, "MM/DD/YYYY") and moment(ctrl.$modelValue, "M/D/YYYY") as you have done in the if condition.
Your complete code will be the following:
element.on("blur", function() {
var currentDate = moment();
var formattedInput;
if (ctrl.$modelValue !== undefined && ctrl.$modelValue !== "") {
if(moment(ctrl.$modelValue, "MM/DD/YYYY", true).isValid()) {
formattedInput = moment(ctrl.$modelValue, "MM/DD/YYYY", true);
// This line returns a string, but does not assign to value, so it's superfluous
//formattedInput.format('MM/DD/YYYY');
if (formattedInput.isAfter(currentDate)) {
ctrl.$setViewValue(currentDate.format('MM/DD/YYYY'));
ctrl.$render();
}
} else if (moment(ctrl.$modelValue, "M/D/YYYY", true).isValid()) {
formattedInput = moment(ctrl.$modelValue, "M/D/YYYY", true);
// see previous comment
//formattedInput.format('MM/DD/YYYY');
if (formattedInput.isAfter(currentDate)) {
ctrl.$setViewValue(currentDate.format('MM/DD/YYYY'));
ctrl.$render();
} else {
ctrl.$setViewValue(formattedInput.format('MM/DD/YYYY'));
ctrl.$render();
}
} else {
ctrl.$setViewValue(currentDate.format('MM/DD/YYYY'));
ctrl.$render();
}
}
});
Be sure to fully understand the difference between moment parsing (build a moment object from a string) and moment format (display a string representation of a moment object).

Check Cookies AND Session in Same IF Statement

I have a function that checks for Session and Cookies and redirects user based on those.
private void CheckRecruiterLogin()
{
List<string> list = new List<string>();
if (Session["Candidate"] != null ||
Request.Cookies["Candidate"] != null)
{
list = (List<string>)Session["Candidate"];
string status = list[1].ToString();
if (status.Equals("applicant") ||
Request.Cookies["Candidate"]["Status"].Equals("applicant"))
{
Response.Redirect("ApplicantHome.aspx");
}
if (status.Equals("preboarding") ||
Request.Cookies["Candidate"]["Status"].Equals("preboarding"))
{
Response.Redirect("PreboardingHome.aspx");
}
else if (status.Equals("hiring") ||
Request.Cookies["Candidate"]["Status"].Equals("hiring"))
{
Response.Redirect("HiringHome.aspx");
}
}
else if (Session["HR"] != null || Request.Cookies["HR"] != null)
{
list = (List<string>)Session["HR"];
string type = list[1].ToString();
if (type.Equals("preboarder") ||
Request.Cookies["HR"]["Type"].Equals("preboarder"))
{
Response.Redirect("PreboarderList.aspx");
}
else if (type.Equals("datamanager") ||
Request.Cookies["HR"]["Type"].Equals("datamanager"))
{
Response.Redirect("HiringList.aspx");
}
else if (type.Equals("admin") ||
Request.Cookies["HR"]["Type"].Equals("admin"))
{
Response.Redirect("AdminHome.aspx");
}
}
else if (Session["HR"] == null &&
Request.Cookies["HR"] == null)
{
Response.Redirect("index.aspx");
}
}
But the application throws a runtime exception saying Object reference not set to an instance of an object. I believe this is because there are no cookies present.
My question is: Should I separate the checking of sessions and cookies, or can I do it in one statement?
Thanks!
Your code requires both the cookie, and the session.
If this is intended, you want to change the condition to use && instead of ||.
However, it's more likely you intend the code to use session if available, and cookies if session isn't there. This is quite simply done by storing the value in a variable, and using that later:
if (Session["Candidate"] != null || Request.Cookies["Candidate"] != null)
{
var list = Session["Candidate"] as List<string>;
var status = list == null ? Request.Cookies["Candidate"]["Status"] : list[1];
if (status == "applicant")
{
...
}
...
}
That said, using cookies for security checks like this is a bad idea - they are user visible and user editable.
Also, there's no point in using Equals - just use ==. This isn't Java, .NET actually compares the value, not the reference. Although it's probably a better idea to actually do the comparison using invariant culture, case insensitive equality. There's also no point in creating new List<string> - the value is never used. Just declare the variable at the point where you already have something to fill it with.
You are directly checking that if Request has a cookie named "HR" which will throw exception if there is no cookie with this name. So you first need to check if CookieCollection have any cookie with name "HR". Here is method which checks if CookieCollection have a cookie with a given name.
if(Request.Cookies.Get("cookieNmae") !=null)
So change your if statement like this
if (Session["HR"] != null || Request.Cookies.Get("HR") !=null)

Check Date is tomorrow in C#.net

I write some code to check that now date is tomorrow :
re_dat = SDKClass.Selct_Date_now(); // return today date from database.
DateTime date_now = DateTime.Parse(re_dat).Date;
if (date_now == DateTime.Now.AddDays(1).Date)
{
response.write("tomorrow");
}
but condition doesn't fire.
thanks a lot.
If your question is about difference with some dynamic input date and today date as reference date, then you can use dates difference like this:
var dateDiff = (DateTime.Today - inputDate.Date).TotalDays;
Here is my simple version of date formatting:
public static string GetDateString(DateTime inputDate)
{
var dateDiff = (DateTime.Today - inputDate.Date).TotalDays;
if (dateDiff == 0)
{
return "TODAY";
}
else if(dateDiff == 1)
{
return "YESTERDAY";
}
else if(dateDiff == -1)
{
return "TOMORROW";
}
else
{
return inputDate.ToShortDateString();
}
}
you shouldn't retrive the today date from database.
i think best solutin for this:
if (DateTime.Today == DateTime.Today.AddDays(1))
{
Response.Write("Tomorrow");
}
else { //Write whatever you want }

Correctly convert DateTime property with Dapper on SQLite

I'm using Dapper to insert and get objects to/from SQLite: one object have a property of type DateTime (and DateTimeOffset) that I have to persist and retrieve with milliseconds precision. I can't find a way to correctly retrieve the value because Dapper fail with:
System.FormatException : String was not recognized as a valid DateTime.
in System.DateTimeParse.ParseExactMultiple(String s, String[] formats, DateTimeFormatInfo dtfi, DateTimeStyles style)
in System.DateTime.ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style)
in System.Data.SQLite.SQLiteConvert.ToDateTime(String dateText, SQLiteDateFormats format, DateTimeKind kind, String formatString)
in System.Data.SQLite.SQLite3.GetDateTime(SQLiteStatement stmt, Int32 index)
in System.Data.SQLite.SQLite3.GetValue(SQLiteStatement stmt, SQLiteConnectionFlags flags, Int32 index, SQLiteType typ)
in System.Data.SQLite.SQLiteDataReader.GetValue(Int32 i)
in System.Data.SQLite.SQLiteDataReader.GetValues(Object[] values)
in Dapper.SqlMapper.<>c__DisplayClass5d.<GetDapperRowDeserializer>b__5c(IDataReader r) in SqlMapper.cs: line 2587
in Dapper.SqlMapper.<QueryImpl>d__11`1.MoveNext() in SqlMapper.cs: line 1572
in System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
in System.Linq.Enumerable.ToList(IEnumerable`1 source)
in Dapper.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in SqlMapper.cs: line 1443
in Dapper.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in SqlMapper.cs: line 1382
What do I have to try? Column is of type DATETIME.
Do I have to create a custom TypeHandler and convert DateTime to and from a SQLite string in format "o"?
Dapper version 1.38
I know it's old, but I have found the solution.
After a lot of digging and analyzing Dapper code I came up with this (notice that this is 2019 year):
First you will have to create date time handler:
public class DateTimeHandler : SqlMapper.TypeHandler<DateTimeOffset>
{
private readonly TimeZoneInfo databaseTimeZone = TimeZoneInfo.Local;
public static readonly DateTimeHandler Default = new DateTimeHandler();
public DateTimeHandler()
{
}
public override DateTimeOffset Parse(object value)
{
DateTime storedDateTime;
if (value == null)
storedDateTime = DateTime.MinValue;
else
storedDateTime = (DateTime)value;
if (storedDateTime.ToUniversalTime() <= DateTimeOffset.MinValue.UtcDateTime)
return DateTimeOffset.MinValue;
else
return new DateTimeOffset(storedDateTime, databaseTimeZone.BaseUtcOffset);
}
public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
{
DateTime paramVal = value.ToOffset(this.databaseTimeZone.BaseUtcOffset).DateTime;
parameter.Value = paramVal;
}
}
Now, notice that Dapper translates .Net's type DateTimeOffset to dbType - DateTimeOffset. You need to remove this mapping and add your own like this:
SqlMapper.RemoveTypeMap(typeof(DateTimeOffset));
SqlMapper.AddTypeHandler(DateTimeHandler.Default);
That's all. Now everytime Dapper will see DateTimeOffset property in your model, it will run your DateTimeHandler to manage this.
I have found that custom TypeHandler for base types can't be used because of default typeMap that is choosen before looking for TypeHandler.
I have opened an issue dapper-dot-net but in the mean time I have solved replacing via reflection the default typeMap with a new one like the previous minus the four key DateTime, DateTime?, DateTimeOffset, DateTimeOffset?
I've made a slight modification to Adam Jachocki's solution as it didn't work for me. I am storing a date as TEXT in Sqlite and Dapper was giving me a string instead of a DateTime as the object value to parse. Apparently, Sqlite stores datetime values using three different data types: INTEGER (unix epoch), TEXT (ISO 8601 YYYY-MM-DD HH:MM:SS.SSS), and REAL ("number of days since noon in Greenwich on November 24, 4741 B.C."). That last one is really out there, so it isn't supported in the code below.
See the sqlite docs and this page for more info.
Below is my implementation of the DateTimeOffset TypeHandler. The rest of Adam's solution remains the same.
internal class DateTimeOffsetHandler : SqlMapper.TypeHandler<DateTimeOffset>
{
private static readonly TimeZoneInfo databaseTimeZone = TimeZoneInfo.Local;
private static readonly DateTime unixOrigin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
public static DateTimeOffsetHandler Default { get; } = new DateTimeOffsetHandler();
public DateTimeOffsetHandler() {}
public override DateTimeOffset Parse(object value)
{
if (!TryGetDateTime(value, out DateTime storedDateValue))
{
throw new InvalidOperationException($"Unable to parse value {value} as DateTimeOffset");
}
if (storedDateValue.ToUniversalTime() <= DateTimeOffset.MinValue.UtcDateTime)
{
return DateTimeOffset.MinValue;
}
else
{
return new DateTimeOffset(storedDateValue, databaseTimeZone.BaseUtcOffset);
}
}
public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
{
DateTime paramVal = value.ToOffset(databaseTimeZone.BaseUtcOffset).DateTime;
parameter.Value = paramVal;
}
private bool TryGetDateTime(object value, out DateTime dateTimeValue)
{
dateTimeValue = default;
if (value is DateTime d)
{
dateTimeValue = d;
return true;
}
if (value is string v)
{
dateTimeValue = DateTime.Parse(v);
return true;
}
if (long.TryParse(value?.ToString() ?? string.Empty, out long l))
{
dateTimeValue = unixOrigin.AddSeconds(l);
return true;
}
if (float.TryParse(value?.ToString() ?? string.Empty, out float f))
{
throw new InvalidOperationException("Unsupported Sqlite datetime type, REAL.");
}
return false;
}
}

Why do I get strange timings when tracking my workflow?

I have a tracking participant which, when called, fires off a new thread to do the tracking work. The tracking work eventually does this:
private static readonly ConcurrentDictionary<string, DateTime> TimingsDictionary = new ConcurrentDictionary<string, DateTime>();
private static readonly ConcurrentDictionary<Guid, DateTime> WorkflowTimingsDictionary = new ConcurrentDictionary<Guid, DateTime>();
private void TimeActivityRecord(TrackingRecord record)
{
var activityStateRecord = record as ActivityStateRecord;
if (activityStateRecord != null)
{
if (activityStateRecord.State == ActivityStates.Executing)
{
if (!TimingsDictionary.TryAdd(GetActivityId(activityStateRecord), activityStateRecord.EventTime))
{}
}
if (activityStateRecord.State == ActivityStates.Closed
|| activityStateRecord.State == ActivityStates.Faulted
|| activityStateRecord.State == ActivityStates.Canceled)
{
DateTime startTime;
if (TimingsDictionary.TryRemove(GetActivityId(activityStateRecord), out startTime))
{
timer.TimeAction("Executing workflow step " + activityStateRecord.Activity.Name, activityStateRecord.InstanceId, activityStateRecord.EventTime.Subtract(startTime));
}
}
}
}
private void TimeWorkflowRecords(TrackingRecord record)
{
var workflowInstanceRecord = record as WorkflowInstanceRecord;
if (workflowInstanceRecord != null)
{
if (workflowInstanceRecord.State == WorkflowInstanceStates.Started)
{
if (!WorkflowTimingsDictionary.TryAdd(workflowInstanceRecord.InstanceId, workflowInstanceRecord.EventTime))
{}
}
if (workflowInstanceRecord.State == WorkflowInstanceStates.Completed
|| workflowInstanceRecord.State == WorkflowInstanceStates.Aborted
|| workflowInstanceRecord.State == WorkflowInstanceStates.UnhandledException
|| workflowInstanceRecord.State == WorkflowInstanceStates.Terminated
|| workflowInstanceRecord.State == WorkflowInstanceStates.Canceled)
{
DateTime startTime;
if (WorkflowTimingsDictionary.TryRemove(workflowInstanceRecord.InstanceId, out startTime))
{
timer.TimeAction("Executing workflow", workflowInstanceRecord.InstanceId, workflowInstanceRecord.EventTime.Subtract(startTime));
}
}
}
}
to track the entire workflow time and the times of the configured activities. however I get strange results with the workflow instance itself always seeming to take less time than the longest activity. sometimes I get the workflow taking 16ms and the 6 activities within it taking 625ms, 150ms, 125ms, 93ms, 17ms, 78ms.
Am I doing something very wrong? I feel like I must be missing something very obvious but can't for the life of me see what it is.
of course I was doing something stupid. When I logged the time taken from the timespan I was using
timespan.Milliseconds
rather than
timespan.TotalMilliseconds
back to school for me. Or maybe just some sleep.

Resources