Datetime issues with Mongo and C# - c#

I'm having an issue with saving and retrieving dates with Mongo using the c# driver. For some reason it it's truncating the ticks.
When I store this:
DateTime -> 5/17/2011 7:59:13 PM
Ticks -> 634412591533741650
I get this back:
DateTime -> 5/17/2011 7:59:13 PM
Ticks -> 634412591533740000
So if I try to do:
serverDateTime == mongoDateTime
It always fails. Anyway around this?

The reason is that the BSON DateTime format stores values with less precision than a .NET DateTime value, so when you read it back from the database the value has been truncated.
If your DateTime value is a property of a C# class you are serializing you can ask the serializer to serialize the DateTime value as an embedded document containing both the BSON DateTime value (truncated) and the original .NET DateTime value (stored as Ticks). In that case the value will not be truncated when deserialized.
For example:
public class MyClass {
public ObjectId Id;
[BsonRepresentation(BsonType.Document)]
public DateTime MyDateTime;
}
You can also use a BsonRepresentation of Int64 or String and not lose precision, but then the stored document only has Ticks or a string representation and no BSON DateTime, which makes it hard to do DateTime related queries.
You'll also want to keep in mind that DateTime values are stored in UTC in the database. The best practice is to always use UTC values for storage and only use local times when displaying them to the user.

Here's an extension you could use :)
public static class MongoDateComparison
{
private static int precisionInMilliseconds = 1000;
public static bool MongoEquals(this DateTime dateTime, DateTime mongoDateTime)
{
return Math.Abs((dateTime - mongoDateTime).TotalMilliseconds) < precisionInMilliseconds;
}
}

Related

How can I get the value of a date into a string in the format YYYY-MM-DDThh:mm:ss.sssZ for CosmosDB?

The CosmosDB database I am using suggests I store DateTime in a string.
Working with Dates in Azure Cosmos DB
So I am trying to do this:
string DateAndTime = DateTime.Now.ToString()
but it's not giving me the correct format. Is there a method to do this and to convert it to this exact format: YYYY-MM-DDThh:mm:ss.sssZ ?
If you're not already using the DocumentClient, you could use this to interface with your collection.
Using the DocumentClient means that you can define your document types as you wish, without having to manually convert fields to string. For example, you could use the following type to create/query documents out of the collection:
public class CosmosDocument
{
[JsonProperty("id")]
public string Id { get; set; }
public DateTime TimeStamp { get; set; }
}
The DocumentClient will then serialize/deserialize/model-bind the data, including DateTime values for you.
The serialization is configurable if you need to make any changes to the default settings.
EDIT
As noted in the comments, CosmosClient is the newer version that provides the same functionality described above.
According to Custom date and time format strings, you should use something like that
string DateAndTime = DateTime.Now.ToString("yyyy-MM-ddThh:mm:ss.sssz");
It will give you the following string 2020-04-04T11:19:06.06+3
yyyy means four-digit year (YYYY format doesn't exist), dd represents the day of the month (from 01 to 31). z is used for offset between your local time zone and UTC
The capital Z literal in string indicates that datetime is in UTC format (according to ISO 8601 standard). To get it literally in a result string you may use DateTime.UtcNow instead of DateTime.Now with Z literal or K specifier at the end
string DateAndTime = DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ss.sssK");
It gives you 2020-04-04T08:49:22.22Z (current datetime in UTC format). K specifier will add Z literal for UTC dates and offset (in zzz format) for local dates

Display date in local format but force time in 24-hour format

So in one instance I've decorated a nullable DateTime with
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy HH:mm:ss}")]
and in another, an interpolated string
$"{theDateTimeObject:dd/MM/yyyy HH:mm:ss}"
I want to display the date in the local format (so MM/dd/yyyy for the U.S.) but always display the time in 24-hour format, regardless of any OS settings or otherwise.
Thanks in advance for any help.
One way to do it is to display a string property instead of your actual DateTime value.
Here's an example:
private DateTime _actualDateTime;
public string DateTimeForDisplay
{
get
{
return _actualDateTime.ToString("d") +" "+ _actualDateTime.ToString("HH:mm:ss");
}
}

Converting DateTime to SmallDateTime in c#

How can ı convert datetime to smalldatetime in c# ? I'm taking the date and ı need to convert it to be accordance with database. It is forbidden to change the datatype of column in sql.
You can use the .NET DateTime type for your entity framework model, but tell EF that it uses a non-default column type in the database. You do this by overriding the OnModelCreating method of your DbContext, and using the HasColumnType method:
public class Foo
{
public int Id { get; set; }
public DateTime IAmSoSmall { get; set; } // wants to be smalldatetime in SQL
}
public class MyContext : DbContext
{
public DbSet<Foo> Foos { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var foo = modelBuilder.Entity<Foo>();
foo.Property(f => f.IAmSoSmall).HasColumnType("smalldatetime");
base.OnModelCreating(modelBuilder);
}
}
Of course, you'll have to do the appropriate range-checking on your DateTime property to be sure that the stored values fall between those supported by SQL's smalldatetime. I guess you could do that with a property attribute like:
[Range(typeof(DateTime), "1/1/1900", "6/6/2079")]
public DateTime IAmSoSmall { get; set; } // wants to be smalldatetime in SQL
...based on a valid range from January 1, 1900, through June 6, 2079, as documented on MSDN.
Sql Server datetime and smalldatetime are both automatically mapped to and from the CLR's System.DateTime. A smalldatetime has a precision of 1 minute; a datetime has a precision of approximately 1/300 of a second (Don't ask why. It just is). Since the CLR's System.DateTime1 has a precision of 100-nanoseconds, the runtime takes care of rounding.
smalldatetime is internally a 32-bit integer, containing a count of minutes since the smalldatetime epoch (1900-01-01 00:00).
In conversion, seconds and fractional seconds are rounded using SQL Server's arcane date/time rounding rules, so the date 2013-01-31 23:59:59 gets rounded to the next date 2013-02-01 00:00:00'.
datetime is a pair of 32-bit integers internally. The high-order word is a count of days since the epoch; the low-order word is a count of milliseconds since start-of-day (00:00:00). The epoch of a datetime is 1900-01-01 00:00:00.000.
And again, values are rounded in the conversion in the same arcane way, with franctional seconds getting placed into one of the appropriate millisecond buckets for SQL Server, a multiple of 3ms — there is no SQL Server `datetime value like 2013-05-01 13:57:23.004. That will get "rounded" to either 23.003ms or 23.006ms.
If you want more control over things, you'll need to adjust your datetime values in C# before sending them to the database.
Maybe you can do something like YourDateTime.Date
Normally, when you do that way, it will set time to 00:00:00.

Force XmlSerializer to serialize DateTime as 'YYYY-MM-DD hh:mm:ss'

I have a XSD schema for some RESTful service. When used in conjunction with xsd.exe tool to generate C# code, XSD's xs:date generates the following code:
[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified, DataType="date")]
public System.DateTime time {
get {
return this.timeField;
}
set {
this.timeField = value;
}
}
When deserializing XML to objects using XmlSerializer all seems to be well. The problem I am facing is that the service expects dates to be formatted as YYYY-MM-DD hh:mm:ss and the XSD generated code seems to produce only YYYY-MM-DD.
If I modify XSD manually to xs:dateTime type, the generated C# code produces: 2010-08-20T20:07:03.915039Z.
Basically, how do I force serialization to produce YYYY-MM-DD hh:mm:ss? Is there something to do to XSD or is there something I can do to alter generated C# code?
In the past, I've done the following to control datetime serialization:
Ignore the DateTime property.
Create a dummy string property that serializes/deserializes the way I want
Here is an example:
public class SomeClass
{
[XmlIgnore]
public DateTime SomeDate { get; set; }
[XmlElement("SomeDate")]
public string SomeDateString
{
get { return this.SomeDate.ToString("yyyy-MM-dd HH:mm:ss"); }
set { this.SomeDate = DateTime.Parse(value); }
}
}
Use [XmlElement(DataType = "date")] attribute to format your DateTime property value as you need.
From MSDN:
Note:
The attribute that annotates the publicationdate field has a
DataType property. There is no type in the .NET Framework that matches
the type xs:date completely. The closest match is System.DateTime,
which stores date and time data. Specifying the DataType property as a
"date" ensures that the XmlSerializer will only serialize the date
part of the DateTime object.
If you only need to clear out the millisecond part. Refer to:
How to truncate milliseconds off of a .NET DateTime
And basicly do something like:
startDateTimeToUse = startDateTimeToUse.AddTicks(-(startDateTimeToUse.Ticks % TimeSpan.TicksPerSecond));
endDate = endDate.AddTicks(-(endDate.Ticks % TimeSpan.TicksPerSecond));
I can confirm that this serializes to:
<startDate>2015-10-31T12:13:04</startDate>
<endDate>2016-11-10T12:13:06</endDate>
I must also state that Before clearing the milliseconds I'm doing this:
var startDateTimeToUse = ssStartDateTime.ToUniversalTime();
var endDate = DateTime.Now.ToUniversalTime();
startDateTimeToUse = DateTime.SpecifyKind(startDateTimeToUse, DateTimeKind.Unspecified);
endDate = DateTime.SpecifyKind(endDate, DateTimeKind.Unspecified);
Which I don't know if it's having any effect on the serialization or not at this point
I believe implementing IXmlSerializable interface will do a trick. You can then control how you serialize and deserialize your object.
see answers above but to add-- if you only wanted output when the value is non-null (e.g. XML maxOccurs=0) you can utilize something like this:
private System.DateTime? someDateField;
public string someDate
{
get
{
return someDateField?.ToString("MM-dd-yyyy");
}
set
{
dobField = System.DateTime.Parse(value);
}
}
I may have another option.
When setting your DateTime just subtract the number of ticks of everything after the seconds, like:
public DateTime Dt
{
get => _dt;
set
{
_dt = value;
long elapsedTicks = _dt.Ticks - new DateTime(_dt.Year, _dt.Month, _dt.Day, _dt.Hour, _dt.Minute, _dt.Second).Ticks;
TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
_dt = _dt.Subtract(elapsedSpan);
}
}
private DateTime _dt = default(DateTime);
That way when you serialize your DateTime (Dt) the milliseconds won't be used and you'll have a value hh:mm:ss, that is at least what it gave me. That way no need to modify anything inside your XML definition.

Replace a Date or Time section in a DateTime object in C#

I have a DateTime object which may or may not already contain some date/time information. With that I need to replace the time with my new time independently of the date and vice versa. How would I achieve this? I can't see anything obvious other than creating two new DateTime objects, one with the old/new date and one with the old/new time and concatenating. There surely must be a better way than this?
I would write two or three extension methods:
public static DateTime WithTime(this DateTime date, TimeSpan time)
{
return date.Date + time;
}
public static DateTime WithDate(this DateTime original, DateTime newDate)
{
return newDate.WithTime(original);
}
public static DateTime WithTime(this DateTime original, DateTime newTime)
{
return original.Date + newTime.TimeOfDay;
}
(You really don't need both of the second methods, but occasionally it might be simpler if you're chaining together a lot of calls.)
Note that you aren't creating any objects in terms of items on the heap, as DateTime is a struct.
DateTime is an immutable structure.
The only option is to construct a new DateTime struct based off your two existing values. This is the best approach. Luckily, it's a one liner:
DateTime CreateNewDateTime(DateTime date, DateTime time)
{
return new DateTime(date.Year, date.Month, date.Day, time.Hour, time.Minute, time.Second);
}
Strip the time from an existing datetime by writing .Date
DateTime new = oldDate.Date;
Add your TIme by either adding the hours, minutes & seconds individually
DateTime new = oldDate.Date.AddHours(14).AddMinutes(12).AddSeconds(33);
or all at once
DateTime new = oldDate.Date.AddSeconds(51153);
or by adding a TimeSpan()
DateTime new = oldDate.Date.Add(new TimeSpan(14,12,33));
This may not be exactly what you're looking for, but the DateTime class has a series of Add methods (AddMinutes(), AddDays(), etc.). I say this might not be what you're looking for, because these return a DateTime, so you would have to do something like
myDate = myDate.AddMinutes(60);

Categories

Resources