I want to query the update timestamp _ts on documents to get documents that haven't mutated since a certain amount of time.
When I create a select query in the azure portal this works:
SELECT TOP 10 c.id FROM c WHERE c._ts < 6.35909919217878E+17
The wierd number is the Ticks created with a datetime object, see below.
But when I try to create it through LINQ it won't do because you don't have _ts but a Timestamp as a DateTime object. When I try to enter a full DateTime object to compare to the Timestamp it crashes saying it doesn't support it. So I try this:
DocRepo.Get(x => x.Timestamp.Ticks < CloseDate.Ticks);
This results to nothing and when I watch the query executed it has this as a select query:
SELECT * FROM root WHERE root[\"_ts\"][\"Ticks\"] < 6.35909943137688E+17
Is it possible to query on the _ts timestamp or do i have to have an extra updatedAt field to do it, which seems redundant.
You have a couple of problems with your queries. In your first query, you are comparing "Ticks" (one ten millionth of a second - see here) to the _ts value which will most likely return all the documents in your collection because the _ts value is a POSIX (Unix) time measured in seconds see here. They also aren't based on the same epoch. The Unix value starts at midnight 1,1,1970 where the Ticks start at midnight 1,1,0001 Therefore, the _ts value will always be much smaller than the Ticks value (not to mention off by 1,969 years!). You will need to convert your dates to their Unix time value. You could create an Extension method to help you do this:
public static long ToUnixTime(this DateTime date)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (long)(date - epoch).TotalSeconds;
}
As for the Linq statement, you can't (unfortunately) put a DateTime into a Linq query because a DateTime value won't convert to a const (which is the error you are getting). So, in both cases, you can't compare either the _ts value or TimeStamp value very easily.
So what to do? Well, in looking at the DocumentDB SDK, if you look at the definition of TimeStamp you will see the following:
// Summary:
// Gets the last modified timestamp associated with the resource.
[JsonConverter(typeof(UnixDateTimeConverter))]
[JsonProperty(PropertyName = "_ts")]
public virtual DateTime Timestamp { get; internal set; }
So by default, the SDK is converting the _ts value to a DateTime and exposing it through TimeStamp field. There are a couple of things you could do depending on what type your DocRepo is returning. If it is the default Document type, you could create a new class and inherit from the Docment type like this:
public class MyDocument : Document
{
public long _ts
{
get; set;
}
}
If it is your own custom class, then just add the _ts field to your class. Either way, if the _ts field is present, DocumentDB will populate the field. Then, if you add the ToUnixTime extension method you could compose your Linq query like this:
DocRepo.Get(x => x._ts < CloseDate.ToUnixTime());
It may not be an elegant solution and someone (hopefully) might come up with a better solution, but I have verified that it works against my own DocumentDB collection.
Hope this helps.
This is what i use to convert Unix timestamp into DateTime format we can easily understand in C#:
public DateTime TimeStamp
{
get
{
return DateTimeOffset.FromUnixTimeSeconds(int.Parse(_ts)).DateTime;
}
}
Hope this helps.
Related
I have 2 datetime objects that I need to combine.
This contains the correct date, but the time part is not needed.
DateTime? sessionDate = fl.EventDateTimeStart
This contains the correct time, but the date part needs to be the date value from the
sessionDate object above.
DateTime? sessionStartTime = g.GameStartTime.Value
I tried using some of the various DateTime toString() methods, but found out that
because they are part of a class, they need to remain DateTime? types
so I can't just convert them to a string.
So I came up with this really ugly method:
sessionStartTime = new DateTime(
fl.EventDateTimeStart.Value.Year,
fl.EventDateTimeStart.Value.Month,
fl.EventDateTimeStart.Value.Day,
g.GameStartTime.Value.Hour,
g.GameStartTime.Value.Minute,
g.GameStartTime.Value.Second)
Is there a more elegant way of to do this?
Thanks!
Sure.
var result = fl.Value.Date + g.Value.TimeOfDay;
DateTime.Date returns a DateTime with the time part set to midnight. DateTime.TimeOfDay gets a TimeSpan containing the fraction of the day that has elapsed since midnight.
Make sure that both of your DateTimes have the same Kind, otherwise the result might not be what you expect.
My application automatically bills subscribed customers using a payment processing vendor. I keep only information on the expiry date of the card and the vendors reference number for auto-billing. Everyday I want to check members whose cards will expire within 30 days. I am running a background process to send email reminders. I am struggling getting Linq to accept my query. The expiry date is stored in the database as a string eg 0319 for March 2019. I am wondering if I have any chance of getting this to work. Please assist if you can. My last resort might be having to format expiry dates currently stored as strings mmyy in database to proper dates.
int mon = DateTime.Now.Month;
int yr = DateTime.Now.Year;
int days = DateTime.DaysInMonth(yr, mon);
int dy = DateTime.Now.Day;
var allCardExpiring = db.DirectDebits.Include(i => i.Customer).Where(a =>a.DdOk && a.Customer.PassOk && DateTime.DaysInMonth(Convert.ToInt32(a.DateExpiry.Substring(2, 4)), Convert.ToInt32(a.DateExpiry.Substring(0, 2)))+days-dy < 30).Select(a => a.DirectDebitId).Distinct().ToList();
This is a good example that shows that you should not form the database into the format that operators use to enter their input. If your database would have had the ExpiryDate as a DateTime, you wouldn't have had this problem. Of course with the cost that when operators enter their expiry date you would have to convert it to a DateTime, but (1) that is easier than converting back and (2) What do you more often: query the ExpiryDate or update it?
If you are stuck with this database, then my advice would be to create a query where you split your MonthYear property into a a Month and a Year, using DbFunctions.Left and DbFunctions.Right then convert it in your query to a proper DateTime using DbFunctions.CreateDateTime
If you need this conversion for other functions, consider creating separate IQueryable functions for this, so you can re-use it.
As extension function for your DirectDebit that takes an input sequence of DirectDebits and returns a DateTimeDirectDebit sequence:
public static IQueryable<DateTimeDirectDebit> ToDateTimeDirectDebits(
this IQueryable<DirectDebit> directDebits)
{
return directDebits.Select(directDebit => new
{
// split ExpiryDate into a Month and a Year
ExpiryDate = new
{
Month = DbFunctions.Left(directDebit.DateExpire, 2),
Year = DbFunctions.Right(directDebit.DateExpire, 2),
}
DirectDebit = directDebit,
})
.Select(directDebit => new DateTimeDirectDebit
{
// create the ExpiryDate as DateTime
ExpiryDate = DbFunctions.CreateDateTime(
directDebit.ExpiryDate.Year,
directDebit.ExpiryDate.Mnth,
1, // first day of the month
...),
DirectDebit = directDebit.DirectDebit,
});
}
You also need a function that returns the DateTimeDirectDebits that expire within a certain amount of days. Again as an extension method:
public static IQueryable<DateTimeDirectDebit> WhereExpiresWithinDays(
this IQueryable<DateTimeDirectDebit> source,
int nrOfDays)
{
DateTime now = DateTime.now;
DateTime limitDate = now.AddDays(nrOfDays);
return source.Where(directDebit => directDebit.ExpiryDate < limitDate);
}
Similarly you might want a function that returns all directDebits that expire next Month use DbFunctions.DiffMonths for this.
Usage:
using (var dbContext = new ...)
{
var directDebitsThatExpireNextMonth = dbContext.DirectDebits
.ToDateTimeDirectDebits
.WhereExpiresWithinDays(30)
.Select(...);
}
The nice thing is, that by using these LINQ-like extension methods, you can hide how your database is structured, especially the parts that you are not happy about. This way, your code does not have to be restructures so much if your database changes internally, especially those functions that don't use these changes.
Of course, for a proper hiding of the database structure, class DateTimeDirectDebits should not expose property DirectDebits, but only the properties you want to show to the outside world.
I have a view model in which I am storing a DateTime but in my view using a JQUERY datetimepicker, time only:
ViewModel
[DataType(DataType.Time)]
public DateTime? MondayFrom { get; set; }
[DataType(DataType.Time)]
public DateTime? MondayTo { get; set; }
As it stands, when the Create method gets called it is using todays date plus the time selected from the timepicker.
As I am not particularly concerned with the Date part of the DateTime, I want to change the day, month & year to 01/01/1900 or something less specific than the date the record was written, before the record is created, this is purely to avoid any confusion in the future.
I don't want to get bogged down on whether this is the right thing to do or not.
I'm struggling to get a handle on the Date part of the DateTime, see below:
public void CreateClub(Club club)
{
foreach (var item in club.MeetingDays)
{
// change Date part to 01/01/1900, leave the time as is..
}
_repository.CreateClub(club);
}
How might I floor the date part of the item but leave the time well alone?
Just use the TimeOfDay property to extract the time within the day, and add that to the date you want:
private static readonly DateTime BaseDate = new DateTime(1900, 1, 1);
var updatedDateTime = BaseDate + otherDateTime.TimeOfDay;
You could even write an extension method or two:
public static DateTime WithDate(this DateTime start, DateTime date)
{
// No need to use the Date property if you already know
// it will be midnight...
return date.Date + start.TimeOfDay;
}
public static DateTime WithFloorDate(this DateTime start)
{
return start.WithDate(FloorDate);
}
Of course, I'd suggest you use Noda Time where you can specify dates, times and date/time values (with or without a time zone or UTC offset0 separately, but that's a different conversation.
DateTime is immutable - you cant just change part of it. You can extract the time and add it to a "base" date:
for(int i=0; i < club.MeetingDays.Count; i++)
{
club.MeetingDays[i] = new DateTime(1900, 1, 1) + club.MeetingDays[i].TimeOfDay;
}
Note that you need a for loop so you can place the new value back in the collection. You could also use Linq:
club.MeetingDays = club.MeetingDays
.Select(t => new DateTime(1900, 1, 1) + t.TimeOfDay)
.ToList();
Assuming that club.MeetingDays is a List<Datetime>
I need to store DateTime in int. So I tried below codes
Int64 n = Int64.Parse(DateTime.Today.ToString("dd-MM-yyyy"));
or
Int64 twoday_date=Convert.ToInt64(System.DateTime.Today.ToString("dd-MM-yyyy"));
but its showing error:
Input string was not in a correct format.
Where is the error?
Just use DateTime.Ticks instead - there's absolutely no reason to start converting to and from strings here.
long ticks = DateTime.Today.Ticks;
// Later in the code when you need a DateTime again
DateTime dateTime = new DateTime(ticks);
Note that this will use the local date - if you're trying to retain a global timestamp, you should use DateTime.UtcNow instead of DateTime.Today.
If you really need int instead of long, you probably ought to translate and scale, e.g. to seconds since the Unix epoch.
You could either store the milliseconds from a certain point in time (that you define), or you could use a format such as yyyyMMddhhmmss (and fff if you want more precision).
The original question asks where is the error? within:
Int64 n = Int64.Parse(DateTime.Today.ToString("dd-MM-yyyy"));
The ToString(...) method generates a string representation of the date time value. In this case its argument, the string "dd-MM-yyyy" gives the format of the string to be generated. So today that will generate the string "11-01-2014". The Int64.Parse(...) attempts to parse its argument string as an integer, but here it has a mix of digits and hyphens. Hence it throws an exception.
Understanding these sort of problems can be tricky. One technique is to break the statement into smaller pieces and understand each of them in turn. When the problem is resolved the corrected pieces can be assembled into a single statement if desired. In this case the statement could be split to be:
string s = DateTime.Today.ToString("dd-MM-yyyy");
Console.WriteLine("The date string is '{0}'", s);
Int64 n = Int64.Parse(s);
Then use either a debugger or the WriteLine shown to show the value in s. Note that the WriteLine encloses the displayed value of s in quotes so that the presence or absence of spaces, newlines and other unexpected characters can easily be detected.
// the local utc offset is +2:00
public class Program
{
public static void Main(string[] args)
{
// code executed in timezone GMT+2:00
long ticksUtc = DateTime.UtcNow.Ticks;
Console.WriteLine("{0:d}",ticksUtc);
DateTime _todayUtc = new DateTime(ticksUtc);
Console.WriteLine("{0}",_todayUtc);
// get local date time from Utc time
Console.WriteLine("{0}",_todayUtc.ToLocalTime());
Console.WriteLine();
long ticksLocal = DateTime.Now.Ticks;
Console.WriteLine("{0:d}",ticksLocal);
Console.WriteLine("{0:d}",ticksLocal-ticksUtc);
DateTime _todayLocal = new DateTime(ticksLocal);
Console.WriteLine("{0}",_todayLocal);
// get the utc time from _todaylocal time
Console.WriteLine("{0}",_todayLocal.ToUniversalTime());
}
}
I have a date in the string format in a table and I need to compare it with the parameter to retrieve all rows that match with the given date. how can I do this? I can't use DateTime.Parse and Convert.ToDateTime. both of them are not supported (I get an error). Is this possible at all in Linq OR do I have to write a stored procedure for it due to this limitation?
Note: I can't change the datatype of the column from varchar to DateTime, because that column contains other values as well, not just dates. it is a generic table and the column may contain different types of values based on the values in other columns. changing this design is outside the scope of this question.
sample code ("x" is the date parameter passed into this method):
from t1 in Table1
where EntityFunctions.DiffDays(DateTime.Parse(t1.Value),x) == 0
select new {t1.Col1, t1.Col2};
Update: if I use DateTime.Parse, I get the error "LINQ to Entities does not recognize the method 'System.DateTime Parse(System.String)' method, and this method cannot be translated into a store expression." similar error for Convert.ToDateTime as well.
Apart from the issues that #Douglas points about work with string representations, you can convert a string to DateTime in Linq to Entities using SqlFunctions and DbFunctions classes:
DbFunctions.CreateDateTime(SqlFunctions.DatePart("yy", dateString),
SqlFunctions.DatePart("mm", dateString),
SqlFunctions.DatePart("dd", dateString),
SqlFunctions.DatePart("hh", dateString),
SqlFunctions.DatePart("mi", dateString),
SqlFunctions.DatePart("ss", dateString));
(Replicating my comment to paste some sample code)
If the date is in string format, couldn’t you apply a ToString on your DateTime (presumably x) and then do a string comparison?
Since you are working on string representations, you need to take care of several issues that would otherwise be handled transparently by DateTime, including:
Date-time format discrepancies (dd/MM/yyyy vs MM/dd/yyyy).
Presence or absence of leading zeros for single-digit days and months (e.g. 01/01/2011 vs 1/1/2001).
Two-digit or four-digit representation of years (e.g. 01/01/2011 vs 01/01/11).
Timezone offsets. For example, the date for 2011-01-01 23:30 -01:00 would actually be 2011-01-02.
The sample code below will work if all your dates are in US format, with two-digit days and months, four-digit years, and no timezone offsets.
from t1 in Table1
where t1.Value.StartsWith(x.ToString(#"MM\/dd\/yyyy"))
select new {t1.Col1, t1.Col2};
Edit: Alternate solution:
If you can define a view in your database, you can circumvent the problem by casting your VARCHAR to DATETIME selectively. I’m assuming that Value is the name of your date column.
SELECT CONVERT(DATE, Value, 101) AS Value, Col1, Col2
FROM Table1
WHERE ISDATE(Value) = 1
Then, in your LINQ, do a simple DateTime equality check:
from t1 in Table1
where t1.Value == x.Date
select new {t1.Col1, t1.Col2};
This works. You need an Extensionmethod to make the dateTime parsing safe. After that you can use the result of that method in the Linq query. It will fetch all rows from the table so performance wise this might be a less optimal (!) solution. It answers the question though.
void Main()
{
var stringDates = new List<string> { "2011-13-01", "2011-01-12" };
DateTime paramDate = new DateTime(2011,01,13);
var q = from stringDate in stringDates
let realdate = stringDate.SafeParse()
where realdate == paramDate
select new { stringDate, realdate };
q.Dump();
}
static class StringDateParseExt
{
public static DateTime SafeParse(this string any)
{
DateTime parsedDate;
DateTime.TryParseExact(any,
"yyyy-dd-MM",
System.Globalization.CultureInfo.InvariantCulture ,
System.Globalization.DateTimeStyles.None,
out parsedDate);
return parsedDate;
}
}
Linq to SQL does have support for Convert.ToDateTime to go from String to DateTime. I'm not sure about Entity Framework though, if you are really using that instead. There is also a class SqlMethods with a DateDiff method that you can use to get translated to TSQL's DateDiff function.
Linq to SQL will also let you convert between types by casting. You can't directly cast between String and DateTime, but you can cheat by casting to Object first and then to DateTime. The Object cast gets erased in the translate but the DateTime cast get converted to a TSQL convert operation.
Have you tried casting?
Expression<Func<string, DateTime>> expr = s => (DateTime)(object)s;
Further web searching reveals that the lack of string-date conversion is a missing feature in EF. It looks like some string conversions are supported, but not date parsing: http://msdn.microsoft.com/en-us/library/dd466166.aspx