Search between Specific Times - sql

I have a date field and 2 time fields(Start Time and End Time). I have to get Data from the date and entered in that date field and between Start and end times.
I am using Linq query.
result = result.Where(x => x.CreatedDate.ToLocalTime() > search.StartTime &&
x.CreatedDate.ToLocalTime() < search.EndTime);
I am using this but I am getting the following error.
LINQ to Entities does not recognize the method 'System.DateTime ToLocalTime()' method, and this method cannot be translated into a store expression
Please Help.

You can't use ToLocalTime() for Linq to Entities. Because it can't be translated to SQL. There is no equivalent to apply it.
So, why don't you convert your startTime and endTime by considering required time zone which is stored in the database. Opposite conversion should be like that;
//I use utc time to provide example.
//Convert your dates with required timezones which is stored in the database
var startTime = search.StartTime.ToUtcDateTime();
var endTime = search.EndTime.ToUtcDateTime();
result = result.Where(x => x.CreatedDate > startTime &&
x.CreatedDate < endTime);

As Panagiotis Kanavos pointed out there may be no equivalent argument. When you do have the correct type though you are essentially doing a conversion of one DateTime to another. Both the predicate values and the set should have their values preferably stored in the same TimeZone. Here is a simple console example to show what I mean.
public class TestData
{
public DateTime Dt { get; set; }
public TestData(DateTime dt)
{
Dt = dt;
}
public override string ToString() => Dt.ToString();
}
static void Main(string[] args)
{
var dt = new DateTime(2018, 1, 11);
var s = dt;
var e = dt.AddHours(3);
var dts = new List<TestData>();
for (int i = 0; i < 10; i++)
{
dts.Add(new TestData(dt.AddHours(i)));
}
Console.WriteLine("Dates as are");
dts.ForEach(Console.WriteLine);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Dates to local time are");
dts.ForEach(x => Console.WriteLine(x.Dt.ToLocalTime()));
Console.WriteLine(Environment.NewLine);
Console.WriteLine("searches are");
Console.WriteLine(s);
Console.WriteLine(e);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("searches to local time are");
Console.WriteLine(s.ToLocalTime());
Console.WriteLine(e.ToLocalTime());
Console.WriteLine(Environment.NewLine);
Console.WriteLine("Weird results as one set is cast to local and other is not. Plus the cast is now performed on presentation");
dts.Where(x => x.Dt.ToLocalTime() >= s && x.Dt.ToLocalTime() <= e).ToList().ForEach(Console.WriteLine);
Console.WriteLine(Environment.NewLine);
Console.WriteLine("expected results as both are uniform");
dts.Where(x => x.Dt >= s && x.Dt <= e).ToList().ForEach(Console.WriteLine);
Console.ReadLine();
}
Since different posters on SO are in different timezone the second result set will vary. But essentially I am in PST in the US so I see times for the second set eight hours prior to my first. You generally in .NET perform operations of storage to be UTC if your application is going to be worldwide or even country wide. Then you just deal with DateTimes and would only do a conversion on the client end for presentation to a potential end user. But most of the time not in the logic for predicates.

Related

Entity Framework Core 6 - Date Comparision

I need to create a query to find records between a date range. I need to truncate the time for comparison. I came across a few threads suggesting to truncate time using DbFunctions.TruncateTime when comparing the dates.
I cannot find DbFunctions class in EntityFrameworkCore 6.0. How do I truncate time and compare the DateTime columns?
Edit: Excerpt from my query handler
IQueryable<TestReportItem> query = _context.TestReportItems;
DateTime requestDateStart = DateTimeOffset.FromUnixTimeMilliseconds(request.TestDateStart).LocalDateTime;
DateTime requestDateEnd = DateTimeOffset.FromUnixTimeMilliseconds(request.TestDateEnd).LocalDateTime;
if (request.FacilityId != 0)
{
query = query.Where(e => e.FacilityId == request.FacilityId);
}
if (request.TestDateStart != 0 && request.TestDateEnd != 0)
{
query.Where(e => e.TestDate.Date >= requestDateStart
&& e.TestDate.Date <= requestDateEnd);
}
var count = query.Count();
return count;
The request will be for a date range (dates converted into UnixTimeMilliseconds). I am using SqLite database.

Best way to get current web visitor timezone in asp.net core Razor Pages [duplicate]

I am building an application in MVC3 and when a user comes into my site I want to know that user's timezone. I want to know how to do this in c# not in javaScript?
As has been mentioned, you need your client to tell your ASP.Net server details about which timezone they're in.
Here's an example.
I have an Angular controller, which loads a list of records from my SQL Server database in JSON format. The problem is, the DateTime values in these records are in the UTC timezone, and I want to show the user the date/times in their local timezone.
I determine the user's timezone (in minutes) using the JavaScript "getTimezoneOffset()" function, then append this value to the URL of the JSON service I'm trying to call:
$scope.loadSomeDatabaseRecords = function () {
var d = new Date()
var timezoneOffset = d.getTimezoneOffset();
return $http({
url: '/JSON/LoadSomeJSONRecords.aspx?timezoneOffset=' + timezoneOffset,
method: 'GET',
async: true,
cache: false,
headers: { 'Accept': 'application/json', 'Pragma': 'no-cache' }
}).success(function (data) {
$scope.listScheduleLog = data.Results;
});
}
In my ASP.Net code, I extract the timezoneOffset parameter...
int timezoneOffset = 0;
string timezoneStr = Request["timezoneOffset"];
if (!string.IsNullOrEmpty(timezoneStr))
int.TryParse(timezoneStr, out timezoneOffset);
LoadDatabaseRecords(timezoneOffset);
... and pass it to my function which loads the records from the database.
It's a bit messy as I want to call my C# FromUTCData function on each record from the database, but LINQ to SQL can't combine raw SQL with C# functions.
The solution is to read in the records first, then iterate through them, applying the timezone offset to the DateTime fields in each record.
public var LoadDatabaseRecords(int timezoneOffset)
{
MyDatabaseDataContext dc = new MyDatabaseDataContext();
List<MyDatabaseRecords> ListOfRecords = dc.MyDatabaseRecords.ToList();
var results = (from OneRecord in ListOfRecords
select new
{
ID = OneRecord.Log_ID,
Message = OneRecord.Log_Message,
StartTime = FromUTCData(OneRecord.Log_Start_Time, timezoneOffset),
EndTime = FromUTCData(OneRecord.Log_End_Time, timezoneOffset)
}).ToList();
return results;
}
public static DateTime? FromUTCData(DateTime? dt, int timezoneOffset)
{
// Convert a DateTime (which might be null) from UTC timezone
// into the user's timezone.
if (dt == null)
return null;
DateTime newDate = dt.Value - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);
return newDate;
}
It works nicely though, and this code is really useful when writing a web service to display date/times to users in different parts of the world.
Right now, I'm writing this article at 11am Zurich time, but if you were reading it in Los Angeles, you'd see that I edited it at 2am (your local time). Using code like this, you can get your webpages to show date times that make sense to international users of your website.
Phew.
Hope this helps.
This isn't possible server side unless you assume it via the users ip address or get the user to set it in some form of a profile. You could get the clients time via javascript.
See here for the javacript solution: Getting the client's timezone in JavaScript
You will need to use both client-side and server-side technologies.
On the client side:
(pick one)
This works in most modern browsers:
Intl.DateTimeFormat().resolvedOptions().timeZone
There is also jsTimeZoneDetect's jstz.determine(), or Moment-Timezone's moment.tz.guess() function for older browsers, thought these libraries are generally only used in older applications.
The result from either will be an IANA time zone identifier, such as America/New_York. Send that result to the server by any means you like.
On the server side:
(pick one)
Using TimeZoneInfo (on. NET 6+ on any OS, or older on non-Windows systems only):
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
Using TimeZoneConverter (on any OS):
TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/New_York");
Using NodaTime (on any OS):
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
I got the same issue , Unfortunately there is no way for the server to know the client timezone .
If you want you can send client timezone as header while making ajax call .
In-case if you want more info on adding the header this post may help how to add header to request : How can I add a custom HTTP header to ajax request with js or jQuery?
new Date().getTimezoneOffset();//gets the timezone offset
If you don't want to add header every time , you can think of setting a cookie since cookie is sent with all httpRequest you can process the cookie to get client timezone on server side . But i don't prefer adding cookies , for the same reason they sent with all http requests.
Thanks.
For Dot Net version 3.5 and higher you can use :
TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);
but for Dot Net lower than version 3.5 you can handle it manually via this way :
first, get Offset from the client and store it in the cookie
function setTimezoneCookie(){
var timezone_cookie = "timezoneoffset";
// if the timezone cookie does not exist create one.
if (!$.cookie(timezone_cookie)) {
// check if the browser supports cookie
var test_cookie = 'test cookie';
$.cookie(test_cookie, true);
// browser supports cookie
if ($.cookie(test_cookie)) {
// delete the test cookie
$.cookie(test_cookie, null);
// create a new cookie
$.cookie(timezone_cookie, new Date().getTimezoneOffset());
// re-load the page
location.reload();
}
}
// if the current timezone and the one stored in cookie are different
// then store the new timezone in the cookie and refresh the page.
else {
var storedOffset = parseInt($.cookie(timezone_cookie));
var currentOffset = new Date().getTimezoneOffset();
// user may have changed the timezone
if (storedOffset !== currentOffset) {
$.cookie(timezone_cookie, new Date().getTimezoneOffset());
location.reload();
}
}
}
after that you can use a cookie in backend code like that :
public static string ToClientTime(this DateTime dt)
{
// read the value from session
var timeOffSet = HttpContext.Current.Session["timezoneoffset"];
if (timeOffSet != null)
{
var offset = int.Parse(timeOffSet.ToString());
dt = dt.AddMinutes(-1 * offset);
return dt.ToString();
}
// if there is no offset in session return the datetime in server timezone
return dt.ToLocalTime().ToString();
}
I know the user asked about a non-javascript solution, but I wanted to post a javascript solution that I came up with. I found some js libraries (jsTimezoneDetect, momentjs), but their output was an IANA code, which didn't seem to help me with getting a TimeZoneInfo object in C#. I borrowed ideas from jsTimezoneDetect. In javascript, I get the BaseUtcOffset and the first day of DST and send to server. The server then converts this to a TimeZoneInfo object.
Right now I don't care if the client Time Zone is chosen as "Pacific Time (US)" or "Baja California" for example, as either will create the correct time conversions (I think). If I find multiple matches, I currently just pick the first found TimeZoneInfo match.
I can then convert my UTC dates from the database to local time:
DateTime clientDate = TimeZoneInfo.ConvertTimeFromUtc(utcDate, timeZoneInfo);
Javascript
// Time zone. Sets two form values:
// tzBaseUtcOffset: minutes from UTC (non-DST)
// tzDstDayOffset: number of days from 1/1/2016 until first day of DST ; 0 = no DST
var form = document.forms[0];
var janOffset = -new Date(2016, 0, 1).getTimezoneOffset(); // Jan
var julOffset = -new Date(2016, 6, 1).getTimezoneOffset(); // Jul
var baseUtcOffset = Math.min(janOffset, julOffset); // non DST offset (winter offset)
form.elements["tzBaseUtcOffset"].value = baseUtcOffset;
// Find first day of DST (from 1/1/2016)
var dstDayOffset = 0;
if (janOffset != julOffset) {
var startDay = janOffset > baseUtcOffset ? 180 : 0; // if southern hemisphere, start 180 days into year
for (var day = startDay; day < 365; day++) if (-new Date(2016, 0, day + 1, 12).getTimezoneOffset() > baseUtcOffset) { dstDayOffset = day; break; } // noon
}
form.elements["tzDstDayOffset"].value = dstDayOffset;
C#
private TimeZoneInfo GetTimeZoneInfo(int baseUtcOffset, int dstDayOffset) {
// Converts client/browser data to TimeZoneInfo
// baseUtcOffset: minutes from UTC (non-DST)
// dstDayOffset: number of days from 1/1/2016 until first day of DST ; 0 = no DST
// Returns first zone info that matches input, or server zone if none found
List<TimeZoneInfo> zoneInfoArray = new List<TimeZoneInfo>(); // hold multiple matches
TimeSpan timeSpan = new TimeSpan(baseUtcOffset / 60, baseUtcOffset % 60, 0);
bool supportsDst = dstDayOffset != 0;
foreach (TimeZoneInfo zoneInfo in TimeZoneInfo.GetSystemTimeZones()) {
if (zoneInfo.BaseUtcOffset.Equals(timeSpan) && zoneInfo.SupportsDaylightSavingTime == supportsDst) {
if (!supportsDst) zoneInfoArray.Add(zoneInfo);
else {
// Has DST. Find first day of DST and test for match with sent value. Day = day offset into year
int foundDay = 0;
DateTime janDate = new DateTime(2016, 1, 1, 12, 0, 0); // noon
int startDay = zoneInfo.IsDaylightSavingTime(janDate) ? 180 : 0; // if southern hemsphere, start 180 days into year
for (int day = startDay; day < 365; day++) if (zoneInfo.IsDaylightSavingTime(janDate.AddDays(day))) { foundDay = day; break; }
if (foundDay == dstDayOffset) zoneInfoArray.Add(zoneInfo);
}
}
}
if (zoneInfoArray.Count == 0) return TimeZoneInfo.Local;
else return zoneInfoArray[0];
}
You can get this information from client to server (any web API call)
var timezoneOffset = new Date().getTimezoneOffset();
With the help of timezoneoffset details you can achieve the same. Here in my case i converted UTC DateTime to my client local datetime in Server side.
DateTime clientDateTime = DateTime.UtcNow - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);
Click for code example
Take a look at this asp.net c# solution
TimeZoneInfo mytzone = TimeZoneInfo.Local;
System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_TIMEZONE"] ;

date time condition in razor view

How to set a condition to say if a data in a table is less than 5 days ago and then display a users information.
Below I can say less than date now.
#foreach (var item in Model)
{
if(item.RegisteredAt < DateTime.Now )
{
}
}
You can get the difference between two dates as a TimeSpan and use TotalDays property.
(DateTime.Now - item.RegisteredAt).TotalDays < 5
You can pass in a negative number to the AddDays function.
if(item.RegisteredAt < DateTime.Now.AddDays(-5)) {
If you wanted to ignore the time portion then you should compare them off the Date property.
if(item.RegisteredAt.Date < DateTime.Today.AddDays(-5)) {
if(item.RegisteredAt.Substract(DateTime.Now).Days.ToString().AsInt() < 5)
{
#* your expected code *#
}

Hibernate Criteria - Restricting Data Based on Field in One-to-Many Relationship

I need some hibernate/SQL help, please. I'm trying to generate a report against an accounting database. A commission order can have multiple account entries against it.
class CommissionOrderDAO {
int id
String purchaseOrder
double bookedAmount
Date customerInvoicedDate
String state
static hasMany = [accountEntries: AccountEntryDAO]
SortedSet accountEntries
static mapping = {
version false
cache usage: 'read-only'
table 'commission_order'
id column:'id', type:'integer'
purchaseOrder column: 'externalId'
bookedAmount column: 'bookedAmount'
customerInvoicedDate column: 'customerInvoicedDate'
state column : 'state'
accountEntries sort : 'id', order : 'desc'
}
...
}
class AccountEntryDAO implements Comparable<AccountEntryDAO> {
int id
Date eventDate
CommissionOrderDAO commissionOrder
String entryType
String description
double remainingPotentialCommission
static belongsTo = [commissionOrder : CommissionOrderDAO]
static mapping = {
version false
cache usage: 'read-only'
table 'account_entry'
id column:'id', type:'integer'
eventDate column: 'eventDate'
commissionOrder column: 'commissionOrder'
entryType column: 'entryType'
description column: 'description'
remainingPotentialCommission formula : SQLFormulaUtils.AccountEntrySQL.REMAININGPOTENTIALCOMMISSION_FORMULA
}
....
}
The criteria for the report is that the commissionOrder.state==open and the commissionOrder.customerInvoicedDate is not null. And the account entries in the report should be between the startDate and the endDate and with remainingPotentialCommission > 0.
I'm looking to display information on the CommissionOrder mainly (and to display account entries on that commission order between the dates), but when I use the following projection:
def results = accountEntryCriteria.list {
projections {
like ("entryType", "comm%")
ge("eventDate", beginDate)
le("eventDate", endDate)
gt("remainingPotentialCommission", 0.0099d)
and {
commissionOrder {
eq("state", "open")
isNotNull("customerInvoicedDate")
}
}
}
order("id", "asc")
}
I get the correct accountEntries with the proper commissionOrders, but I'm going in backwards: I have loads of accountEntries which can reference the same commissionOrder. Aut when I look at the commissionOrders that I've retrieved, each one has ALL its accountEntries not just the accountEntries between the dates.
I then loop through the results, get the commissionOrder from the accountEntriesList, and remove accountEntries on that commissionOrder after the end date to get the "snapshot" in time that I need.
def getCommissionOrderListByRemainingPotentialCommissionFromResults(results, endDate) {
log.debug("begin getCommissionOrderListByRemainingPotentialCommissionFromResults")
int count = 0;
List<CommissionOrderDAO> commissionOrderList = new ArrayList<CommissionOrderDAO>()
if (results) {
CommissionOrderDAO[] commissionOrderArray = new CommissionOrderDAO[results?.size()];
Set<CommissionOrderDAO> coDuplicateCheck = new TreeSet<CommissionOrderDAO>()
for (ae in results) {
if (!coDuplicateCheck.contains(ae?.commissionOrder?.purchaseOrder) && ae?.remainingPotentialCommission > 0.0099d) {
CommissionOrderDAO co = ae?.commissionOrder
CommissionOrderDAO culledCO = removeAccountEntriesPastDate(co, endDate)
def lastAccountEntry = culledCO?.accountEntries?.last()
if (lastAccountEntry?.remainingPotentialCommission > 0.0099d) {
commissionOrderArray[count++] = culledCO
}
coDuplicateCheck.add(ae?.commissionOrder?.purchaseOrder)
}
}
log.debug("Count after clean is ${count}")
if (count > 0) {
commissionOrderList = Arrays.asList(ArrayUtils.subarray(commissionOrderArray, 0, count))
log.debug("commissionOrderList size = ${commissionOrderList?.size()}")
}
}
log.debug("end getCommissionOrderListByRemainingPotentialCommissionFromResults")
return commissionOrderList
}
Please don't think I'm under the impression that this isn't a Charlie Foxtrot. The query itself doesn't take very long, but the cull process takes over 35 minutes. Right now, it's "manageable" because I only have to run the report once a month.
I need to let the database handle this processing (I think), but I couldn't figure out how to manipulate hibernate to get the results I want. How can I change my criteria?
Try to narrow down the bottle neck of that process. If you have a lot of data, then maybe this check could be time expensive.
coDuplicateCheck.contains(ae?.commissionOrder?.purchaseOrder)
in Set contains have O(n) complexity. You can use i.e. Map to store keys that you would check and then search for "ae?.commissionOrder?.purchaseOrder" as key in the map.
The second thought is that maybe when you're getting ae?.commissionOrder?.purchaseOrder it is always loaded from db by lazy mechanism. Try to turn on query logging and check that you don't have dozens of queries inside this processing function.
Finally and again I would suggest to narrow down where is the most expensive part and time waste.
This plugin maybe helpful.

axis2 xsd:date format issue

I have WSDL as follows:
< xsd:simpleType name="USER_ACT_STRDT_TypeDef">
< xsd:annotation>
< xsd:documentation>USER_ACT_STRDT is a date.< /xsd:documentation>
< /xsd:annotation>
< xsd:restriction base="xsd:date">
< xsd:pattern value="(\d{4}-\d{2}-\d{2})"/>
< /xsd:restriction>
< /xsd:simpleType>
When I generate the STUB (using Axis2 1.5.3), the generated stub (ADB Data Binding) has the following source code :
public void setUSER_ACT_STRDT_TypeDef(Date param) {
if (ConverterUtil.convertToString(param).matches("\d{4}-\d{2}-\d{2}")) {
this.localUSER_ACT_STRDT_TypeDef=param; } else { throw new java.lang.RuntimeException();
} }
This method always throws RuntimeException because the ConverterUtil.convertToString() method returns a String in a different format than "yyyy-mm-dd". It returns the date by appending +5.30 as 2011-03-21+05:30.
I tried passing the date in different formats but same result for all.
Can any one suggest how to resolve this issue.
This code:
if (ConverterUtil.convertToString(param).matches("\\d{4}-\\d{2}-\\d{2}"))
will work only with one of date representations available. In WSDL date specification you will find that 2011-03-21+05:30 is also correct date representation, it simply include time zone as +5 hours and 30 minutes offset to UTC.
Axis2 by default generate dates with timezone but should be able to operate on other date formats.
To check if string starts with YYYY-MM-DD date you can use such code:
if (! sd.matches("\\d{4}-\\d{2}-\\d{2}.*"))
throw new ParseException("Something is terribly wrong with date: " + sd, 0);
else
{
sd = sd.substring(0, 10);
System.out.println("ok: '" + sd + "'");
}
PS Do you escape \d as \\d?
PPS Why do you throw RuntimeException? There are much "better" exceptions like ParseException (used by JDK date parsing methods) or IllegalArgumentException (used by joda time library)