I have an object that represents a scheduled payment. My database has a list of these payments, but I have one instance of a payment.
I need to write a method that gets the next payment after the one I have, as well as the previous date of the previous payment.
I'd like to write a method that return the two dates. But the return type of 'DateTime' only allows for one. I could return a List<DateTime> but that seems strange and ma be ambiguous. Which is the previous and which is the next?
I can also create a DTO object that has:
DateTime previousPayment {get; set;}
DateTime nextPayment {get; set;}
Tuple<DateTime, DateTime> might be another options, but it too is ambiguous. Unless I can name the properties of it?
But - is there a better way to allow for a method to return two dates? Anonymous types or something?
Use the "ref" modifier. (You may use "out" instead if you do not need to read the variable before it is assigned)
public void GetNextPayment(ref DateTime previousPayment, ref DateTime nextPayment){
// do stuff here
}
Usage:
DateTime previousPayment = DateTime.Now(); //Example
DateTime nextPayment = DateTime.Now(); // example
GetNextPayment(ref previousPayment, ref nextPayment); // Forgot to add "ref" when calling it
previousPayment and nextPayment will be modified in the function and maintain the value.
Update with Dictionary
As Anik mentioned, it might be better to use a Dictionary;
public Dictionary<string,DateTime> GetNextPayment(DateTime previousPayment, DateTime nextPayment){
// modify payments
Dictionary<string,DateTime> myDict = new Dictionary(string, DateTime);
myDict.Add("PreviousPayment", [date]);
myDict.Add("NextPayment", [date]);
return myDict;
}
Use Class
Ilya. N. mentioned to use a class. I would have to agree with this if you're going to have lots of payment objects going to be used more than once. But I firmly believe it's better to give you all the tools available at your disposal because you never know when you might want to use out parameters or Dictionaries.
public class Payment {
public string Name {get;set;}
public DateTime previousPayment {get;set;}
public DateTime nextPayment {get;set;}
public GetNextPayment(){
// code to get the next payment
this.previousPayment = //whatever
this.nextPayment = //whatever
}
}
If you only have ONE payment you are going to be using, like ever. (good to future proof with a class), then you might use a method or dictionary.
Besides the two options you listed, there are two more:
Return a Tuple<DateTime, DateTime>
Use out parameters
Why not simply return a class?
public class DateCombo {
DateTime PreviousPayment {get; set;}
DateTime NextPayment {get; set;}
}
try this ...
private void Form1_Load(object sender, EventArgs e)
{
DateTime previousPayment =new DateTime();
DateTime nextPayment=new DateTime();
getdate(ref previousPayment, ref nextPayment);
}
public void getdate(ref DateTime previousPayment, ref DateTime nextPayment)
{
previousPayment = System.DateTime.Now;
nextPayment = System.DateTime.Now.AddDays(1);
}
Related
I've read a bunch about auto implemented properties but I still don't quite get it. I have and entity:
public class News
{
public int NewsId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Date { get; set; }
}
Now I don't want the user to set date himself every time a new entity of News type is created. I want the record to be saved automatically with the datetime it's created. Thinking about it I suggest that it's enough to just modify the set for my property to something like :
public DateTime Date
{
get;
set
{
Date = DateTime.Now;
}
}
But reading about the topic I saw that the standard way is to create private variable and use it instead in the implementation. That's where I get a little bit lost.
private DateTime _date = null;
public DateTime Date
{
Well I'm not sure for the getter and setter implementations. It seems reasonable to have something like : set { _date = DateTime.Now;} and I have no idea how to deal with the get part since I want this data to be fetched from the database so something like : get {return _date;} doesn't make much sense to me even though almost every example with auto implementedset` returns the private variable. But I think that if the property is an entity this is not making a lot of sense.
Some ways to return the current date:
public DateTime Date { get { return DateTime.Now; } }
or
public class News
{
public News()
{
Date = DateTime.Now;
}
public DateTime Date { get; private set; }
}
The first one will always return the current date/time, even if that instance was created some time ago. The second one will return the date/time the instance was created. Both prevent the user from setting that Date value.
You could add a constructor to your class and then initialize there your property.
public class News
{
// properties goes here
public News()
{
Date=DateTime.Now;
}
}
A far better constructor would be the following
public News(int newsId, string title, string content)
{
NewsId=newsId;
Title=title;
Content=content;
Date=DateTime.Now;
}
That way you could create an object of type News in a single line of code.
News news = new News(1,"title1","whatever");
Don't touch the getter and setter! They are auto generated from a template and will be overridden every once and a while. Instead, as you might have noticed the generated entities are declared partially, create a partial class and declare a constructor there that sets the _date or Date of you r entity to DateTime.Now on construction (just as you desired).
public partial class News
{
public News()
{
this.Date = DateTime.Now;
}
}
I have an object class TimeDuration. When I tried to change the value of object taken from the array Span, the value inside the array also changes. How can I get copy of an object that won't change its parent object value? I need to pass this copy to another function where I have to make changes to this object
public void test()
{
List<TimeDuration> Span = new List<TimeDuration>();
TimeDuration ob = new TimeDuration();
ob.FromTime = DateTime.Now;
ob.ToTime = DateTime.Now.AddDays(1);
Span.Add(ob);
//Trying to assign value here!
TimeDuration ob2= Span[1];
ob2.FromTime = DateTime.Now.AddDays(3);
}
public class TimeDuration
{
public DateTime FromTime { get; set; }
public DateTime ToTime { get; set; }
}
Firstly, you should understand why the current code behaves as it does. See my article on reference types and value types for more details.
How can I get copy of an object that won't change its parent object value?
Two simple options:
Create some sort of cloning method which creates a copy of the existing object. You need to do this explicitly - although you could use object.MemberwiseClone as a shortcut in some cases. In many cases it's pretty simple, although inheritance makes it harder.
Make your TimeDuration class immutable, e.g. with methods of WithToTime returning
a new version:
public TimeDuration WithFromTime(DateTime newFromTime)
{
return new TimeDuration(newFromTime, ToTime);
}
You'd make your properties read-only, and provide a constructor taking both values (which can also validate them). You might even consider making it a struct at this point.
Consider turning the class into a struct, and of course also make it immutable:
public struct TimeDuration
{
public DateTime FromTime { get; private set; }
public DateTime ToTime { get; private set; }
public TimeDuration(DateTime fromTime, DateTime toTime) : this()
{
FromTime = fromTime;
ToTime = toTime;
}
public TimeDuration SetFromTime(DateTime fromTime)
{
var copy = this;
copy.FromTime = fromTime;
return copy;
}
public TimeDuration SetToTime(DateTime toTime)
{
var copy = this;
copy.ToTime = toTime;
return copy;
}
}
Make your TimeDuration a struct instead of a class: value types are passed by value, so you will get a kind of "copy" behaviour.
Classes are reference types. The value inside the array is a pointer to the memory location of your TimeDuration object and not a new instance of it. Therefore when you change the value it affects the array also.
You will have to create a new object of TimeDuration and pass that about.
If you're always using TimeDuration this way, you may want to consider changing it from a class to a struct. To duplicate a class, you should implement ICloneable and call the Clone method.
I'm using Dapper to map my entities to SQL Server CE. If I save a DateTime with Kind=Utc, when I read it back I get a DateTime with Kind=Unspecified, which leads to all kind of problems.
Example:
var f = new Foo { Id = 42, ModificationDate = DateTime.UtcNow };
Console.WriteLine("{0} ({1})", f.ModificationDate, f.ModificationDate.Kind);
connection.Execute("insert into Foo(Id, ModificationDate) values(#Id, #ModificationDate)", f);
var f2 = connection.Query<Foo>("select * from Foo where Id = #Id", f).Single();
Console.WriteLine("{0} ({1})", f2.ModificationDate, f2.ModificationDate.Kind);
This code gives the following output:
20/09/2012 10:04:16 (Utc)
20/09/2012 10:04:16 (Unspecified)
I know I should be using a DateTimeOffset, but unfortunately SQL CE has no support for this type.
Is there a workaround? Can I tell Dapper to assume that all dates have DateTimeKind.Utc? And more generally, what are my options to customize the mapping?
EDIT: My current workaround is to patch the dates after Dapper has materialized the result, but it kind of smells...
var results = _connection.Query<Foo>(sql, param).Select(PatchDate);
...
static Foo PatchDate(Foo f)
{
if (f.ModificationDate.Kind == DateTimeKind.Unspecified)
f.ModificationDate = DateTime.SpecifyKind(f.ModificationDate, DateTimeKind.Utc);
return f;
}
Adding this answer for anyone else who comes looking for a simple fix. This is possible now with the addition of SqlMapper.TypeHandler in Dapper.
Add this class to convert the value from the db to a datetime with the kind specified as UTC.
public class DateTimeHandler : SqlMapper.TypeHandler<DateTime>
{
public override void SetValue(IDbDataParameter parameter, DateTime value)
{
parameter.Value = value;
}
public override DateTime Parse(object value)
{
return DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
}
}
Then in my Global.asax file of my Web API I add the type handler to dapper.
SqlMapper.AddTypeHandler(new DateTimeHandler());
If you need to ensure you are always inserting dates as UTC, then on the SetValue method you can use:
parameter.Value = DateTime.SpecifyKind(value, DateTimeKind.Utc);
Looked into the Dapper code. Unless mine was out of date, for value types like datetime (which is mapped to DbType.DateTime), dapper just does a simple cast from the IDataReader object.
Pseudo : yield return (DateTime)IDataReader.GetValue(0);
That's the specific case for Datetime out of a bunch of generic code and lambdas.
AFAIK, SQL datetime never stores the offset / timezone so the kind will always say "Unspecified" on any datetime you store and fetch.
So, to do it cleanly, you could touch dapper internals:
which is a pain as you'd have to touch a big IL generating method (the DataRow Deserializer) and put in an if case for DateTime.
OR
just put a setter on the DateTime props where UTC is an issue (which is kinda against POCO but is relatively sane):
class Foo
{
private DateTime _modificationDate;
public DateTime ModificationDate
{
get { return _modificationDate; }
set { _modificationDate = DateTime.SpecifyKind(value, DateTimeKind.Utc); }
}
//Ifs optional? since it's always going to be a UTC date, and any DB call will return unspecified anyways
}
Just wanted to put my full solution here for seamlessly integrating DateTimeOffset / DateTimeOffset? fields/properties with a MySQL 5.7 database (which doesn't support DbType.DateTimeOffset) - based on #matt-jenkins answer above:
public static class DapperExtensions
{
class DateTimeOffsetTypeHandler : SqlMapper.TypeHandler<DateTimeOffset>
{
public override void SetValue(IDbDataParameter parameter, DateTimeOffset value)
{
switch (parameter.DbType)
{
case DbType.DateTime:
case DbType.DateTime2:
case DbType.AnsiString: // Seems to be some MySQL type mapping here
parameter.Value = value.UtcDateTime;
break;
case DbType.DateTimeOffset:
parameter.Value = value;
break;
default:
throw new InvalidOperationException("DateTimeOffset must be assigned to a DbType.DateTime SQL field.");
}
}
public override DateTimeOffset Parse(object value)
{
switch (value)
{
case DateTime time:
return new DateTimeOffset(DateTime.SpecifyKind(time, DateTimeKind.Utc), TimeSpan.Zero);
case DateTimeOffset dto:
return dto;
default:
throw new InvalidOperationException("Must be DateTime or DateTimeOffset object to be mapped.");
}
}
}
private static int DateTimeOffsetMapperInstalled = 0;
public static void InstallDateTimeOffsetMapper()
{
// Assumes SqlMapper.ResetTypeHandlers() is never called.
if (Interlocked.CompareExchange(ref DateTimeOffsetMapperInstalled, 1, 0) == 0)
{
// First remove the default type map between typeof(DateTimeOffset) => DbType.DateTimeOffset (not valid for MySQL)
SqlMapper.RemoveTypeMap(typeof(DateTimeOffset));
SqlMapper.RemoveTypeMap(typeof(DateTimeOffset?));
// This handles nullable value types automatically e.g. DateTimeOffset?
SqlMapper.AddTypeHandler(typeof(DateTimeOffset), new DateTimeOffsetTypeHandler());
}
}
}
If you are using Dapper from source (not nuget), you could tweak the code to always force DateTimeKind of UTC. A more configurable option might be to create a new attribute for DateTime property values that allow you to specify date time kind as a hint to dapper. Dapper could look for DateTime properties with this attribute and when found could use it to specify the DateTime kind during ORM mapping. This might be a nice feature for core dapper as you are not the only one with this issue :)
I want to subtract two Dates and get the value in Timespan for Example
TimeSpan duration = Convert.ToDateTime(completeDate).Subtract(Convert.ToDateTime(lastRundate));
This is for Normal implementation. HOw can one do it in Linq to Entities in Entity Framework wherein
from job in Jobs
select new JobEntity
{
Duration = job.CompleteDate.Value.Subtract(job.NextRunDate.Value)
};
where Jobs is my table, CompleteDate & NextRunDate are my column names of DataType DateTime? (since it allows null value)
When I tried this code, it gives me this error
LINQ to Entities does not recognize the method 'System.TimeSpan Subtract(System.DateTime)' method, and this method cannot be translated into a store expression.
Please do let me know how to go about this.
thanks in advance
Why not extend your JobEntity model?
public DateTime NextRunDate { get; set; }
public DateTime CompletedDate { get; set; }
public Timespan Duration
{
get
{
return CompleteDate.Subtract(NextRunDate)
}
}
You can try to use EntityFunctions:
from job in Jobs
select new JobEntity
{
Duration = EntityFunctions.DiffSeconds(job.CompleteDate, job.NextRunDate)
};
You need using System.Data.Objects; in your code file for this. It will return the time span in seconds as an int.
What is the best way to compare all properties of two objects where some of them have different formats (e.g. DateTime in one and DateTime.ToString() with custom format in other)?
I was able to do that by using 2 assertions:
o1.ShouldHave().AllPropertiesBut(dto1 => dto1.Date).EqualTo(o2);
o1.Date.Should().Be(DateTime.Parse(o2.Date));
I would think about the following, but that does not compile because EqualTo<T>() is void.
o1.ShouldHave().AllProperties().But(d => d.Date).EqualTo(o2)
.And.Date.Should().Be((DateTime.Parse(o2.Date));
types are:
public class Dto1
{
public int ID { get { return 1; } }
public DateTime Date { get { return DateTime.Now.Date; } }
}
public class Dto2
{
public int ID { get { return 1; } }
public string Date { get { return DateTime.Now.Date.ToShortDateString(); } }
}
var o1 = new Dto1();
var o2 = new Dto2();
The first example is typically the best way. However, if you would switch o1 and o2, it might work in a single call. Fluent Assertions will try to convert (using Convert.ChangeType) the actual value of a property to the expected value of the property with the same name. In your particular example, it would try to convert the DateTime in Dto1 to a string in Dto2 before comparing the values. But since the string representation of a DateTime is dependent on the culture of the thread, it would not give you predictable results. However, if you would switch o1 and o2, I wouldn't be surprised if Convert.ChangeType would succesfully convert your short datetime back to a DateTIme object.
As a side-note, my DTOs usually just pass the DateTime to the caller without any string conversion. I believe that the actual representation of the DateTime is purely a UI responsibility.
HTH
Dennis